First Commit of my working state
[simh.git] / AltairZ80 / mfdc.c
CommitLineData
196ba1fc
PH
1/*************************************************************************\r
2 * *\r
3 * $Id: mfdc.c 1773 2008-01-11 05:46:19Z hharte $ *\r
4 * *\r
5 * Copyright (c) 2007-2008 Howard M. Harte. *\r
6 * http://www.hartetec.com *\r
7 * *\r
8 * Permission is hereby granted, free of charge, to any person obtaining *\r
9 * a copy of this software and associated documentation files (the *\r
10 * "Software"), to deal in the Software without restriction, including *\r
11 * without limitation the rights to use, copy, modify, merge, publish, *\r
12 * distribute, sublicense, and/or sell copies of the Software, and to *\r
13 * permit persons to whom the Software is furnished to do so, subject to *\r
14 * the following conditions: *\r
15 * *\r
16 * The above copyright notice and this permission notice shall be *\r
17 * included in all copies or substantial portions of the Software. *\r
18 * *\r
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *\r
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *\r
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *\r
22 * NONINFRINGEMENT. IN NO EVENT SHALL HOWARD M. HARTE BE LIABLE FOR ANY *\r
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *\r
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *\r
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *\r
26 * *\r
27 * Except as contained in this notice, the name of Howard M. Harte shall *\r
28 * not be used in advertising or otherwise to promote the sale, use or *\r
29 * other dealings in this Software without prior written authorization *\r
30 * Howard M. Harte. *\r
31 * *\r
32 * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. *\r
33 * *\r
34 * Module Description: *\r
35 * Micropolis FD Control module for SIMH. *\r
36 * See the "Vector Using MDOS Revision 8.4" manual at: *\r
37 * www.hartetechnologies.com/manuals in the Vector Graphic section *\r
38 * for details of the on-disk sector format and programming information. *\r
39 * *\r
40 * Environment: *\r
41 * User mode only *\r
42 * *\r
43 *************************************************************************/\r
44\r
45/*#define DBG_MSG */\r
46#define USE_VGI /* Use 275-byte VGI-format sectors (includes all metadata) */\r
47\r
48#include "altairz80_defs.h"\r
49#include "sim_imd.h"\r
50\r
51#if defined (_WIN32)\r
52#include <windows.h>\r
53#endif\r
54\r
55#ifdef DBG_MSG\r
56#define DBG_PRINT(args) printf args\r
57#else\r
58#define DBG_PRINT(args)\r
59#endif\r
60\r
61#define SEEK_MSG 0x01\r
62#define ORDERS_MSG 0x02\r
63#define CMD_MSG 0x04\r
64#define RD_DATA_MSG 0x08\r
65#define WR_DATA_MSG 0x10\r
66#define STATUS_MSG 0x20\r
67\r
68extern uint32 PCX;\r
69extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc);\r
70extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc);\r
71extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,\r
72 int32 (*routine)(const int32, const int32, const int32), uint8 unmap);\r
73extern int32 find_unit_index(UNIT *uptr);\r
74\r
75static void MFDC_Command(uint8 cData);\r
76\r
77#define MFDC_MAX_DRIVES 4\r
78#define JUMPER_W9 1 /* Not Installed (0) = 2MHz, Installed (1) = 4MHz. */\r
79#define JUMPER_W10 0\r
80\r
81#define MFDC_SECTOR_LEN 275\r
82\r
83typedef union {\r
84 struct {\r
85 uint8 sync;\r
86 uint8 header[2];\r
87 uint8 unused[10];\r
88 uint8 data[256];\r
89 uint8 checksum;\r
90 uint8 ecc[4];\r
91 uint8 ecc_valid; /* Not used for Micropolis FDC, but is used by FDHD. */\r
92 } u;\r
93 uint8 raw[MFDC_SECTOR_LEN];\r
94\r
95} SECTOR_FORMAT;\r
96\r
97typedef struct {\r
98 UNIT *uptr;\r
99 DISK_INFO *imd;\r
100 uint8 track;\r
101 uint8 wp; /* Disk write protected */\r
102 uint8 ready; /* Drive is ready */\r
103 uint8 sector; /* Current Sector number */\r
104 uint32 sector_wait_count;\r
105} MFDC_DRIVE_INFO;\r
106\r
107typedef struct {\r
108 PNP_INFO pnp; /* Plug and Play */\r
109 uint8 xfr_flag; /* Indicates controller is ready to send/receive data */\r
110 uint8 sel_drive; /* Currently selected drive */\r
111 uint8 selected; /* 1 if drive is selected */\r
112 uint8 track0; /* Set it selected drive is on track 0 */\r
113 uint8 head; /* Currently selected head */\r
114 uint8 wr_latch; /* Write enable latch */\r
115 uint8 int_enable; /* Interrupt Enable */\r
116 uint32 datacount; /* Number of data bytes transferred from controller for current sector */\r
117 uint8 read_in_progress; /* TRUE if a read is in progress */\r
118 MFDC_DRIVE_INFO drive[MFDC_MAX_DRIVES];\r
119} MFDC_INFO;\r
120\r
121static MFDC_INFO mfdc_info_data = { { 0xF800, 1024, 0, 0 } };\r
122static MFDC_INFO *mfdc_info = &mfdc_info_data;\r
123\r
124static SECTOR_FORMAT sdata;\r
125\r
126#define UNIT_V_MFDC_WLK (UNIT_V_UF + 0) /* write locked */\r
127#define UNIT_MFDC_WLK (1 << UNIT_V_MFDC_WLK)\r
128#define UNIT_V_MFDC_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */\r
129#define UNIT_MFDC_VERBOSE (1 << UNIT_V_MFDC_VERBOSE)\r
130#define MFDC_CAPACITY (77*16*MFDC_SECTOR_LEN) /* Default Micropolis Disk Capacity */\r
131#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */\r
132#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */\r
133#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */\r
134\r
135static t_stat mfdc_reset(DEVICE *mfdc_dev);\r
136static t_stat mfdc_attach(UNIT *uptr, char *cptr);\r
137static t_stat mfdc_detach(UNIT *uptr);\r
138static uint8 MFDC_Read(const uint32 Addr);\r
139static uint8 MFDC_Write(const uint32 Addr, uint8 cData);\r
140\r
141static int32 mdskdev(const int32 Addr, const int32 rw, const int32 data);\r
142\r
143static int32 trace_level = 0;\r
144\r
145static UNIT mfdc_unit[] = {\r
146 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) },\r
147 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) },\r
148 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) },\r
149 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) }\r
150};\r
151\r
152static REG mfdc_reg[] = {\r
153 { HRDATA (TRACELEVEL, trace_level, 16), },\r
154 { NULL }\r
155};\r
156\r
157static MTAB mfdc_mod[] = {\r
158 { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL },\r
159 { UNIT_MFDC_WLK, 0, "WRTENB", "WRTENB", NULL },\r
160 { UNIT_MFDC_WLK, UNIT_MFDC_WLK, "WRTLCK", "WRTLCK", NULL },\r
161 /* quiet, no warning messages */\r
162 { UNIT_MFDC_VERBOSE, 0, "QUIET", "QUIET", NULL },\r
163 /* verbose, show warning messages */\r
164 { UNIT_MFDC_VERBOSE, UNIT_MFDC_VERBOSE, "VERBOSE", "VERBOSE", NULL },\r
165 { 0 }\r
166};\r
167\r
168DEVICE mfdc_dev = {\r
169 "MDSK", mfdc_unit, mfdc_reg, mfdc_mod,\r
170 MFDC_MAX_DRIVES, 10, 31, 1, MFDC_MAX_DRIVES, MFDC_MAX_DRIVES,\r
171 NULL, NULL, &mfdc_reset,\r
172 NULL, &mfdc_attach, &mfdc_detach,\r
173 &mfdc_info_data, (DEV_DISABLE | DEV_DIS), 0,\r
174 NULL, NULL, NULL\r
175};\r
176\r
177/* Micropolis FD Control Boot ROM\r
178 * This ROM code is runtime-relocatable. See Appendix F of the "Vector Using MDOS Revision 8.4"\r
179 * manual at www.hartetechnologies.com/manuals in the Vector Graphic section.\r
180 */\r
181static uint8 mfdc_rom[256] = {\r
182 0xF3, 0x21, 0xA2, 0x00, 0xF9, 0x36, 0xC9, 0xCD, 0xA2, 0x00, 0xEB, 0x2A, 0xA0, 0x00, 0x2E, 0x00, /* 0x00 */\r
183 0xE5, 0x01, 0x1D, 0x00, 0x09, 0xE5, 0xE1, 0x0E, 0x1A, 0x09, 0x06, 0xBD, 0xEB, 0x3B, 0x3B, 0x1A, /* 0x10 */\r
184 0x77, 0xBE, 0xC0, 0x23, 0x13, 0x05, 0xC0, 0xE1, 0x2A, 0xA0, 0x00, 0x11, 0x00, 0x02, 0x19, 0x22, /* 0x20 */\r
185 0xA2, 0x00, 0x36, 0xA0, 0xC3, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xA2, 0x00, 0x7E, 0xE6, /* 0x30 */\r
186 0x80, 0xCA, 0xA9, 0x00, 0x7E, 0xE6, 0x0F, 0xA8, 0xC2, 0xA9, 0x00, 0x23, 0xB6, 0xF2, 0xB7, 0x00, /* 0x40 */\r
187 0x23, 0x7E, 0xAF, 0xEB, 0x06, 0x00, 0x00, 0x00, 0x1A, 0x77, 0x23, 0x88, 0x47, 0x1A, 0x77, 0x23, /* 0x50 */\r
188 0x88, 0x47, 0x0D, 0xC2, 0xC3, 0x00, 0x1A, 0xB8, 0xC9, 0x2A, 0xA2, 0x00, 0x36, 0x20, 0x23, 0x7E, /* 0x60 */\r
189 0x2B, 0xE6, 0x24, 0xEE, 0x20, 0xC2, 0xD4, 0x00, 0x0E, 0x5E, 0xCD, 0x49, 0x01, 0x23, 0x7E, 0x2B, /* 0x70 */\r
190 0xE6, 0x24, 0xEE, 0x20, 0xC2, 0xD4, 0x00, 0x23, 0x7E, 0xE6, 0x08, 0x2B, 0xCA, 0x07, 0x01, 0x06, /* 0x80 */\r
191 0x08, 0x36, 0x61, 0x0E, 0x0F, 0xCD, 0x49, 0x01, 0x05, 0xC2, 0xFC, 0x00, 0x23, 0x7E, 0xE6, 0x08, /* 0x90 */\r
192 0x2B, 0xC2, 0x19, 0x01, 0x36, 0x60, 0x0E, 0x0F, 0xCD, 0x49, 0x01, 0xC3, 0x07, 0x01, 0x21, 0x5F, /* 0xA0 */\r
193 0x01, 0xCD, 0x37, 0x01, 0xC2, 0xD4, 0x00, 0x2A, 0x69, 0x02, 0x22, 0xA4, 0x00, 0xCD, 0x37, 0x01, /* 0xB0 */\r
194 0xC2, 0xD4, 0x00, 0x2A, 0xA4, 0x00, 0x11, 0x0C, 0x00, 0x19, 0xD1, 0xE9, 0xE5, 0xEB, 0x01, 0x86, /* 0xC0 */\r
195 0x00, 0xCD, 0xA6, 0x00, 0xE1, 0xC2, 0x37, 0x01, 0xE5, 0x7E, 0x23, 0xB6, 0xE1, 0xC9, 0x7E, 0xE6, /* 0xD0 */\r
196 0x20, 0x79, 0xC2, 0x51, 0x01, 0x07, 0x4F, 0x3E, 0xFF, 0xD6, 0x01, 0xB7, 0xC2, 0x54, 0x01, 0x0D, /* 0xE0 */\r
197 0xC2, 0x52, 0x01, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xA6, 0x00 /* 0xF0 */\r
198};\r
199\r
200/* Reset routine */\r
201t_stat mfdc_reset(DEVICE *dptr)\r
202{\r
203 uint8 i;\r
204 PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;\r
205\r
206 if(dptr->flags & DEV_DIS) {\r
207 sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &mdskdev, TRUE);\r
208 } else {\r
209 /* Connect MFDC at base address */\r
210 for(i = 0; i < MFDC_MAX_DRIVES; i++) {\r
211 mfdc_info->drive[i].uptr = &mfdc_dev.units[i];\r
212 }\r
213 if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &mdskdev, FALSE) != 0) {\r
214 printf("%s: error mapping resource at 0x%04x\n", __FUNCTION__, pnp->mem_base);\r
215 dptr->flags |= DEV_DIS;\r
216 return SCPE_ARG;\r
217 }\r
218 }\r
219 return SCPE_OK;\r
220}\r
221\r
222/* Attach routine */\r
223t_stat mfdc_attach(UNIT *uptr, char *cptr)\r
224{\r
225 char header[4];\r
226 t_stat r;\r
227 unsigned int i = 0;\r
228\r
229 r = attach_unit(uptr, cptr); /* attach unit */\r
230 if ( r != SCPE_OK) /* error? */\r
231 return r;\r
232\r
233 /* Determine length of this disk */\r
234 if(sim_fsize(uptr->fileref) != 0) {\r
235 uptr->capac = sim_fsize(uptr->fileref);\r
236 } else {\r
237 uptr->capac = MFDC_CAPACITY;\r
238 }\r
239\r
240 i = find_unit_index(uptr);\r
241\r
242 /* Default for new file is DSK */\r
243 uptr->u3 = IMAGE_TYPE_DSK;\r
244\r
245 if(uptr->capac > 0) {\r
246 fgets(header, 4, uptr->fileref);\r
247 if(!strcmp(header, "IMD")) {\r
248 uptr->u3 = IMAGE_TYPE_IMD;\r
249 } else if(!strcmp(header, "CPT")) {\r
250 printf("CPT images not yet supported\n");\r
251 uptr->u3 = IMAGE_TYPE_CPT;\r
252 mfdc_detach(uptr);\r
253 return SCPE_OPENERR;\r
254 } else {\r
255 uptr->u3 = IMAGE_TYPE_DSK;\r
256 }\r
257 }\r
258\r
259 if (uptr->flags & UNIT_MFDC_VERBOSE)\r
260 printf("MDSK%d, attached to '%s', type=%s, len=%d\n", i, cptr,\r
261 uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",\r
262 uptr->capac);\r
263\r
264 if(uptr->u3 == IMAGE_TYPE_IMD) {\r
265 if(uptr->capac < 318000) {\r
266 printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n");\r
267 mfdc_detach(uptr);\r
268 return SCPE_OPENERR;\r
269 }\r
270\r
271 if (uptr->flags & UNIT_MFDC_VERBOSE)\r
272 printf("--------------------------------------------------------\n");\r
273 mfdc_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_MFDC_VERBOSE));\r
274 if (uptr->flags & UNIT_MFDC_VERBOSE)\r
275 printf("\n");\r
276 } else {\r
277 mfdc_info->drive[i].imd = NULL;\r
278 }\r
279\r
280 return SCPE_OK;\r
281}\r
282\r
283\r
284/* Detach routine */\r
285t_stat mfdc_detach(UNIT *uptr)\r
286{\r
287 t_stat r;\r
288 int8 i;\r
289\r
290 for(i = 0; i < MFDC_MAX_DRIVES; i++) {\r
291 if(mfdc_dev.units[i].fileref == uptr->fileref) {\r
292 break;\r
293 }\r
294 }\r
295\r
296 if (i >= MFDC_MAX_DRIVES) return SCPE_ARG;\r
297\r
298 DBG_PRINT(("Detach MFDC%d\n", i));\r
299 diskClose(mfdc_info->drive[i].imd);\r
300\r
301 r = detach_unit(uptr); /* detach unit */\r
302 if ( r != SCPE_OK)\r
303 return r;\r
304\r
305 return SCPE_OK;\r
306}\r
307\r
308\r
309\r
310static uint8 cy;\r
311static uint8 adc(uint8 sum, uint8 a1)\r
312{\r
313 uint32 total;\r
314\r
315 total = sum + a1 + cy;\r
316\r
317 if(total > 0xFF) {\r
318 cy = 1;\r
319 } else {\r
320 cy = 0;\r
321 }\r
322\r
323 return(total & 0xFF);\r
324}\r
325\r
326/* Main Entry Point for Memory-Mapped I/O to the Micropolis FD Control Board\r
327 *\r
328 * The controller is typically located at 0xF800 in the Memory Map, and occupies\r
329 * 1K of address space. Accesses are broken down as follows:\r
330 *\r
331 * 0xF800-0xF8FF: Bootstrap ROM\r
332 * 0xF900-0xF9FF: Nothing (reads 0xFF)\r
333 * 0xFA00-0xFBFF: Controller registers: there are four registers, which are shadowed\r
334 * throughout this 512-byte range.\r
335 *\r
336 * The controller can be relocated on any 1K boundary in the memory map, and since the\r
337 * boot ROM code is runtime relocatable, it moves with the controller registers.\r
338 */\r
339static int32 mdskdev(const int32 Addr, const int32 rw, const int32 data)\r
340{\r
341 switch(Addr & 0x300) {\r
342 case 0x000: /* Boot ROM */\r
343 if(rw == 0) { /* Read boot ROM */\r
344 return(mfdc_rom[Addr & 0xFF]);\r
345 } else {\r
346 printf("MFDC: Attempt to write to boot ROM." NLP);\r
347 return (-1);\r
348 }\r
349 break;\r
350 case 0x100: /* Nothing */\r
351 return(0xFF);\r
352 break;\r
353 case 0x200:\r
354 case 0x300: /* Controller Registers */\r
355 if(rw == 0) { /* Read Register */\r
356 return(MFDC_Read(Addr));\r
357 } else { /* Write Register */\r
358 return(MFDC_Write(Addr, data));\r
359 }\r
360 break;\r
361 }\r
362\r
363 return(-1);\r
364}\r
365\r
366\r
367static uint8 MFDC_Read(const uint32 Addr)\r
368{\r
369 uint8 cData;\r
370 MFDC_DRIVE_INFO *pDrive;\r
371\r
372 cData = 0x00;\r
373\r
374 pDrive = &mfdc_info->drive[mfdc_info->sel_drive];\r
375\r
376 switch(Addr & 0x3) {\r
377 case 0:\r
378 if(mfdc_info->read_in_progress == FALSE) {\r
379 pDrive->sector_wait_count++;\r
380 if(pDrive->sector_wait_count > 10) {\r
381 pDrive->sector++;\r
382 pDrive->sector &= 0x0F; /* Max of 16 sectors */\r
383 mfdc_info->wr_latch = 0; /* on new sector, disable the write latch */\r
384 DBG_PRINT(("Head over sector %d" NLP, pDrive->sector));\r
385 pDrive->sector_wait_count = 0;\r
386 }\r
387 }\r
388\r
389 cData = (pDrive->sector) & 0xF; /* [3:0] current sector */\r
390 cData |= (JUMPER_W10 << 4);\r
391 cData |= ((~JUMPER_W9) & 1) << 5;\r
392 cData |= (0 << 6); /* Sector Interrupt Flag, reset by RESET command or Interrupt Disable */\r
393 cData |= (1 << 7); /* Sector Flag */\r
394 mfdc_info->xfr_flag = 1; /* Drive has data */\r
395 mfdc_info->datacount = 0;\r
396 TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Sector Register = 0x%02x" NLP, PCX, cData));\r
397 break;\r
398 case 1:\r
399 cData = (mfdc_info->sel_drive & 0x3); /* [1:0] selected drive */\r
400 cData |= (!mfdc_info->selected << 2); /* [2] drive is selected */\r
401 cData |= (pDrive->track == 0) ? 0x08 : 0; /* [3] TK0 */\r
402 pDrive->wp = ((pDrive->uptr)->flags & UNIT_MFDC_WLK) ? 1 : 0;\r
403 cData |= (pDrive->wp << 4); /* [4] Write Protect */\r
404 cData |= (pDrive->ready << 5); /* [5] Drive Ready */\r
405 cData |= (0 << 6); /* [6] PINTE from S-100 Bus */\r
406 cData |= (mfdc_info->xfr_flag << 7); /* [7] Transfer Flag */\r
407\r
408 TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Status = 0x%02x" NLP, PCX, cData));\r
409 break;\r
410 case 2:\r
411 case 3:\r
412 if(mfdc_info->datacount == 0) {\r
413 unsigned int i, checksum;\r
414 unsigned long sec_offset;\r
415 unsigned int flags;\r
416 unsigned int readlen;\r
417\r
418 /* Clear out unused portion of sector. */\r
419 memset(&sdata.u.unused[0], 0x00, 10);\r
420\r
421 sdata.u.sync = 0xFF;\r
422 sdata.u.header[0] = pDrive->track;\r
423 sdata.u.header[1] = pDrive->sector;\r
424\r
425 TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " RD Data T:%d S:[%d]" NLP,\r
426 PCX,\r
427 pDrive->track,\r
428 pDrive->sector));\r
429\r
430#ifdef USE_VGI\r
431 sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \\r
432 (pDrive->sector * MFDC_SECTOR_LEN);\r
433#else\r
434 sec_offset = (pDrive->track * 4096) + \\r
435 (pDrive->sector * 256);\r
436#endif /* USE_VGI */\r
437\r
438 if (!(pDrive->uptr->flags & UNIT_ATT)) {\r
439 if (pDrive->uptr->flags & UNIT_MFDC_VERBOSE)\r
440 printf("MFDC: " ADDRESS_FORMAT " MDSK%i not attached." NLP, PCX,\r
441 mfdc_info->sel_drive);\r
442 return 0x00;\r
443 }\r
444\r
445 switch((pDrive->uptr)->u3)\r
446 {\r
447 case IMAGE_TYPE_IMD:\r
448 if(pDrive->imd == NULL) {\r
449 printf(".imd is NULL!" NLP);\r
450 }\r
451/* printf("%s: Read: imd=%p" NLP, __FUNCTION__, pDrive->imd); */\r
452 sectRead(pDrive->imd,\r
453 pDrive->track,\r
454 mfdc_info->head,\r
455 pDrive->sector,\r
456 sdata.u.data,\r
457 256,\r
458 &flags,\r
459 &readlen);\r
460 break;\r
461 case IMAGE_TYPE_DSK:\r
462 if(pDrive->uptr->fileref == NULL) {\r
463 printf(".fileref is NULL!" NLP);\r
464 } else {\r
465 fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);\r
466#ifdef USE_VGI\r
467 fread(sdata.raw, MFDC_SECTOR_LEN, 1, (pDrive->uptr)->fileref);\r
468#else\r
469 fread(sdata.u.data, 256, 1, (pDrive->uptr)->fileref);\r
470#endif /* USE_VGI */\r
471 }\r
472 break;\r
473 case IMAGE_TYPE_CPT:\r
474 printf("%s: CPT Format not supported" NLP, __FUNCTION__);\r
475 break;\r
476 default:\r
477 printf("%s: Unknown image Format" NLP, __FUNCTION__);\r
478 break;\r
479 }\r
480\r
481/* printf("%d/%d @%04x Len=%04x" NLP, sdata.u.header[0], sdata.u.header[1], sdata.u.header[9]<<8|sdata.u.header[8], sdata.u.header[11]<<8|sdata.u.header[10]); */\r
482\r
483 adc(0,0); /* clear Carry bit */\r
484 checksum = 0;\r
485\r
486 /* Checksum everything except the sync byte */\r
487 for(i=1;i<269;i++) {\r
488 checksum = adc(checksum, sdata.raw[i]);\r
489 }\r
490\r
491 sdata.u.checksum = checksum & 0xFF;\r
492/* DBG_PRINT(("Checksum=%x" NLP, sdata.u.checksum)); */\r
493 mfdc_info->read_in_progress = TRUE;\r
494 }\r
495\r
496 cData = sdata.raw[mfdc_info->datacount];\r
497\r
498 mfdc_info->datacount++;\r
499 if(mfdc_info->datacount == 270) {\r
500 TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " Read sector [%d] complete" NLP,\r
501 PCX, pDrive->sector));\r
502 mfdc_info->read_in_progress = FALSE;\r
503 }\r
504\r
505/* DBG_PRINT(("MFDC: " ADDRESS_FORMAT " RD Data Sector %d[%03d]: 0x%02x" NLP, PCX, pDrive->sector, mfdc_info->datacount, cData)); */\r
506 break;\r
507 }\r
508\r
509 return (cData);\r
510}\r
511\r
512static uint8 MFDC_Write(const uint32 Addr, uint8 cData)\r
513{\r
514 unsigned int sec_offset;\r
515 unsigned int flags = 0;\r
516 unsigned int writelen;\r
517 MFDC_DRIVE_INFO *pDrive;\r
518\r
519 pDrive = &mfdc_info->drive[mfdc_info->sel_drive];\r
520\r
521 switch(Addr & 0x3) {\r
522 case 0:\r
523 case 1:\r
524 MFDC_Command(cData);\r
525 break;\r
526 case 2:\r
527 case 3:\r
528/* DBG_PRINT(("MFDC: " ADDRESS_FORMAT " WR Data" NLP, PCX)); */\r
529 if(mfdc_info->wr_latch == 0) {\r
530 printf("MFDC: " ADDRESS_FORMAT " Error, attempt to write data when write latch is not set." NLP, PCX);\r
531 } else {\r
532#ifdef USE_VGI\r
533 sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \\r
534 (pDrive->sector * MFDC_SECTOR_LEN);\r
535\r
536 sdata.raw[mfdc_info->datacount] = cData;\r
537#else\r
538 int data_index = mfdc_info->datacount - 13;\r
539\r
540 sec_offset = (pDrive->track * 4096) + \\r
541 (pDrive->sector * 256);\r
542\r
543 if((data_index >= 0) && (data_index < 256)) {\r
544 DBG_PRINT(("writing data [%03d]=%02x" NLP, data_index, cData));\r
545\r
546 sdata.u.data[data_index] = cData;\r
547\r
548 }\r
549\r
550#endif /* USE_VGI */\r
551\r
552 mfdc_info->datacount ++;\r
553\r
554 if(mfdc_info->datacount == 270) {\r
555 TRACE_PRINT(WR_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " WR Data T:%d S:[%d]" NLP,\r
556 PCX,\r
557 pDrive->track,\r
558 pDrive->sector));\r
559\r
560 if (!(pDrive->uptr->flags & UNIT_ATT)) {\r
561 if (pDrive->uptr->flags & UNIT_MFDC_VERBOSE)\r
562 printf("MFDC: " ADDRESS_FORMAT " MDSK%i not attached." NLP, PCX,\r
563 mfdc_info->sel_drive);\r
564 return 0x00;\r
565 }\r
566\r
567 switch((pDrive->uptr)->u3)\r
568 {\r
569 case IMAGE_TYPE_IMD:\r
570 if(pDrive->imd == NULL) {\r
571 printf(".imd is NULL!" NLP);\r
572 }\r
573 sectWrite(pDrive->imd,\r
574 pDrive->track,\r
575 mfdc_info->head,\r
576 pDrive->sector,\r
577 sdata.u.data,\r
578 256,\r
579 &flags,\r
580 &writelen);\r
581 break;\r
582 case IMAGE_TYPE_DSK:\r
583 if(pDrive->uptr->fileref == NULL) {\r
584 printf(".fileref is NULL!" NLP);\r
585 } else {\r
586 fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);\r
587#ifdef USE_VGI\r
588 fwrite(sdata.raw, MFDC_SECTOR_LEN, 1, (pDrive->uptr)->fileref);\r
589#else\r
590 fwrite(sdata.u.data, 256, 1, (pDrive->uptr)->fileref);\r
591#endif /* USE_VGI */\r
592 }\r
593 break;\r
594 case IMAGE_TYPE_CPT:\r
595 printf("%s: CPT Format not supported" NLP, __FUNCTION__);\r
596 break;\r
597 default:\r
598 printf("%s: Unknown image Format" NLP, __FUNCTION__);\r
599 break;\r
600 }\r
601 }\r
602 }\r
603 break;\r
604 }\r
605\r
606 cData = 0x00;\r
607\r
608 return (cData);\r
609}\r
610\r
611#define MFDC_CMD_NOP 0\r
612#define MFDC_CMD_SELECT 1\r
613#define MFDC_CMD_INTR 2\r
614#define MFDC_CMD_STEP 3\r
615#define MFDC_CMD_SET_WRITE 4\r
616#define MFDC_CMD_RESET 5\r
617\r
618static void MFDC_Command(uint8 cData)\r
619{\r
620 uint8 cCommand;\r
621 uint8 cModifier;\r
622 MFDC_DRIVE_INFO *pDrive;\r
623\r
624 pDrive = &mfdc_info->drive[mfdc_info->sel_drive];\r
625\r
626\r
627 cCommand = cData >> 5;\r
628 cModifier = cData & 0x1F;\r
629\r
630 switch(cCommand) {\r
631 case MFDC_CMD_NOP:\r
632 TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " No Op." NLP, PCX));\r
633 break;\r
634 case MFDC_CMD_SELECT:\r
635 mfdc_info->sel_drive = cModifier & 3;\r
636 mfdc_info->head = (cModifier & 0x10) >> 4;\r
637 mfdc_info->selected = TRUE;\r
638\r
639 if(pDrive->uptr->fileref != NULL) {\r
640 pDrive->ready = 1;\r
641 } else {\r
642 pDrive->ready = 0;\r
643 }\r
644\r
645 TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Select Drive: %d, Head: %s" NLP,\r
646 PCX, mfdc_info->sel_drive, (mfdc_info->head) ? "Upper" : "Lower"));\r
647 break;\r
648 case MFDC_CMD_INTR:\r
649 mfdc_info->int_enable = cModifier & 1; /* 0=int disable, 1=enable */\r
650 TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Interrupts %s." NLP,\r
651 PCX, mfdc_info->int_enable ? "Enabled" : "Disabled"));\r
652 break;\r
653 case MFDC_CMD_STEP:\r
654 if(cModifier & 1) { /* Step IN */\r
655 pDrive->track++;\r
656 }\r
657 else { /* Step OUT */\r
658 if(pDrive->track != 0) {\r
659 pDrive->track--;\r
660 }\r
661 }\r
662\r
663 TRACE_PRINT(SEEK_MSG, ("MFDC: " ADDRESS_FORMAT " Step %s, Track=%d." NLP,\r
664 PCX, (cModifier & 1) ? "IN" : "OUT", pDrive->track));\r
665\r
666 break;\r
667 case MFDC_CMD_SET_WRITE:\r
668 TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Set WRITE." NLP, PCX));\r
669 mfdc_info->wr_latch = 1; /* Allow writes for the current sector */\r
670 mfdc_info->datacount = 0; /* reset the byte counter */\r
671 break;\r
672 case MFDC_CMD_RESET:\r
673 TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Reset Controller." NLP, PCX));\r
674 mfdc_info->selected = 0; /* de-select the drive */\r
675 mfdc_info->wr_latch = 0; /* Disable the write latch */\r
676 mfdc_info->datacount = 0; /* reset the byte counter */\r
677 break;\r
678 default:\r
679 TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Unsupported command." NLP, PCX));\r
680 break;\r
681 }\r
682}\r