robmcmullen-apple2/src/floppy.cpp

753 lines
20 KiB
C++

//
// 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 "applevideo.h" // For message spawning... Though there's probably a better approach than this!
//using namespace std;
// 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)
{
disk[0] = disk[1] = NULL;
diskSize[0] = diskSize[1] = 0;
diskType[0] = diskType[1] = DT_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] = DT_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::GetImageName(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*/)
{
// Probably want to save a dirty image... ;-)
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] = DT_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::DriveIsEmpty(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::DiskIsWriteProtected(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;
}
// 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
/*
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])
{
nybblizedImage[activeDrive][(track * 6656) + currentPos] = latchValue;
imageDirty[activeDrive] = true;
}
else
//doesn't seem to do anything
return 0;//is this more like it?
}
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
*/