]> Shamusworld >> Repos - apple2/blob - apple2/src/floppy.cpp
9c0165c4d0d86a203b247c474c9da7bddd0d4707
[apple2] / apple2 / src / floppy.cpp
1 //\r
2 // Apple 2 floppy disk support\r
3 //\r
4 // by James L. Hammons\r
5 // (c) 2005 Underground Software\r
6 //\r
7 // JLH = James L. Hammons <jlhamm@acm.org>\r
8 //\r
9 // WHO  WHEN        WHAT\r
10 // ---  ----------  ------------------------------------------------------------\r
11 // JLH  12/03/2005  Created this file\r
12 // JLH  12/15/2005  Fixed nybblization functions to work properly\r
13 // JLH  12/27/2005  Added blank disk creation, fixed saving to work properly\r
14 //\r
15 \r
16 #include "floppy.h"\r
17 \r
18 #include <stdio.h>\r
19 #include <string>\r
20 #include "apple2.h"\r
21 #include "log.h"\r
22 #include "applevideo.h"                                 // For message spawning... Though there's probably a better approach than this!\r
23 \r
24 using namespace std;\r
25 \r
26 // Useful enums\r
27 \r
28 enum { IO_MODE_READ, IO_MODE_WRITE };\r
29 \r
30 // FloppyDrive class variable initialization\r
31 \r
32 uint8 FloppyDrive::header[21] = {\r
33         0xD5, 0xAA, 0x96, 0xFF, 0xFE, 0x00, 0x00, 0x00,\r
34         0x00, 0x00, 0x00, 0xDE, 0xAA, 0xFF,     0xFF, 0xFF,\r
35         0xFF, 0xFF, 0xD5, 0xAA, 0xAD };\r
36 uint8 FloppyDrive::doSector[16] = {\r
37         0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF };\r
38 uint8 FloppyDrive::poSector[16] = {\r
39         0x0, 0x8, 0x1, 0x9, 0x2, 0xA, 0x3, 0xB, 0x4, 0xC, 0x5, 0xD, 0x6, 0xE, 0x7, 0xF };\r
40 \r
41 // FloppyDrive class implementation...\r
42 \r
43 FloppyDrive::FloppyDrive(): motorOn(0), activeDrive(0), ioMode(IO_MODE_READ), phase(0), track(0)\r
44 {\r
45         disk[0] = disk[1] = NULL;\r
46         diskSize[0] = diskSize[1] = 0;\r
47         diskType[0] = diskType[1] = DT_UNKNOWN;\r
48         imageDirty[0] = imageDirty[1] = false;\r
49         imageName[0][0] = imageName[1][0] = 0;                  // Zero out filenames\r
50 }\r
51 \r
52 FloppyDrive::~FloppyDrive()\r
53 {\r
54         if (disk[0])\r
55                 delete[] disk[0];\r
56 \r
57         if (disk[1])\r
58                 delete[] disk[1];\r
59 }\r
60 \r
61 bool FloppyDrive::LoadImage(const char * filename, uint8 driveNum/*= 0*/)\r
62 {\r
63         if (driveNum > 1)\r
64         {\r
65                 WriteLog("FLOPPY: Attempted to load image to drive #%u!\n", driveNum);\r
66                 return false;\r
67         }\r
68 \r
69         imageName[driveNum][0] = 0;                                     // Zero out filename, in case it doesn't load\r
70 \r
71         FILE * fp = fopen(filename, "rb");\r
72 \r
73         if (fp == NULL)\r
74         {\r
75                 WriteLog("FLOPPY: Failed to open image file '%s' for reading...\n", filename);\r
76                 return false;\r
77         }\r
78 \r
79         if (disk[driveNum])\r
80                 delete[] disk[driveNum];\r
81 \r
82         fseek(fp, 0, SEEK_END);\r
83         diskSize[driveNum] = ftell(fp);\r
84         fseek(fp, 0, SEEK_SET);\r
85         disk[driveNum] =  new uint8[diskSize[driveNum]];\r
86         fread(disk[driveNum], 1, diskSize[driveNum], fp);\r
87 \r
88         fclose(fp);\r
89 //printf("Read disk image: %u bytes.\n", diskSize);\r
90         DetectImageType(filename, driveNum);\r
91         strcpy(imageName[driveNum], filename);\r
92 \r
93         return true;\r
94 }\r
95 \r
96 bool FloppyDrive::SaveImage(uint8 driveNum/*= 0*/)\r
97 {\r
98         if (driveNum > 1)\r
99         {\r
100                 WriteLog("FLOPPY: Attempted to save image to drive #%u!\n", driveNum);\r
101                 return false;\r
102         }\r
103 \r
104         if (!imageDirty[driveNum])\r
105         {\r
106                 WriteLog("FLOPPY: No need to save unchanged image...\n");\r
107                 return false;\r
108         }\r
109 \r
110         if (imageName[driveNum][0] == 0)\r
111         {\r
112                 WriteLog("FLOPPY: Attempted to save non-existant image!\n");\r
113                 return false;\r
114         }\r
115 \r
116         if (diskType[driveNum] == DT_NYBBLE)\r
117                 memcpy(disk[driveNum], nybblizedImage[driveNum], 232960);\r
118         else\r
119                 DenybblizeImage(driveNum);\r
120 \r
121         FILE * fp = fopen(imageName[driveNum], "wb");\r
122 \r
123         if (fp == NULL)\r
124         {\r
125                 WriteLog("FLOPPY: Failed to open image file '%s' for writing...\n", imageName[driveNum]);\r
126                 return false;\r
127         }\r
128 \r
129         fwrite(disk[driveNum], 1, diskSize[driveNum], fp);\r
130         fclose(fp);\r
131 \r
132         return true;\r
133 }\r
134 \r
135 bool FloppyDrive::SaveImageAs(const char * filename, uint8 driveNum/*= 0*/)\r
136 {\r
137 //WARNING: Buffer overflow possibility\r
138         strcpy(imageName[driveNum], filename);\r
139         return SaveImage(driveNum);\r
140 }\r
141 \r
142 void FloppyDrive::CreateBlankImage(uint8 driveNum/*= 0*/)\r
143 {\r
144         if (disk[driveNum] != NULL)\r
145                 delete disk[driveNum];\r
146 \r
147         disk[driveNum] = new uint8[143360];\r
148         diskSize[driveNum] = 143360;\r
149         memset(disk[driveNum], 0x00, 143360);\r
150         memset(nybblizedImage[driveNum], 0x00, 232960); // Set it to 0 instead of $FF for proper formatting...\r
151         diskType[driveNum] = DT_DOS33;\r
152         strcpy(imageName[driveNum], "newblank.dsk");\r
153 SpawnMessage("New blank image inserted in drive %u...", driveNum);\r
154 }\r
155 \r
156 void FloppyDrive::SwapImages(void)\r
157 {\r
158         uint8 nybblizedImageTmp[232960];\r
159         char imageNameTmp[MAX_PATH];\r
160 \r
161         memcpy(nybblizedImageTmp, nybblizedImage[0], 232960);\r
162         memcpy(nybblizedImage[0], nybblizedImage[1], 232960);\r
163         memcpy(nybblizedImage[1], nybblizedImageTmp, 232960);\r
164 \r
165         memcpy(imageNameTmp, imageName[0], MAX_PATH);\r
166         memcpy(imageName[0], imageName[1], MAX_PATH);\r
167         memcpy(imageName[1], imageNameTmp, MAX_PATH);\r
168 \r
169         uint8 * diskTmp = disk[0];\r
170         disk[0] = disk[1];\r
171         disk[1] = diskTmp;\r
172 \r
173         uint32 diskSizeTmp = diskSize[0];\r
174         diskSize[0] = diskSize[1];\r
175         diskSize[1] = diskSizeTmp;\r
176 \r
177         uint8 diskTypeTmp = diskType[0];\r
178         diskType[0] = diskType[1];\r
179         diskType[1] = diskTypeTmp;\r
180 \r
181         uint8 imageDirtyTmp = imageDirty[0];\r
182         imageDirty[0] = imageDirty[1];\r
183         imageDirty[1] = imageDirtyTmp;\r
184 SpawnMessage("Drive 0: %s...", imageName[0]);\r
185 }\r
186 \r
187 void FloppyDrive::DetectImageType(const char * filename, uint8 driveNum)\r
188 {\r
189         diskType[driveNum] = DT_UNKNOWN;\r
190 \r
191         if (diskSize[driveNum] == 232960)\r
192         {\r
193                 diskType[driveNum] = DT_NYBBLE;\r
194                 memcpy(nybblizedImage[driveNum], disk[driveNum], 232960);\r
195         }\r
196         else if (diskSize[driveNum] == 143360)\r
197         {\r
198                 const char * ext = strrchr(filename, '.');\r
199 \r
200                 if (ext == NULL)\r
201                         return;\r
202 WriteLog("FLOPPY: Found extension [%s]...\n", ext);\r
203 \r
204 //Apparently .dsk can house either DOS order OR PRODOS order... !!! FIX !!!\r
205 //[DONE, see below why we don't need it]\r
206                 if (strcasecmp(ext, ".po") == 0)\r
207                         diskType[driveNum] = DT_PRODOS;\r
208                 else if ((strcasecmp(ext, ".do") == 0) || (strcasecmp(ext, ".dsk") == 0))\r
209                 {\r
210                         diskType[driveNum] = DT_DOS33;\r
211 //WriteLog("Detected DOS 3.3 disk!\n");\r
212 /*\r
213 This doesn't seem to be accurate... Maybe it's just a ProDOS disk in a DOS33 order...\r
214 That would seem to be the case--just because it's a ProDOS disk doesn't mean anything\r
215 WRT to the disk image itself.\r
216                         // This could really be a ProDOS order disk with a .dsk extension, so let's see...\r
217                         char fingerprint[3][4] = {\r
218                                 { 0x04, 0x00, 0x00, 0x00 },             // @ $500\r
219                                 { 0x03, 0x00, 0x05, 0x00 },             // @ $700\r
220                                 { 0x02, 0x00, 0x04, 0x00 } };   // @ $900\r
221 \r
222                         if ((strcmp((char *)(disk[driveNum] + 0x500), fingerprint[0]) == 0)\r
223                                 && (strcmp((char *)(disk[driveNum] + 0x700), fingerprint[1]) == 0)\r
224                                 && (strcmp((char *)(disk[driveNum] + 0x900), fingerprint[2]) == 0))\r
225                                 diskType[driveNum] = DT_PRODOS;\r
226 //*/\r
227                 }\r
228 \r
229                 NybblizeImage(driveNum);\r
230         }\r
231 WriteLog("FLOPPY: Detected image type %s...\n", (diskType[driveNum] == DT_NYBBLE ?\r
232         "Nybble image" : (diskType[driveNum] == DT_DOS33 ?\r
233         "DOS 3.3 image" : (diskType[driveNum] == DT_PRODOS ? "ProDOS image" : "unknown"))));\r
234 }\r
235 \r
236 void FloppyDrive::NybblizeImage(uint8 driveNum)\r
237 {\r
238         // Format of a sector is header (23) + nybbles (343) + footer (30) = 396\r
239         // (short by 20 bytes of 416 [413 if 48 byte header is one time only])\r
240 // Hmph. Who'da thunk that AppleWin's nybblization routines would be wrong?\r
241 // This is now correct, BTW\r
242         // hdr (21) + nybbles (343) + footer (48) = 412 bytes per sector\r
243         // (not incl. 64 byte track marker)\r
244 \r
245         uint8 footer[48] = {\r
246                 0xDE, 0xAA, 0xEB, 0xFF, 0xEB, 0xFF, 0xFF, 0xFF,\r
247                 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r
248                 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r
249                 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r
250                 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r
251                 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };\r
252 \r
253         uint8 diskbyte[0x40] = {\r
254                 0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6,\r
255                 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3,\r
256                 0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC,\r
257                 0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3,\r
258                 0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE,\r
259                 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC,\r
260                 0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,\r
261                 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF };\r
262 \r
263         uint8 * img = nybblizedImage[driveNum];\r
264         memset(img, 0xFF, 232960);                                      // Doesn't matter if 00s or FFs...\r
265 \r
266         for(uint8 trk=0; trk<35; trk++)\r
267         {\r
268                 memset(img, 0xFF, 64);                                  // Write gap 1, 64 bytes (self-sync)\r
269                 img += 64;\r
270 \r
271                 for(uint8 sector=0; sector<16; sector++)\r
272                 {\r
273                         memcpy(img, header, 21);                        // Set up the sector header\r
274 \r
275                         img[5] = ((trk >> 1) & 0x55) | 0xAA;\r
276                         img[6] =  (trk       & 0x55) | 0xAA;\r
277                         img[7] = ((sector >> 1) & 0x55) | 0xAA;\r
278                         img[8] =  (sector       & 0x55) | 0xAA;\r
279                         img[9] = (((trk ^ sector ^ 0xFE) >> 1) & 0x55) | 0xAA;\r
280                         img[10] = ((trk ^ sector ^ 0xFE)       & 0x55) | 0xAA;\r
281 \r
282                         img += 21;\r
283                         uint8 * bytes = disk[driveNum];\r
284 \r
285                         if (diskType[driveNum] == DT_DOS33)\r
286                                 bytes += (doSector[sector] * 256) + (trk * 256 * 16);\r
287                         else if (diskType[driveNum] == DT_PRODOS)\r
288                                 bytes += (poSector[sector] * 256) + (trk * 256 * 16);\r
289                         else\r
290                                 bytes += (sector * 256) + (trk * 256 * 16);\r
291 \r
292                         // Convert the 256 8-bit bytes into 342 6-bit bytes.\r
293 \r
294                         for(uint16 i=0; i<0x56; i++)\r
295                         {\r
296                                 img[i] = ((bytes[(i + 0xAC) & 0xFF] & 0x01) << 7)\r
297                                         | ((bytes[(i + 0xAC) & 0xFF] & 0x02) << 5)\r
298                                         | ((bytes[(i + 0x56) & 0xFF] & 0x01) << 5)\r
299                                         | ((bytes[(i + 0x56) & 0xFF] & 0x02) << 3)\r
300                                         | ((bytes[(i + 0x00) & 0xFF] & 0x01) << 3)\r
301                                         | ((bytes[(i + 0x00) & 0xFF] & 0x02) << 1);\r
302                         }\r
303 \r
304                         img[0x54] &= 0x3F;\r
305                         img[0x55] &= 0x3F;\r
306                         memcpy(img + 0x56, bytes, 256);\r
307 \r
308                         // XOR the data block with itself, offset by one byte,\r
309                         // creating a 343rd byte which is used as a cheksum.\r
310 \r
311                         img[342] = 0x00;\r
312 \r
313                         for(uint16 i=342; i>0; i--)\r
314                                 img[i] = img[i] ^ img[i - 1];\r
315 \r
316                         // Using a lookup table, convert the 6-bit bytes into disk bytes.\r
317 \r
318                         for(uint16 i=0; i<343; i++)\r
319                                 img[i] = diskbyte[img[i] >> 2];\r
320 \r
321                         img += 343;\r
322 \r
323                         // Done with the nybblization, now for the epilogue...\r
324 \r
325                         memcpy(img, footer, 48);\r
326                         img += 48;\r
327                 }\r
328         }\r
329 }\r
330 \r
331 void FloppyDrive::DenybblizeImage(uint8 driveNum)\r
332 {\r
333         uint8 decodeNybble[0x80] = {\r
334                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
335                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
336                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,\r
337                 0x00, 0x00, 0x08, 0x0C, 0x00, 0x10, 0x14, 0x18,\r
338                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20,\r
339                 0x00, 0x00, 0x00, 0x24, 0x28, 0x2C, 0x30, 0x34,\r
340                 0x00, 0x00, 0x38, 0x3C, 0x40, 0x44, 0x48, 0x4C,\r
341                 0x00, 0x50, 0x54, 0x58, 0x5C, 0x60, 0x64, 0x68,\r
342                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
343                 0x00, 0x00, 0x00, 0x6C, 0x00, 0x70, 0x74, 0x78,\r
344                 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x80, 0x84,\r
345                 0x00, 0x88, 0x8C, 0x90, 0x94, 0x98, 0x9C, 0xA0,\r
346                 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xA8, 0xAC,\r
347                 0x00, 0xB0, 0xB4, 0xB8, 0xBC, 0xC0, 0xC4, 0xC8,\r
348                 0x00, 0x00, 0xCC, 0xD0, 0xD4, 0xD8, 0xDC, 0xE0,\r
349                 0x00, 0xE4, 0xE8, 0xEC, 0xF0, 0xF4, 0xF8, 0xFC };\r
350 \r
351         // Sanity checks...\r
352         if (disk[driveNum] == NULL || diskSize[driveNum] < 143360)\r
353         {\r
354                 WriteLog("FLOPPY: Source disk image invalid! [drive=%u, disk=%08X, diskSize=%u]\n",\r
355                         driveNum, disk[driveNum], diskSize[driveNum]);\r
356                 return;\r
357         }\r
358 \r
359         uint8 * srcImg = nybblizedImage[driveNum];\r
360         uint8 * dstImg = disk[driveNum];\r
361         uint8 buffer[345];                                                      // 2 extra bytes for the unpack routine below...\r
362 \r
363         for(uint8 trk=0; trk<35; trk++)\r
364         {\r
365                 uint8 * trackBase = srcImg + (trk * 6656);\r
366 \r
367                 for(uint8 sector=0; sector<16; sector++)\r
368                 {\r
369                         uint16 sectorStart = (uint16)-1;\r
370 \r
371                         for(uint16 i=0; i<6656; i++)\r
372                         {\r
373                                 if (trackBase[i] == header[0]\r
374                                         && trackBase[(i + 1) % 6656] == header[1]\r
375                                         && trackBase[(i + 2) % 6656] == header[2]\r
376                                         && trackBase[(i + 3) % 6656] == header[3]\r
377                                         && trackBase[(i + 4) % 6656] == header[4])\r
378                                 {\r
379 //Could also check the track # at +5,6...\r
380                                         uint8 foundSector = ((trackBase[(i + 7) % 6656] & 0x55) << 1)\r
381                                                 | (trackBase[(i + 8) % 6656] & 0x55);\r
382 \r
383                                         if (foundSector == sector)\r
384                                         {\r
385                                                 sectorStart = (i + 21) % 6656;\r
386                                                 break;\r
387                                         }\r
388                                 }\r
389                         }\r
390 \r
391                         // Sanity check...\r
392                         if (sectorStart == (uint16)-1)\r
393                         {\r
394                                 WriteLog("FLOPPY: Failed to find sector %u (track %u) in nybble image!\n",\r
395                                         sector, trk);\r
396                                 return;\r
397                         }\r
398 \r
399                         // Using a lookup table, convert the disk bytes into 6-bit bytes.\r
400 \r
401                         for(uint16 i=0; i<343; i++)\r
402                                 buffer[i] = decodeNybble[trackBase[(sectorStart + i) % 6656] & 0x7F];\r
403 \r
404                         // XOR the data block with itself, offset by one byte.\r
405 \r
406                         for(uint16 i=1; i<342; i++)\r
407                                 buffer[i] = buffer[i] ^ buffer[i - 1];\r
408 \r
409                         // Convert the 342 6-bit bytes into 256 8-bit bytes (at buffer + $56).\r
410 \r
411                         for(uint16 i=0; i<0x56; i++)\r
412                         {\r
413                                 buffer[0x056 + i] |= ((buffer[i] >> 3) & 0x01) | ((buffer[i] >> 1) & 0x02);\r
414                                 buffer[0x0AC + i] |= ((buffer[i] >> 5) & 0x01) | ((buffer[i] >> 3) & 0x02);\r
415                                 buffer[0x102 + i] |= ((buffer[i] >> 7) & 0x01) | ((buffer[i] >> 5) & 0x02);\r
416                         }\r
417 \r
418                         uint8 * bytes = dstImg;\r
419 \r
420                         if (diskType[driveNum] == DT_DOS33)\r
421                                 bytes += (doSector[sector] * 256) + (trk * 256 * 16);\r
422                         else if (diskType[driveNum] == DT_PRODOS)\r
423                                 bytes += (poSector[sector] * 256) + (trk * 256 * 16);\r
424                         else\r
425                                 bytes += (sector * 256) + (trk * 256 * 16);//*/\r
426 \r
427                         memcpy(bytes, buffer + 0x56, 256);\r
428                 }\r
429         }\r
430 }\r
431 \r
432 // Memory mapped I/O functions\r
433 \r
434 /*\r
435 The DSK format is a byte-for-byte image of a 16-sector Apple II floppy disk: 35 tracks of 16\r
436 sectors of 256 bytes each, making 143,360 bytes in total. The PO format is exactly the same\r
437 size as DSK and is also organized as 35 sequential tracks, but the sectors within each track\r
438 are in a different sequence. The NIB format is a nybblized format: a more direct representation\r
439 of the disk's data as encoded by the Apple II floppy drive hardware. NIB contains 35 tracks of\r
440 6656 bytes each, for a total size of 232,960 bytes. Although this format is much larger, it is\r
441 also more versatile and can represent the older 13-sector disks, many copy-protected disks, and\r
442 other unusual encodings.\r
443 */\r
444 \r
445 void FloppyDrive::ControlStepper(uint8 addr)\r
446 {\r
447         // $C0E0 - 7\r
448 /*\r
449 What I can gather here:\r
450 bits 1-2 are the "phase" of the track (which is 1/4 of a full track (?))\r
451 bit 0 is the "do something" bit.\r
452 */\r
453         if (addr & 0x01)\r
454         {\r
455                 uint8 newPhase = (addr >> 1) & 0x03;\r
456 //WriteLog("*** Stepper change [%u]: track = %u, phase = %u, newPhase = %u\n", addr, track, phase, newPhase);\r
457 \r
458                 if (((phase + 1) & 0x03) == newPhase)\r
459                         phase += (phase < 79 ? 1 : 0);\r
460 \r
461                 if (((phase - 1) & 0x03) == newPhase)\r
462                         phase -= (phase > 0 ? 1 : 0);\r
463 \r
464                 if (!(phase & 0x01))\r
465                 {\r
466                         track = ((phase >> 1) < 35 ? phase >> 1 : 34);\r
467                         currentPos = 0;\r
468                 }\r
469 //WriteLog("                        track = %u, phase = %u, newPhase = %u\n", track, phase, newPhase);\r
470 SpawnMessage("Stepping to track %u...", track);\r
471         }\r
472 \r
473 //      return something if read mode...        \r
474 }\r
475 \r
476 void FloppyDrive::ControlMotor(uint8 addr)\r
477 {\r
478         // $C0E8 - 9\r
479         motorOn = addr;\r
480 }\r
481 \r
482 void FloppyDrive::DriveEnable(uint8 addr)\r
483 {\r
484         // $C0EA - B\r
485         activeDrive = addr;\r
486 }\r
487 \r
488 uint8 FloppyDrive::ReadWrite(void)\r
489 {\r
490 SpawnMessage("%sing %s track %u, sector %u...", (ioMode == IO_MODE_READ ? "Read" : "Write"),\r
491         (ioMode == IO_MODE_READ ? "from" : "to"), track, currentPos / 396);\r
492         // $C0EC\r
493 /*\r
494 I think what happens here is that once a track is read its nybblized form\r
495 is fed through here, one byte at a time--which means for DO disks, we have\r
496 to convert the actual 256 byte sector to a 416 byte nybblized data "sector".\r
497 Which we now do. :-)\r
498 */\r
499         if (ioMode == IO_MODE_WRITE && (latchValue & 0x80))\r
500         {\r
501                 nybblizedImage[activeDrive][(track * 6656) + currentPos] = latchValue;\r
502                 imageDirty[activeDrive] = true;\r
503         }\r
504 \r
505         uint8 diskByte = nybblizedImage[activeDrive][(track * 6656) + currentPos];\r
506         currentPos = (currentPos + 1) % 6656;\r
507 \r
508         return diskByte;\r
509 }\r
510 \r
511 uint8 FloppyDrive::GetLatchValue(void)\r
512 {\r
513         // $C0ED\r
514         return latchValue;\r
515 }\r
516 \r
517 void FloppyDrive::SetLatchValue(uint8 value)\r
518 {\r
519         // $C0ED\r
520         latchValue = value;\r
521 }\r
522 \r
523 void FloppyDrive::SetReadMode(void)\r
524 {\r
525         // $C0EE\r
526         ioMode = IO_MODE_READ;\r
527 }\r
528 \r
529 void FloppyDrive::SetWriteMode(void)\r
530 {\r
531         // $C0EF\r
532         ioMode = IO_MODE_WRITE;\r
533 }\r