1 /*************************************************************************
2  *                                                                       *
3  * $Id: vfdhd.c 1995 2008-07-15 03:59:13Z 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 FDC module for SIMH                                    *
36  *                                                                       *
37  * Environment:                                                          *
38  *     User mode only                                                    *
39  *                                                                       *
40  *************************************************************************/
41 
42 /*#define DBG_MSG */
43 #define USE_VGI     /* Use 275-byte VGI-format sectors (includes all metadata) */
44 
45 #include "altairz80_defs.h"
46 
47 #if defined (_WIN32)
48 #include <windows.h>
49 #endif
50 
51 #include "sim_imd.h"
52 
53 /* #define DBG_MSG */
54 
55 #ifdef DBG_MSG
56 #define DBG_PRINT(args) printf args
57 #else
58 #define DBG_PRINT(args)
59 #endif
60 
61 /* Debug flags */
62 #define ERROR_MSG   (1 << 0)
63 #define SEEK_MSG    (1 << 1)
64 #define CMD_MSG     (1 << 2)
65 #define RD_DATA_MSG (1 << 3)
66 #define WR_DATA_MSG (1 << 4)
67 #define STATUS_MSG  (1 << 5)
68 #define ORDERS_MSG  (1 << 7)
69 
70 static void VFDHD_Command(void);
71 
72 #define VFDHD_MAX_DRIVES    4
73 
74 #define VFDHD_SECTOR_LEN    275
75 #define VFDHD_RAW_LEN       (40 + VFDHD_SECTOR_LEN + 128)
76 
77 typedef union {
78     struct {
79         uint8 preamble[40]; /* Hard disk uses 30 bytes of preamble, floppy uses 40. */
80         uint8 sync;
81         uint8 header[2];
82         uint8 unused[10];
83         uint8 data[256];
84         uint8 checksum;
85         uint8 ecc[4];
86         uint8 ecc_valid;    /* 0xAA indicates ECC is being used. */
87         uint8 postamble[128];
88     } u;
89     uint8 raw[VFDHD_RAW_LEN];
90 
91 } SECTOR_FORMAT;
92 
93 typedef struct {
94     UNIT *uptr;
95     DISK_INFO *imd;
96     uint16 ntracks; /* number of tracks */
97     uint8 nheads;   /* number of heads */
98     uint8 nspt;     /* number of sectors per track */
99     uint8 npre_len; /* preamble length */
100     uint32 sectsize; /* sector size, not including pre/postamble */
101     uint16 track;
102     uint8 wp;       /* Disk write protected */
103     uint8 ready;    /* Drive is ready */
104     uint8 write_fault;
105     uint8 seek_complete;
106     uint8 sync_lost;
107     uint32 sector_wait_count;
108 } VFDHD_DRIVE_INFO;
109 
110 typedef struct {
111     PNP_INFO    pnp;    /* Plug and Play */
112     uint8 xfr_flag;     /* Indicates controller is ready to send/receive data */
113     uint8 sel_drive;    /* Currently selected drive */
114     uint8 selected;     /* 1 if drive is selected */
115     uint8 track0;       /* Set it selected drive is on track 0 */
116     uint8 head;         /* Currently selected head */
117     uint8 wr_latch;     /* Write enable latch */
118     uint8 int_enable;   /* Interrupt Enable */
119     uint32 datacount;   /* Number of data bytes transferred from controller for current sector */
120     uint8 step;
121     uint8 direction;
122     uint8 rwc;
123     uint8 sector;
124     uint8 read;
125     uint8 ecc_enable;
126     uint8 precomp;
127     uint8 floppy_sel;
128     uint8 controller_busy;
129     uint8 motor_on;
130     uint8 hdsk_type;
131     VFDHD_DRIVE_INFO drive[VFDHD_MAX_DRIVES];
132 } VFDHD_INFO;
133 
134 static VFDHD_INFO vfdhd_info_data = { { 0x0, 0, 0xC0, 4 } };
135 static VFDHD_INFO *vfdhd_info = &vfdhd_info_data;
136 
137 static SECTOR_FORMAT sdata;
138 extern uint32 PCX;
139 extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
140 extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
141 extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
142         int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
143 
144 #define UNIT_V_VFDHD_WLK        (UNIT_V_UF + 0) /* write locked                             */
145 #define UNIT_VFDHD_WLK          (1 << UNIT_V_VFDHD_WLK)
146 #define UNIT_V_VFDHD_VERBOSE    (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages   */
147 #define UNIT_VFDHD_VERBOSE      (1 << UNIT_V_VFDHD_VERBOSE)
148 #define VFDHD_CAPACITY          (77*2*16*256)   /* Default Micropolis Disk Capacity         */
149 
150 static t_stat vfdhd_reset(DEVICE *vfdhd_dev);
151 static t_stat vfdhd_attach(UNIT *uptr, char *cptr);
152 static t_stat vfdhd_detach(UNIT *uptr);
153 
154 static int32 vfdhddev(const int32 port, const int32 io, const int32 data);
155 
156 static uint8 VFDHD_Read(const uint32 Addr);
157 static uint8 VFDHD_Write(const uint32 Addr, uint8 cData);
158 
159 static int32 hdSize = 5;
160 
161 static UNIT vfdhd_unit[] = {
162     { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, VFDHD_CAPACITY) },
163     { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, VFDHD_CAPACITY) },
164     { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, VFDHD_CAPACITY) },
165     { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, VFDHD_CAPACITY) }
166 };
167 
168 static REG vfdhd_reg[] = {
169     { DRDATA (HDSIZE, hdSize, 10), },
170     { NULL }
171 };
172 
173 static MTAB vfdhd_mod[] = {
174     { MTAB_XTD|MTAB_VDV,    0,                  "IOBASE",   "IOBASE", &set_iobase, &show_iobase, NULL },
175     { UNIT_VFDHD_WLK,       0,                  "WRTENB",   "WRTENB", NULL  },
176     { UNIT_VFDHD_WLK,       UNIT_VFDHD_WLK,     "WRTLCK",   "WRTLCK", NULL  },
177     /* quiet, no warning messages       */
178     { UNIT_VFDHD_VERBOSE,   0,                  "QUIET",    "QUIET", NULL   },
179     /* verbose, show warning messages   */
180     { UNIT_VFDHD_VERBOSE,   UNIT_VFDHD_VERBOSE, "VERBOSE",  "VERBOSE", NULL },
181     { 0 }
182 };
183 
184 /* Debug Flags */
185 static DEBTAB vfdhd_dt[] = {
186     { "ERROR",  ERROR_MSG },
187     { "SEEK",   SEEK_MSG },
188     { "CMD",    CMD_MSG },
189     { "RDDATA", RD_DATA_MSG },
190     { "WRDATA", WR_DATA_MSG },
191     { "STATUS", STATUS_MSG },
192     { "ORDERS", ORDERS_MSG },
193     { NULL,     0 }
194 };
195 
196 DEVICE vfdhd_dev = {
197     "VFDHD", vfdhd_unit, vfdhd_reg, vfdhd_mod,
198     VFDHD_MAX_DRIVES, 10, 31, 1, VFDHD_MAX_DRIVES, VFDHD_MAX_DRIVES,
199     NULL, NULL, &vfdhd_reset,
200     NULL, &vfdhd_attach, &vfdhd_detach,
201     &vfdhd_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
202     vfdhd_dt, NULL, "Vector Graphic FD-HD Controller VFDHD"
203 };
204 
205 /* Reset routine */
vfdhd_reset(DEVICE * dptr)206 static t_stat vfdhd_reset(DEVICE *dptr)
207 {
208     PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
209 
210     if(dptr->flags & DEV_DIS) {
211         sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &vfdhddev, TRUE);
212     } else {
213         /* Connect MFDC at base address */
214         if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &vfdhddev, FALSE) != 0) {
215             printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base);
216             return SCPE_ARG;
217         }
218     }
219     return SCPE_OK;
220 }
221 
222 
223 /* Attach routine */
vfdhd_attach(UNIT * uptr,char * cptr)224 static t_stat vfdhd_attach(UNIT *uptr, char *cptr)
225 {
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     uptr->capac = sim_fsize(uptr->fileref);
235 
236     for(i = 0; i < VFDHD_MAX_DRIVES; i++) {
237         vfdhd_info->drive[i].uptr = &vfdhd_dev.units[i];
238     }
239 
240     for(i = 0; i < VFDHD_MAX_DRIVES; i++) {
241         if(vfdhd_dev.units[i].fileref == uptr->fileref) {
242             break;
243         }
244     }
245 
246     if(uptr->capac > 0) {
247         r = assignDiskType(uptr);
248         if (r != SCPE_OK) {
249             vfdhd_detach(uptr);
250             return r;
251         }
252     } else {
253         /* creating file, must be DSK format. */
254         uptr->u3 = IMAGE_TYPE_DSK;
255     }
256 
257     if (uptr->flags & UNIT_VFDHD_VERBOSE)
258         printf("VFDHD%d: attached to '%s', type=%s, len=%d\n", i, cptr,
259             uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",
260             uptr->capac);
261 
262     if(uptr->u3 == IMAGE_TYPE_IMD) {
263         if(uptr->capac < 318000) {
264             printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n");
265             vfdhd_detach(uptr);
266             return SCPE_OPENERR;
267         }
268 
269         if (uptr->flags & UNIT_VFDHD_VERBOSE)
270             printf("--------------------------------------------------------\n");
271         vfdhd_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_VFDHD_VERBOSE));
272         if (uptr->flags & UNIT_VFDHD_VERBOSE)
273             printf("\n");
274     } else {
275         vfdhd_info->drive[i].imd = NULL;
276     }
277 
278     if(i>0) { /* Floppy Disk, Unit 1-3 */
279         vfdhd_info->drive[i].ntracks  = 77;     /* number of tracks */
280         vfdhd_info->drive[i].nheads   = 2;      /* number of heads */
281         vfdhd_info->drive[i].nspt     = 16;     /* number of sectors per track */
282         vfdhd_info->drive[i].npre_len = 40;     /* preamble length */
283         vfdhd_info->drive[i].sectsize = VFDHD_SECTOR_LEN;   /* sector size, not including pre/postamble */
284     } else { /* Hard Disk, Unit 0 */
285         if(hdSize == 10) {
286             vfdhd_info->drive[i].ntracks  = 153;    /* number of tracks */
287             vfdhd_info->drive[i].nheads   = 6;      /* number of heads */
288             vfdhd_info->hdsk_type = 1;
289             printf("10MB\n");
290         } else if (hdSize == 5) {
291             vfdhd_info->drive[i].ntracks  = 153;    /* number of tracks */
292             vfdhd_info->drive[i].nheads   = 4;      /* number of heads */
293             vfdhd_info->hdsk_type = 0;
294             printf("5MB\n");
295         } else {
296             vfdhd_info->drive[i].ntracks  = 512;    /* number of tracks */
297             vfdhd_info->drive[i].nheads   = 8;      /* number of heads */
298             vfdhd_info->hdsk_type = 1;
299             printf("32MB\n");
300         }
301 
302         vfdhd_info->drive[i].nheads   = 4;      /* number of heads */
303         vfdhd_info->drive[i].nspt     = 32;     /* number of sectors per track */
304         vfdhd_info->drive[i].npre_len = 30;     /* preamble length */
305         vfdhd_info->drive[i].sectsize = VFDHD_SECTOR_LEN;   /* sector size, not including pre/postamble */
306         vfdhd_info->drive[i].ready = 1;
307         vfdhd_info->drive[i].seek_complete = 1;
308         vfdhd_info->drive[i].sync_lost = 1;     /* Active LOW */
309     }
310 
311     vfdhd_info->motor_on = 1;
312     return SCPE_OK;
313 }
314 
315 
316 /* Detach routine */
vfdhd_detach(UNIT * uptr)317 static t_stat vfdhd_detach(UNIT *uptr)
318 {
319     t_stat r;
320     int8 i;
321 
322     for(i = 0; i < VFDHD_MAX_DRIVES; i++) {
323         if(vfdhd_dev.units[i].fileref == uptr->fileref) {
324             break;
325         }
326     }
327 
328     DBG_PRINT(("Detach VFDHD%d\n", i));
329     r = diskClose(&vfdhd_info->drive[i].imd);
330     if (r != SCPE_OK)
331         return r;
332 
333     r = detach_unit(uptr);  /* detach unit */
334     if (r != SCPE_OK)
335         return r;
336 
337     return SCPE_OK;
338 }
339 
340 
341 static uint8 cy;
adc(uint8 sum,uint8 a1)342 static uint8 adc(uint8 sum, uint8 a1)
343 {
344     uint32 total;
345 
346     total = sum + a1 + cy;
347 
348     if(total > 0xFF) {
349         cy = 1;
350     } else {
351         cy = 0;
352     }
353 
354     return(total & 0xFF);
355 }
356 
vfdhddev(const int32 port,const int32 io,const int32 data)357 static int32 vfdhddev(const int32 port, const int32 io, const int32 data)
358 {
359     DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port));
360     if(io) {
361         VFDHD_Write(port, data);
362         return 0;
363     } else {
364         return(VFDHD_Read(port));
365     }
366 }
367 
368 #define FDHD_CTRL_STATUS0   0   /* R=Status Port 0, W=Control Port 0 */
369 #define FDHD_CTRL_STATUS1   1   /* R=Status Port 1, W=Control Port 0 */
370 #define FDHD_DATA           2   /* R/W=Data Port */
371 #define FDHD_RESET_START    3   /* R=RESET, W=START */
372 
VFDHD_Read(const uint32 Addr)373 static uint8 VFDHD_Read(const uint32 Addr)
374 {
375     uint8 cData;
376     VFDHD_DRIVE_INFO    *pDrive;
377 
378     pDrive = &vfdhd_info->drive[vfdhd_info->sel_drive];
379 
380     cData = 0x00;
381 
382     switch(Addr & 0x3) {
383         case FDHD_CTRL_STATUS0:
384             cData  = (pDrive->wp & 1);                 /* [0] Write Protect (FD) */
385             cData |= (pDrive->ready & 1) << 1;         /* [1] Drive ready (HD) */
386             cData |= (pDrive->track == 0) ? 0x04 : 0;  /* [2] TK0 (FD/HD) */
387             cData |= (pDrive->write_fault & 1) << 3;   /* [3] Write Fault (HD) */
388             cData |= (pDrive->seek_complete & 1) << 4; /* [4] Seek Complete (HD) */
389             cData |= (pDrive->sync_lost & 1) << 5;     /* [5] Loss of Sync (HD) */
390             cData |= 0xC0;                                                              /* [7:6] Reserved (pulled up) */
391             sim_debug(STATUS_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD S0 = 0x%02x\n", PCX, cData);
392             break;
393         case FDHD_CTRL_STATUS1:
394             vfdhd_info->floppy_sel = (vfdhd_info->sel_drive == 0) ? 0 : 1;
395             cData  = (vfdhd_info->floppy_sel & 0x1);            /* [0] Floppy Selected */
396             cData |= (vfdhd_info->controller_busy & 0x1) << 1;  /* [1] Controller busy */
397             cData |= (vfdhd_info->motor_on & 0x1) << 2;         /* [2] Motor On (FD) */
398             cData |= (vfdhd_info->hdsk_type & 0x1) << 3;        /* [3] Hard Disk Type (0=5MB, 1=10MB) */
399             cData |= 0xF0;                                      /* [7:4] Reserved (pulled up) */
400             if(vfdhd_info->sel_drive == 0) {
401 /*              cData &= 0xF0; */
402             }
403 
404             vfdhd_info->controller_busy = 0;
405 
406             sim_debug(STATUS_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD S1 = 0x%02x\n", PCX, cData);
407             break;
408         case FDHD_DATA:
409 /*          DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " RD Data" NLP, PCX)); */
410             if(vfdhd_info->datacount+40 >= VFDHD_RAW_LEN) {
411                 sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount);
412                 vfdhd_info->datacount = 0;
413             }
414             cData = sdata.raw[vfdhd_info->datacount+40];
415 
416             vfdhd_info->datacount++;
417 
418 /*          DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " RD Data Sector %d[%03d]: 0x%02x" NLP, PCX, pDrive->sector, vfdhd_info->datacount, cData)); */
419             break;
420         case FDHD_RESET_START:      /* Reset */
421             sim_debug(CMD_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Reset\n", PCX);
422             vfdhd_info->datacount = 0;
423             cData = 0xFF;           /* Return High-Z data */
424             break;
425     }
426 
427     return (cData);
428 }
429 
VFDHD_Write(const uint32 Addr,uint8 cData)430 static uint8 VFDHD_Write(const uint32 Addr, uint8 cData)
431 {
432     VFDHD_DRIVE_INFO    *pDrive;
433 
434     pDrive = &vfdhd_info->drive[vfdhd_info->sel_drive];
435 
436     switch(Addr & 0x3) {
437         case FDHD_CTRL_STATUS0:
438             vfdhd_info->sel_drive = cData & 0x03;
439             vfdhd_info->head = (cData >> 2) & 0x7;
440             vfdhd_info->step = (cData >> 5) & 1;
441             vfdhd_info->direction = (cData >> 6) & 1;
442             vfdhd_info->rwc = (cData >> 7) & 1;
443 
444             sim_debug(WR_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " WR C0=%02x: sel_drive=%d, head=%d, step=%d, dir=%d, rwc=%d\n", PCX, cData, vfdhd_info->sel_drive, vfdhd_info->head, vfdhd_info->step, vfdhd_info->direction, vfdhd_info->rwc);
445 
446             if(vfdhd_info->step == 1) {
447                 if(vfdhd_info->direction == 1) { /* Step IN */
448                     pDrive->track++;
449                 } else { /* Step OUT */
450                     if(pDrive->track != 0) {
451                         pDrive->track--;
452                     }
453                 }
454                 sim_debug(SEEK_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Drive %d on track %d\n", PCX, vfdhd_info->sel_drive, pDrive->track);
455             }
456 
457             break;
458         case FDHD_CTRL_STATUS1:
459             vfdhd_info->sector = (cData & 0x1f);
460             vfdhd_info->read = (cData >> 5) & 1;
461             vfdhd_info->ecc_enable = (cData >> 6) & 1;
462             vfdhd_info->precomp = (cData >> 7) & 1;
463             if(cData == 0xFF) {
464                 sim_debug(SEEK_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Home Disk %d\n", PCX, vfdhd_info->sel_drive);
465                 pDrive->track = 0;
466             }
467             DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " WR C1=%02x: sector=%d, read=%d, ecc_en=%d, precomp=%d" NLP,
468                 PCX,
469                 cData,
470                 vfdhd_info->sector,
471                 vfdhd_info->read,
472                 vfdhd_info->ecc_enable,
473                 vfdhd_info->precomp));
474             break;
475         case FDHD_DATA:     /* Data Port */
476             DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " WR Data" NLP, PCX));
477 #ifdef USE_VGI
478             if(vfdhd_info->sel_drive > 0) { /* Floppy */
479                 if(vfdhd_info->datacount >= VFDHD_RAW_LEN) {
480                     sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount);
481                     vfdhd_info->datacount = 0;
482                 }
483                 sdata.raw[vfdhd_info->datacount] = cData;
484             } else { /* Hard */
485                 if(vfdhd_info->datacount+10 >= VFDHD_RAW_LEN) {
486                     sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount);
487                     vfdhd_info->datacount = 0;
488                 }
489                 sdata.raw[vfdhd_info->datacount+10] = cData;
490             }
491 #else
492             if((vfdhd_info->datacount-13 >= VFDHD_RAW_LEN) || (vfdhd_info->datacount < 13)) {
493                 sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount);
494                 vfdhd_info->datacount = 13;
495             }
496             sdata.u.data[vfdhd_info->datacount-13] = cData;
497 #endif /* USE_VGI */
498 
499             vfdhd_info->datacount ++;
500 
501             break;
502         case FDHD_RESET_START:
503             sim_debug(CMD_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Start Command\n", PCX);
504             VFDHD_Command();
505             break;
506     }
507 
508     cData = 0x00;
509 
510     return (cData);
511 }
512 
VFDHD_Command(void)513 static void VFDHD_Command(void)
514 {
515     VFDHD_DRIVE_INFO *pDrive;
516 
517     uint32 bytesPerTrack;
518     uint32 bytesPerHead;
519 
520     uint32 sec_offset;
521     uint32 flags;
522     int32 rtn;
523 
524     pDrive = &(vfdhd_info->drive[vfdhd_info->sel_drive]);
525 
526     bytesPerTrack = pDrive->sectsize * pDrive->nspt;
527     bytesPerHead  = bytesPerTrack * pDrive->ntracks;
528 
529     sec_offset = (pDrive->track * bytesPerTrack) + \
530                  (vfdhd_info->head * bytesPerHead) + \
531                  (vfdhd_info->sector * pDrive->sectsize);
532 
533     vfdhd_info->controller_busy = 1;
534 
535     if(vfdhd_info->read == 1) { /* Perform a Read operation */
536         unsigned int i, checksum;
537         uint32 readlen;
538 
539         sim_debug(RD_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD: Drive=%d, Track=%d, Head=%d, Sector=%d\n", PCX, vfdhd_info->sel_drive, pDrive->track, vfdhd_info->head, vfdhd_info->sector);
540 
541         /* Clear out unused portion of sector. */
542         memset(&sdata.u.unused[0], 0x00, 10);
543 
544         sdata.u.sync = 0xFF;
545         sdata.u.header[0] = pDrive->track & 0xFF;
546         sdata.u.header[1] = vfdhd_info->sector;
547 
548         switch((pDrive->uptr)->u3)
549         {
550             case IMAGE_TYPE_IMD:
551                 if(pDrive->imd == NULL) {
552                     printf(".imd is NULL!" NLP);
553                 }
554                 printf("%s: Read: imd=%p" NLP, __FUNCTION__, pDrive->imd);
555                 sectRead(pDrive->imd,
556                     pDrive->track,
557                     vfdhd_info->head,
558                     vfdhd_info->sector,
559                     sdata.u.data,
560                     256,
561                     &flags,
562                     &readlen);
563 
564                 adc(0,0); /* clear Carry bit */
565                 checksum = 0;
566 
567                 /* Checksum everything except the sync byte */
568                 for(i=1;i<269;i++) {
569                     checksum = adc(checksum, sdata.raw[i+40]);
570                 }
571 
572                 sdata.u.checksum = checksum & 0xFF;
573                 sdata.u.ecc_valid = 0xAA;
574                 break;
575             case IMAGE_TYPE_DSK:
576                 if(pDrive->uptr->fileref == NULL) {
577                     printf(".fileref is NULL!" NLP);
578                 } else {
579                     sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);
580                     rtn = sim_fread(&sdata.u.sync, 1, 274, /*VFDHD_SECTOR_LEN,*/ (pDrive->uptr)->fileref);
581                     if (rtn != 274) {
582                         sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " READ: sim_fread error.\n", PCX);
583                     }
584 
585                     memset(&sdata.u.preamble, 0, 40);
586                     memset(&sdata.u.ecc, 0, 5); /* Clear out the ECC and ECC Valid bytes */
587                     sdata.u.ecc_valid = 0xAA;
588                     for(vfdhd_info->datacount = 0; sdata.raw[vfdhd_info->datacount] == 0x00; vfdhd_info->datacount++) {
589                     }
590 
591                     DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " READ: Sync found at offset %d" NLP, PCX, vfdhd_info->datacount));
592 
593                 }
594                 break;
595             case IMAGE_TYPE_CPT:
596                 printf("%s: CPT Format not supported" NLP, __FUNCTION__);
597                 break;
598             default:
599                 printf("%s: Unknown image Format" NLP, __FUNCTION__);
600                 break;
601         }
602 
603     } else {    /* Perform a Write operation */
604         uint32 writelen;
605 
606         sim_debug(WR_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " WR: Drive=%d, Track=%d, Head=%d, Sector=%d\n", PCX, vfdhd_info->sel_drive, pDrive->track, vfdhd_info->head, vfdhd_info->sector);
607 
608 #ifdef USE_VGI
609 #else
610         int data_index = vfdhd_info->datacount - 13;
611 
612         sec_offset = (pDrive->track * 4096) + \
613                      (vfdhd_info->head * 315392) + \
614                      (vfdhd_info->sector * 256);
615 #endif /* USE_VGI */
616 
617         switch((pDrive->uptr)->u3)
618         {
619             case IMAGE_TYPE_IMD:
620                 if(pDrive->imd == NULL) {
621                     printf(".imd is NULL!" NLP);
622                 }
623                 sectWrite(pDrive->imd,
624                     pDrive->track,
625                     vfdhd_info->head,
626                     vfdhd_info->sector,
627                     sdata.u.data,
628                     256,
629                     &flags,
630                     &writelen);
631                 break;
632             case IMAGE_TYPE_DSK:
633                 if(pDrive->uptr->fileref == NULL) {
634                     printf(".fileref is NULL!" NLP);
635                 } else {
636                     DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " WR drive=%d, track=%d, head=%d, sector=%d" NLP,
637                         PCX,
638                         vfdhd_info->sel_drive,
639                         pDrive->track,
640                         vfdhd_info->head,
641                         vfdhd_info->sector));
642                     sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);
643 #ifdef USE_VGI
644                     sim_fwrite(&sdata.u.sync, 1, VFDHD_SECTOR_LEN, (pDrive->uptr)->fileref);
645 #else
646                     sim_fwrite(sdata.u.data, 1, 256, (pDrive->uptr)->fileref);
647 #endif /* USE_VGI */
648                 }
649                 break;
650             case IMAGE_TYPE_CPT:
651                 printf("%s: CPT Format not supported" NLP, __FUNCTION__);
652                 break;
653             default:
654                 printf("%s: Unknown image Format" NLP, __FUNCTION__);
655                 break;
656         }
657     }
658 }
659