+++ /dev/null
-//
-// 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
-*/