]> Shamusworld >> Repos - apple2/blobdiff - src/floppy.cpp
Misc. improvements, added WOZ file support to floppy emulation
[apple2] / src / floppy.cpp
diff --git a/src/floppy.cpp b/src/floppy.cpp
deleted file mode 100644 (file)
index 859db6d..0000000
+++ /dev/null
@@ -1,872 +0,0 @@
-//
-// Apple 2 floppy disk support
-//
-// by James Hammons
-// (c) 2005 Underground Software
-//
-// JLH = James Hammons <jlhamm@acm.org>
-//
-// WHO  WHEN        WHAT
-// ---  ----------  -----------------------------------------------------------
-// JLH  12/03/2005  Created this file
-// JLH  12/15/2005  Fixed nybblization functions to work properly
-// JLH  12/27/2005  Added blank disk creation, fixed saving to work properly
-//
-
-#include "floppy.h"
-
-#include <stdio.h>
-#include <string.h>
-#include "apple2.h"
-#include "log.h"
-#include "video.h"             // For message spawning... Though there's probably a
-                                               // better approach than this!
-
-// Useful enums
-
-enum { IO_MODE_READ, IO_MODE_WRITE };
-
-// FloppyDrive class variable initialization
-
-uint8_t FloppyDrive::header[21] = {
-       0xD5, 0xAA, 0x96, 0xFF, 0xFE, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0xDE, 0xAA, 0xFF,     0xFF, 0xFF,
-       0xFF, 0xFF, 0xD5, 0xAA, 0xAD };
-uint8_t FloppyDrive::doSector[16] = {
-       0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF };
-uint8_t FloppyDrive::poSector[16] = {
-       0x0, 0x8, 0x1, 0x9, 0x2, 0xA, 0x3, 0xB, 0x4, 0xC, 0x5, 0xD, 0x6, 0xE, 0x7, 0xF };
-char FloppyDrive::nameBuf[MAX_PATH];
-
-
-// FloppyDrive class implementation...
-
-FloppyDrive::FloppyDrive(): motorOn(0), activeDrive(0), ioMode(IO_MODE_READ), phase(0), track(0), ioHappened(false)
-{
-       disk[0] = disk[1] = NULL;
-       diskSize[0] = diskSize[1] = 0;
-       diskType[0] = diskType[1] = DFT_UNKNOWN;
-       imageDirty[0] = imageDirty[1] = false;
-       writeProtected[0] = writeProtected[1] = false;
-       imageName[0][0] = imageName[1][0] = 0;                  // Zero out filenames
-}
-
-
-FloppyDrive::~FloppyDrive()
-{
-       if (disk[0])
-               delete[] disk[0];
-
-       if (disk[1])
-               delete[] disk[1];
-}
-
-
-bool FloppyDrive::LoadImage(const char * filename, uint8_t driveNum/*= 0*/)
-{
-       WriteLog("FLOPPY: Attempting to load image '%s' in drive #%u.\n", filename, driveNum);
-
-       if (driveNum > 1)
-       {
-               WriteLog("FLOPPY: Attempted to load image to drive #%u!\n", driveNum);
-               return false;
-       }
-
-       imageName[driveNum][0] = 0;                                     // Zero out filename, in case it doesn't load
-
-       FILE * fp = fopen(filename, "rb");
-
-       if (fp == NULL)
-       {
-               WriteLog("FLOPPY: Failed to open image file '%s' for reading...\n", filename);
-               return false;
-       }
-
-       if (disk[driveNum])
-               delete[] disk[driveNum];
-
-       fseek(fp, 0, SEEK_END);
-       diskSize[driveNum] = ftell(fp);
-       fseek(fp, 0, SEEK_SET);
-       disk[driveNum] =  new uint8_t[diskSize[driveNum]];
-       fread(disk[driveNum], 1, diskSize[driveNum], fp);
-
-       fclose(fp);
-//printf("Read disk image: %u bytes.\n", diskSize);
-       DetectImageType(filename, driveNum);
-       strcpy(imageName[driveNum], filename);
-
-#if 0
-       WriteLog("FLOPPY: Opening image for drive #%u.\n", driveNum);
-       FILE * fp2 = fopen("bt-nybblized.nyb", "wb");
-
-       if (fp2 == NULL)
-               WriteLog("FLOPPY: Failed to open image file 'bt-nybblized.nyb' for writing...\n");
-       else
-       {
-               fwrite(nybblizedImage[driveNum], 1, 232960, fp2);
-               fclose(fp2);
-       }
-#endif
-//writeProtected[driveNum] = true;
-       WriteLog("FLOPPY: Loaded image '%s' for drive #%u.\n", filename, driveNum);
-
-       return true;
-}
-
-
-bool FloppyDrive::SaveImage(uint8_t driveNum/*= 0*/)
-{
-       // Various sanity checks...
-       if (driveNum > 1)
-       {
-               WriteLog("FLOPPY: Attempted to save image to drive #%u!\n", driveNum);
-               return false;
-       }
-
-       if (!imageDirty[driveNum])
-       {
-               WriteLog("FLOPPY: No need to save unchanged image...\n");
-               return false;
-       }
-
-       if (imageName[driveNum][0] == 0)
-       {
-               WriteLog("FLOPPY: Attempted to save non-existant image!\n");
-               return false;
-       }
-
-       // Handle nybbylization, if necessary
-       if (diskType[driveNum] == DT_NYBBLE)
-               memcpy(disk[driveNum], nybblizedImage[driveNum], 232960);
-       else
-               DenybblizeImage(driveNum);
-
-       // Finally, write the damn image
-       FILE * fp = fopen(imageName[driveNum], "wb");
-
-       if (fp == NULL)
-       {
-               WriteLog("FLOPPY: Failed to open image file '%s' for writing...\n", imageName[driveNum]);
-               return false;
-       }
-
-       fwrite(disk[driveNum], 1, diskSize[driveNum], fp);
-       fclose(fp);
-
-       WriteLog("FLOPPY: Successfully wrote image file '%s'...\n", imageName[driveNum]);
-
-       return true;
-}
-
-
-bool FloppyDrive::SaveImageAs(const char * filename, uint8_t driveNum/*= 0*/)
-{
-//WARNING: Buffer overflow possibility
-#warning "Buffer overflow possible--!!! FIX !!!"
-       strcpy(imageName[driveNum], filename);
-       return SaveImage(driveNum);
-}
-
-
-void FloppyDrive::CreateBlankImage(uint8_t driveNum/*= 0*/)
-{
-       if (disk[driveNum] != NULL)
-               delete disk[driveNum];
-
-       disk[driveNum] = new uint8_t[143360];
-       diskSize[driveNum] = 143360;
-       memset(disk[driveNum], 0x00, 143360);
-       memset(nybblizedImage[driveNum], 0x00, 232960); // Set it to 0 instead of $FF for proper formatting...
-       diskType[driveNum] = DT_DOS33;
-       strcpy(imageName[driveNum], "newblank.dsk");
-       writeProtected[driveNum] = false;
-SpawnMessage("New blank image inserted in drive %u...", driveNum);
-}
-
-
-void FloppyDrive::SwapImages(void)
-{
-       uint8_t nybblizedImageTmp[232960];
-       char imageNameTmp[MAX_PATH];
-
-       memcpy(nybblizedImageTmp, nybblizedImage[0], 232960);
-       memcpy(nybblizedImage[0], nybblizedImage[1], 232960);
-       memcpy(nybblizedImage[1], nybblizedImageTmp, 232960);
-
-       memcpy(imageNameTmp, imageName[0], MAX_PATH);
-       memcpy(imageName[0], imageName[1], MAX_PATH);
-       memcpy(imageName[1], imageNameTmp, MAX_PATH);
-
-       uint8_t * diskTmp = disk[0];
-       disk[0] = disk[1];
-       disk[1] = diskTmp;
-
-       uint32_t diskSizeTmp = diskSize[0];
-       diskSize[0] = diskSize[1];
-       diskSize[1] = diskSizeTmp;
-
-       uint8_t diskTypeTmp = diskType[0];
-       diskType[0] = diskType[1];
-       diskType[1] = diskTypeTmp;
-
-       uint8_t imageDirtyTmp = imageDirty[0];
-       imageDirty[0] = imageDirty[1];
-       imageDirty[1] = imageDirtyTmp;
-
-       uint8_t writeProtectedTmp = writeProtected[0];
-       writeProtected[0] = writeProtected[1];
-       writeProtected[1] = writeProtectedTmp;
-SpawnMessage("Drive 0: %s...", imageName[0]);
-}
-
-
-void FloppyDrive::DetectImageType(const char * filename, uint8_t driveNum)
-{
-       diskType[driveNum] = DFT_UNKNOWN;
-
-       if (diskSize[driveNum] == 232960)
-       {
-               diskType[driveNum] = DT_NYBBLE;
-               memcpy(nybblizedImage[driveNum], disk[driveNum], 232960);
-       }
-       else if (diskSize[driveNum] == 143360)
-       {
-               const char * ext = strrchr(filename, '.');
-
-               if (ext == NULL)
-                       return;
-WriteLog("FLOPPY: Found extension [%s]...\n", ext);
-
-//Apparently .dsk can house either DOS order OR PRODOS order... !!! FIX !!!
-               if (strcasecmp(ext, ".po") == 0)
-                       diskType[driveNum] = DT_PRODOS;
-               else if ((strcasecmp(ext, ".do") == 0) || (strcasecmp(ext, ".dsk") == 0))
-               {
-                       // We assume this, but check for a PRODOS fingerprint. Trust, but
-                       // verify. ;-)
-                       diskType[driveNum] = DT_DOS33;
-
-                       uint8_t fingerprint[4][4] = {
-                               { 0x00, 0x00, 0x03, 0x00 },             // @ $400
-                               { 0x02, 0x00, 0x04, 0x00 },             // @ $600
-                               { 0x03, 0x00, 0x05, 0x00 },             // @ $800
-                               { 0x04, 0x00, 0x00, 0x00 }              // @ $A00
-                       };
-
-                       bool foundProdos = true;
-
-                       for(uint32_t i=0; i<4; i++)
-                       {
-                               for(uint32_t j=0; j<4; j++)
-                               {
-                                       if (disk[driveNum][0x400 + (i * 0x200) + j] != fingerprint[i][j])
-                                       {
-                                               foundProdos = false;
-                                               break;
-                                       }
-                               }
-                       }
-
-                       if (foundProdos)
-                               diskType[driveNum] = DT_PRODOS;
-               }
-
-// Actually, it just might matter WRT to nybblyzing/denybblyzing
-// (and, it does... :-P)
-               NybblizeImage(driveNum);
-       }
-       else if (diskSize[driveNum] == 143488)
-       {
-               diskType[driveNum] = DT_DOS33_HDR;
-               NybblizeImage(driveNum);
-       }
-
-#warning "Should we attempt to nybblize unknown images here? Definitely SHOULD issue a warning!"
-
-WriteLog("FLOPPY: Detected image type %s...\n", (diskType[driveNum] == DT_NYBBLE ?
-       "Nybble image" : (diskType[driveNum] == DT_DOS33 ?
-       "DOS 3.3 image" : (diskType[driveNum] == DT_DOS33_HDR ?
-       "DOS 3.3 image (headered)" : (diskType[driveNum] == DT_PRODOS ? "ProDOS image" : "unknown")))));
-}
-
-
-void FloppyDrive::NybblizeImage(uint8_t driveNum)
-{
-       // Format of a sector is header (23) + nybbles (343) + footer (30) = 396
-       // (short by 20 bytes of 416 [413 if 48 byte header is one time only])
-// Hmph. Who'da thunk that AppleWin's nybblization routines would be wrong?
-// This is now correct, BTW
-       // hdr (21) + nybbles (343) + footer (48) = 412 bytes per sector
-       // (not incl. 64 byte track marker)
-
-       uint8_t footer[48] = {
-               0xDE, 0xAA, 0xEB, 0xFF, 0xEB, 0xFF, 0xFF, 0xFF,
-               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
-       uint8_t diskbyte[0x40] = {
-               0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6,
-               0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3,
-               0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC,
-               0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3,
-               0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE,
-               0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC,
-               0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
-               0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF };
-
-       uint8_t * img = nybblizedImage[driveNum];
-       memset(img, 0xFF, 232960);                                      // Doesn't matter if 00s or FFs...
-
-       for(uint8_t trk=0; trk<35; trk++)
-       {
-               memset(img, 0xFF, 64);                                  // Write gap 1, 64 bytes (self-sync)
-               img += 64;
-
-               for(uint8_t sector=0; sector<16; sector++)
-               {
-                       memcpy(img, header, 21);                        // Set up the sector header
-
-                       img[5] = ((trk >> 1) & 0x55) | 0xAA;
-                       img[6] =  (trk       & 0x55) | 0xAA;
-                       img[7] = ((sector >> 1) & 0x55) | 0xAA;
-                       img[8] =  (sector       & 0x55) | 0xAA;
-                       img[9] = (((trk ^ sector ^ 0xFE) >> 1) & 0x55) | 0xAA;
-                       img[10] = ((trk ^ sector ^ 0xFE)       & 0x55) | 0xAA;
-
-                       img += 21;
-                       uint8_t * bytes = disk[driveNum];
-
-                       if (diskType[driveNum] == DT_DOS33)
-                               bytes += (doSector[sector] * 256) + (trk * 256 * 16);
-                       else if (diskType[driveNum] == DT_DOS33_HDR)
-                               bytes += (doSector[sector] * 256) + (trk * 256 * 16) + 128;
-                       else if (diskType[driveNum] == DT_PRODOS)
-                               bytes += (poSector[sector] * 256) + (trk * 256 * 16);
-                       else
-                               bytes += (sector * 256) + (trk * 256 * 16);
-
-                       // Convert the 256 8-bit bytes into 342 6-bit bytes.
-
-                       for(uint16_t i=0; i<0x56; i++)
-                       {
-                               img[i] = ((bytes[(i + 0xAC) & 0xFF] & 0x01) << 7)
-                                       | ((bytes[(i + 0xAC) & 0xFF] & 0x02) << 5)
-                                       | ((bytes[(i + 0x56) & 0xFF] & 0x01) << 5)
-                                       | ((bytes[(i + 0x56) & 0xFF] & 0x02) << 3)
-                                       | ((bytes[(i + 0x00) & 0xFF] & 0x01) << 3)
-                                       | ((bytes[(i + 0x00) & 0xFF] & 0x02) << 1);
-                       }
-
-                       img[0x54] &= 0x3F;
-                       img[0x55] &= 0x3F;
-                       memcpy(img + 0x56, bytes, 256);
-
-                       // XOR the data block with itself, offset by one byte,
-                       // creating a 343rd byte which is used as a cheksum.
-
-                       img[342] = 0x00;
-
-                       for(uint16_t i=342; i>0; i--)
-                               img[i] = img[i] ^ img[i - 1];
-
-                       // Using a lookup table, convert the 6-bit bytes into disk bytes.
-
-                       for(uint16_t i=0; i<343; i++)
-//#define TEST_NYBBLIZATION
-#ifdef TEST_NYBBLIZATION
-{
-WriteLog("FL: i = %u, img[i] = %02X, diskbyte = %02X\n", i, img[i], diskbyte[img[i] >> 2]);
-#endif
-                               img[i] = diskbyte[img[i] >> 2];
-#ifdef TEST_NYBBLIZATION
-//WriteLog("            img[i] = %02X\n", img[i]);
-}
-#endif
-                       img += 343;
-
-                       // Done with the nybblization, now for the epilogue...
-
-                       memcpy(img, footer, 48);
-                       img += 48;
-               }
-       }
-}
-
-
-void FloppyDrive::DenybblizeImage(uint8_t driveNum)
-{
-       uint8_t decodeNybble[0x80] = {
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
-               0x00, 0x00, 0x08, 0x0C, 0x00, 0x10, 0x14, 0x18,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20,
-               0x00, 0x00, 0x00, 0x24, 0x28, 0x2C, 0x30, 0x34,
-               0x00, 0x00, 0x38, 0x3C, 0x40, 0x44, 0x48, 0x4C,
-               0x00, 0x50, 0x54, 0x58, 0x5C, 0x60, 0x64, 0x68,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x6C, 0x00, 0x70, 0x74, 0x78,
-               0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x80, 0x84,
-               0x00, 0x88, 0x8C, 0x90, 0x94, 0x98, 0x9C, 0xA0,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xA8, 0xAC,
-               0x00, 0xB0, 0xB4, 0xB8, 0xBC, 0xC0, 0xC4, 0xC8,
-               0x00, 0x00, 0xCC, 0xD0, 0xD4, 0xD8, 0xDC, 0xE0,
-               0x00, 0xE4, 0xE8, 0xEC, 0xF0, 0xF4, 0xF8, 0xFC };
-
-       // Sanity checks...
-       if (disk[driveNum] == NULL || diskSize[driveNum] < 143360)
-       {
-               WriteLog("FLOPPY: Source disk image invalid! [drive=%u, disk=%08X, diskSize=%u]\n",
-                       driveNum, disk[driveNum], diskSize[driveNum]);
-               return;
-       }
-
-       uint8_t * srcImg = nybblizedImage[driveNum];
-       uint8_t * dstImg = disk[driveNum];
-       uint8_t buffer[345];                                                    // 2 extra bytes for the unpack routine below...
-
-       for(uint8_t trk=0; trk<35; trk++)
-       {
-               uint8_t * trackBase = srcImg + (trk * 6656);
-
-               for(uint8_t sector=0; sector<16; sector++)
-               {
-                       uint16_t sectorStart = (uint16_t)-1;
-
-                       for(uint16_t i=0; i<6656; i++)
-                       {
-                               if (trackBase[i] == header[0]
-                                       && trackBase[(i + 1) % 6656] == header[1]
-                                       && trackBase[(i + 2) % 6656] == header[2]
-                                       && trackBase[(i + 3) % 6656] == header[3]
-                                       && trackBase[(i + 4) % 6656] == header[4])
-                               {
-//Could also check the track # at +5,6...
-                                       uint8_t foundSector = ((trackBase[(i + 7) % 6656] & 0x55) << 1)
-                                               | (trackBase[(i + 8) % 6656] & 0x55);
-
-                                       if (foundSector == sector)
-                                       {
-                                               sectorStart = (i + 21) % 6656;
-                                               break;
-                                       }
-                               }
-                       }
-
-                       // Sanity check...
-                       if (sectorStart == (uint16_t)-1)
-                       {
-                               WriteLog("FLOPPY: Failed to find sector %u (track %u) in nybble image!\n",
-                                       sector, trk);
-                               return;
-                       }
-
-                       // Using a lookup table, convert the disk bytes into 6-bit bytes.
-
-                       for(uint16_t i=0; i<343; i++)
-                               buffer[i] = decodeNybble[trackBase[(sectorStart + i) % 6656] & 0x7F];
-
-                       // XOR the data block with itself, offset by one byte.
-
-                       for(uint16_t i=1; i<342; i++)
-                               buffer[i] = buffer[i] ^ buffer[i - 1];
-
-                       // Convert the 342 6-bit bytes into 256 8-bit bytes (at buffer + $56).
-
-                       for(uint16_t i=0; i<0x56; i++)
-                       {
-                               buffer[0x056 + i] |= ((buffer[i] >> 3) & 0x01) | ((buffer[i] >> 1) & 0x02);
-                               buffer[0x0AC + i] |= ((buffer[i] >> 5) & 0x01) | ((buffer[i] >> 3) & 0x02);
-                               buffer[0x102 + i] |= ((buffer[i] >> 7) & 0x01) | ((buffer[i] >> 5) & 0x02);
-                       }
-
-                       uint8_t * bytes = dstImg;
-
-                       if (diskType[driveNum] == DT_DOS33)
-                               bytes += (doSector[sector] * 256) + (trk * 256 * 16);
-                       else if (diskType[driveNum] == DT_DOS33_HDR)
-                               bytes += (doSector[sector] * 256) + (trk * 256 * 16) + 128;
-                       else if (diskType[driveNum] == DT_PRODOS)
-                               bytes += (poSector[sector] * 256) + (trk * 256 * 16);
-                       else
-                               bytes += (sector * 256) + (trk * 256 * 16);//*/
-
-                       memcpy(bytes, buffer + 0x56, 256);
-               }
-       }
-}
-
-
-const char * FloppyDrive::ImageName(uint8_t driveNum/*= 0*/)
-{
-       // Set up a zero-length string for return value
-       nameBuf[0] = 0;
-
-       if (driveNum > 1)
-       {
-               WriteLog("FLOPPY: Attempted to get image name for drive #%u!\n", driveNum);
-               return nameBuf;
-       }
-
-       // Now we attempt to strip out extraneous paths/extensions to get just the filename
-       const char * startOfFile = strrchr(imageName[driveNum], '/');
-       const char * startOfExt = strrchr(imageName[driveNum], '.');
-
-       // If there isn't a path, assume we're starting at the beginning
-       if (startOfFile == NULL)
-               startOfFile = &imageName[driveNum][0];
-       else
-               startOfFile++;
-
-       // If there isn't an extension, assume it's at the terminating NULL
-       if (startOfExt == NULL)
-               startOfExt = &imageName[driveNum][0] + strlen(imageName[driveNum]);
-
-       // Now copy the filename (may copy nothing!)
-       int j = 0;
-
-       for(const char * i=startOfFile; i<startOfExt; i++)
-               nameBuf[j++] = *i;
-
-       nameBuf[j] = 0;
-
-       return nameBuf;
-}
-
-
-void FloppyDrive::EjectImage(uint8_t driveNum/*= 0*/)
-{
-       // Sanity check
-       if (IsEmpty(driveNum))
-               return;
-
-       // Probably want to save a dirty image... ;-)
-       if (SaveImage(driveNum))
-               WriteLog("FLOPPY: Ejected image file '%s' from drive %u...\n", imageName[driveNum], driveNum);
-
-       if (disk[driveNum])
-               delete[] disk[driveNum];
-
-       disk[driveNum] = NULL;
-       diskSize[driveNum] = 0;
-       diskType[driveNum] = DFT_UNKNOWN;
-       imageDirty[driveNum] = false;
-       writeProtected[driveNum] = false;
-       imageName[driveNum][0] = 0;                     // Zero out filenames
-       memset(nybblizedImage[driveNum], 0xFF, 232960); // Doesn't matter if 00s or FFs...
-}
-
-
-bool FloppyDrive::IsEmpty(uint8_t driveNum/*= 0*/)
-{
-       if (driveNum > 1)
-       {
-               WriteLog("FLOPPY: Attempted DriveIsEmtpy() for drive #%u!\n", driveNum);
-               return true;
-       }
-
-       // This is kinda gay, but it works
-       return (imageName[driveNum][0] == 0 ? true : false);
-}
-
-
-bool FloppyDrive::IsWriteProtected(uint8_t driveNum/*= 0*/)
-{
-       if (driveNum > 1)
-       {
-               WriteLog("FLOPPY: Attempted DiskIsWriteProtected() for drive #%u!\n", driveNum);
-               return true;
-       }
-
-       return writeProtected[driveNum];
-}
-
-
-void FloppyDrive::SetWriteProtect(bool state, uint8_t driveNum/*= 0*/)
-{
-       if (driveNum > 1)
-       {
-               WriteLog("FLOPPY: Attempted set write protect for drive #%u!\n", driveNum);
-               return;
-       }
-
-       writeProtected[driveNum] = state;
-}
-
-
-int FloppyDrive::DriveLightStatus(uint8_t driveNum/*= 0*/)
-{
-       int retval = DLS_OFF;
-
-       if (activeDrive != driveNum)
-               return DLS_OFF;
-
-       if (ioHappened)
-               retval = (ioMode == IO_MODE_READ ? DLS_READ : DLS_WRITE);
-
-       ioHappened = false;
-       return retval;
-}
-
-
-void FloppyDrive::SaveState(FILE * file)
-{
-       // Internal state vars
-       fputc(motorOn, file);
-       fputc(activeDrive, file);
-       fputc(ioMode, file);
-       fputc(latchValue, file);
-       fputc(phase, file);
-       fputc(track, file);
-       fputc((ioHappened ? 1 : 0), file);
-       WriteLong(file, currentPos);
-
-       // Disk #1
-       if (disk[0] != NULL)
-       {
-               WriteLong(file, diskSize[0]);
-               WriteLong(file, diskType[0]);
-               fputc((imageDirty[0] ? 1 : 0), file);
-               fputc((writeProtected[0] ? 1 : 0), file);
-               fwrite(nybblizedImage[0], 1, 232960, file);
-               fwrite(imageName[0], 1, MAX_PATH, file);
-       }
-       else
-               WriteLong(file, 0);
-
-       // Disk #2
-       if (disk[1] != NULL)
-       {
-               WriteLong(file, diskSize[1]);
-               WriteLong(file, diskType[1]);
-               fputc((imageDirty[1] ? 1 : 0), file);
-               fputc((writeProtected[1] ? 1 : 0), file);
-               fwrite(nybblizedImage[1], 1, 232960, file);
-               fwrite(imageName[1], 1, MAX_PATH, file);
-       }
-       else
-               WriteLong(file, 0);
-}
-
-
-void FloppyDrive::LoadState(FILE * file)
-{
-       // Eject images if they're loaded
-       EjectImage(0);
-       EjectImage(1);
-
-       // Read internal state variables
-       motorOn = fgetc(file);
-       activeDrive = fgetc(file);
-       ioMode = fgetc(file);
-       latchValue = fgetc(file);
-       phase = fgetc(file);
-       track = fgetc(file);
-       ioHappened = (fgetc(file) == 1 ? true : false);
-       currentPos = ReadLong(file);
-
-       diskSize[0] = ReadLong(file);
-
-       if (diskSize[0])
-       {
-               disk[0] = new uint8_t[diskSize[0]];
-               diskType[0] = (uint8_t)ReadLong(file);
-               imageDirty[0] = (fgetc(file) == 1 ? true : false);
-               writeProtected[0] = (fgetc(file) == 1 ? true : false);
-               fread(nybblizedImage[0], 1, 232960, file);
-               fread(imageName[0], 1, MAX_PATH, file);
-       }
-
-       diskSize[1] = ReadLong(file);
-
-       if (diskSize[1])
-       {
-               disk[1] = new uint8_t[diskSize[1]];
-               diskType[1] = (uint8_t)ReadLong(file);
-               imageDirty[1] = (fgetc(file) == 1 ? true : false);
-               writeProtected[1] = (fgetc(file) == 1 ? true : false);
-               fread(nybblizedImage[1], 1, 232960, file);
-               fread(imageName[1], 1, MAX_PATH, file);
-       }
-}
-
-
-uint32_t FloppyDrive::ReadLong(FILE * file)
-{
-       uint32_t r = 0;
-
-       for(int i=0; i<4; i++)
-               r = (r << 8) | fgetc(file);
-
-       return r;
-}
-
-
-void FloppyDrive::WriteLong(FILE * file, uint32_t l)
-{
-       for(int i=0; i<4; i++)
-       {
-               fputc((l >> 24) & 0xFF, file);
-               l = l << 8;
-       }
-}
-
-
-// Memory mapped I/O functions
-
-/*
-The DSK format is a byte-for-byte image of a 16-sector Apple II floppy disk: 35
-tracks of 16 sectors of 256 bytes each, making 143,360 bytes in total. The PO
-format is exactly the same size as DSK and is also organized as 35 sequential
-tracks, but the sectors within each track are in a different sequence. The NIB
-format is a nybblized format: a more direct representation of the disk's data
-as encoded by the Apple II floppy drive hardware. NIB contains 35 tracks of
-6656 bytes each, for a total size of 232,960 bytes. Although this format is
-much larger, it is also more versatile and can represent the older 13-sector
-disks, many copy-protected disks, and other unusual encodings.
-*/
-
-void FloppyDrive::ControlStepper(uint8_t addr)
-{
-       // $C0E0 - 7
-/*
-What I can gather here:
-bits 1-2 are the "phase" of the track (which is 1/4 of a full track (?))
-bit 0 is the "do something" bit.
-*/
-       if (addr & 0x01)
-       {
-               uint8_t newPhase = (addr >> 1) & 0x03;
-//WriteLog("*** Stepper change [%u]: track = %u, phase = %u, newPhase = %u\n", addr, track, phase, newPhase);
-
-               if (((phase + 1) & 0x03) == newPhase)
-                       phase += (phase < 79 ? 1 : 0);
-
-               if (((phase - 1) & 0x03) == newPhase)
-                       phase -= (phase > 0 ? 1 : 0);
-
-               if (!(phase & 0x01))
-               {
-                       track = ((phase >> 1) < 35 ? phase >> 1 : 34);
-                       currentPos = 0;
-               }
-//WriteLog("                        track = %u, phase = %u, newPhase = %u\n", track, phase, newPhase);
-SpawnMessage("Stepping to track %u...", track);
-       }
-
-//     return something if read mode...
-}
-
-
-void FloppyDrive::ControlMotor(uint8_t addr)
-{
-       // $C0E8 - 9
-       motorOn = addr;
-}
-
-
-void FloppyDrive::DriveEnable(uint8_t addr)
-{
-       // $C0EA - B
-       activeDrive = addr;
-}
-
-
-uint8_t FloppyDrive::ReadWrite(void)
-{
-SpawnMessage("%u:%sing %s track %u, sector %u...", activeDrive,
-       (ioMode == IO_MODE_READ ? "Read" : "Write"),
-       (ioMode == IO_MODE_READ ? "from" : "to"), track, currentPos / 396);
-       // $C0EC
-       ioHappened = true;
-/*
-I think what happens here is that once a track is read its nybblized form
-is fed through here, one byte at a time--which means for DO disks, we have
-to convert the actual 256 byte sector to a 416 byte nybblized data "sector".
-Which we now do. :-)
-*/
-       if (ioMode == IO_MODE_WRITE && (latchValue & 0x80))
-       {
-               // Does it behave like this?
-#warning "Write protection kludged in--investigate real behavior!"
-               if (writeProtected[activeDrive])
-//doesn't seem to do anything
-                       return 0;//is this more like it?
-
-               nybblizedImage[activeDrive][(track * 6656) + currentPos] = latchValue;
-               imageDirty[activeDrive] = true;
-       }
-
-       uint8_t diskByte = nybblizedImage[activeDrive][(track * 6656) + currentPos];
-       currentPos = (currentPos + 1) % 6656;
-
-//WriteLog("FL: diskByte=%02X, currentPos=%u\n", diskByte, currentPos);
-       return diskByte;
-}
-
-
-uint8_t FloppyDrive::GetLatchValue(void)
-{
-       // $C0ED
-       return latchValue;
-}
-
-
-void FloppyDrive::SetLatchValue(uint8_t value)
-{
-       // $C0ED
-       latchValue = value;
-}
-
-
-void FloppyDrive::SetReadMode(void)
-{
-       // $C0EE
-       ioMode = IO_MODE_READ;
-}
-
-
-void FloppyDrive::SetWriteMode(void)
-{
-       // $C0EF
-       ioMode = IO_MODE_WRITE;
-}
-
-/*
-PRODOS 8 MLI ERROR CODES
-
-$00:    No error
-$01:    Bad system call number
-$04:    Bad system call parameter count
-$25:    Interrupt table full
-$27:    I/O error
-$28:    No device connected
-$2B:    Disk write protected
-$2E:    Disk switched
-$40:    Invalid pathname
-$42:    Maximum number of files open
-$43:    Invalid reference number
-$44:    Directory not found
-$45:    Volume not found
-$46:    File not found
-$47:    Duplicate filename
-$48:    Volume full
-$49:    Volume directory full
-$4A:    Incompatible file format, also a ProDOS directory
-$4B:    Unsupported storage_type
-$4C:    End of file encountered
-$4D:    Position out of range
-$4E:    File access error, also file locked
-$50:    File is open
-$51:    Directory structure damaged
-$52:    Not a ProDOS volume
-$53:    Invalid system call parameter
-$55:    Volume Control Block table full
-$56:    Bad buffer address
-$57:    Duplicate volume
-$5A:    File structure damaged
-*/