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