diff --git a/apple/diskii.cpp b/apple/diskii.cpp index febc3b1..6874966 100644 --- a/apple/diskii.cpp +++ b/apple/diskii.cpp @@ -47,7 +47,7 @@ bool DiskII::Serialize(int8_t fd) { return false; - // FIXME: all the new variables are missing + // FIXME: all the new variables are missing *** g_filemanager->writeByte(fd, DISKIIMAGIC); @@ -84,7 +84,7 @@ bool DiskII::Serialize(int8_t fd) bool DiskII::Deserialize(int8_t fd) { return false; - // FIXME: all the new variables are missing + // FIXME: all the new variables are missing *** if (g_filemanager->readByte(fd) != DISKIIMAGIC) { return false; @@ -167,11 +167,11 @@ uint8_t DiskII::readSwitches(uint8_t s) case 0x08: // drive off indicatorIsOn[selectedDisk] = 99; - g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: delay a bit? Queue for later drawing? + g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: delay a bit? Queue for later drawing? *** break; case 0x09: // drive on indicatorIsOn[selectedDisk] = 100; - g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true); // FIXME: delay a bit? Queue for later drawing? + g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true); // FIXME: delay a bit? Queue for later drawing? *** // Start the given disk drive spinning lastDiskRead[selectedDisk] = g_cpu->cycles; @@ -186,6 +186,10 @@ uint8_t DiskII::readSwitches(uint8_t s) case 0x0C: // shift one read or write byte readWriteLatch = readOrWriteByte(); + /* + if (readWriteLatch & 0x80) + printf(" => Disk II reads 0x%.2X @ $%.4X\n", sequencer, g_cpu->pc); + */ if (readWriteLatch & 0x80) sequencer = 0; break; @@ -210,9 +214,9 @@ uint8_t DiskII::readSwitches(uint8_t s) } // FIXME: improve the spin-down here. We need a CPU cycle callback - // for some period of time instead of this silly decrement counter. + // for some period of time instead of this silly decrement counter *** if (!indicatorIsOn[selectedDisk]) { - printf("Unexpected read while disk isn't on?\n"); + // printf("Unexpected read while disk isn't on?\n"); indicatorIsOn[selectedDisk] = 100; g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true); // FIXME: queue for later drawing? } @@ -222,7 +226,7 @@ uint8_t DiskII::readSwitches(uint8_t s) g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: queue for later drawing? // Stop the given disk drive spinning - lastDiskRead[selectedDisk] = 0; // FIXME: magic value. We need a tristate for this. + lastDiskRead[selectedDisk] = 0; // FIXME: magic value. We need a tristate for this. *** } } @@ -351,10 +355,8 @@ void DiskII::setPhase(uint8_t phase) if (curHalfTrack[selectedDisk] != prevHalfTrack) { // We're changing track - flush the old track back to disk - printf("track change\n"); curWozTrack[selectedDisk] = disk[selectedDisk]->trackNumberForQuarterTrack(curHalfTrack[selectedDisk]*2); - printf("New half: %d; track: %d\n", curHalfTrack[selectedDisk]*2, curWozTrack[selectedDisk]); } } @@ -400,7 +402,6 @@ void DiskII::insertDisk(int8_t driveNum, const char *filename, bool drawIt) disk[driveNum]->readFile(filename); // FIXME error checking curWozTrack[driveNum] = disk[driveNum]->trackNumberForQuarterTrack(curHalfTrack[driveNum]*2); - printf("Cur track: %d\n", curWozTrack[driveNum]); if (drawIt) g_ui->drawOnOffUIElement(UIeDisk1_state + driveNum, false); @@ -420,8 +421,6 @@ void DiskII::select(int8_t which) if (which != 0 && which != 1) return; - printf("Select disk %d\n", which); - if (which != selectedDisk) { indicatorIsOn[selectedDisk] = 100; // spindown time (fixme) g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: queue for later drawing? @@ -433,14 +432,12 @@ void DiskII::select(int8_t which) // Update the current woz track for the given disk drive curWozTrack[selectedDisk] = disk[selectedDisk]->trackNumberForQuarterTrack(curHalfTrack[selectedDisk]*2); - printf("Cur Woz track is %d\n", curWozTrack[selectedDisk]); - } uint8_t DiskII::readOrWriteByte() { if (!disk[selectedDisk]) { - printf("reading from uninserted disk\n"); + //printf("reading from uninserted disk\n"); return 0xFF; } diff --git a/apple/nibutil.cpp b/apple/nibutil.cpp index 8c51499..e2f1f0d 100644 --- a/apple/nibutil.cpp +++ b/apple/nibutil.cpp @@ -35,22 +35,24 @@ const static uint8_t _trans[64] = {0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa 0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}; -const static uint8_t _detrans[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 }; +// This is the inverted DOS 3.3 RWTS Write Table (high bit +// stripped). Any "bad" value is stored as 0xFF. +const static uint8_t _detrans[0x80] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x04, + 0xFF, 0xFF, 0x08, 0x0C, 0xFF, 0x10, 0x14, 0x18, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1C, 0x20, + 0xFF, 0xFF, 0xFF, 0x24, 0x28, 0x2C, 0x30, 0x34, + 0xFF, 0xFF, 0x38, 0x3C, 0x40, 0x44, 0x48, 0x4C, + 0xFF, 0x50, 0x54, 0x58, 0x5C, 0x60, 0x64, 0x68, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x6C, 0xFF, 0x70, 0x74, 0x78, + 0xFF, 0xFF, 0xFF, 0x7C, 0xFF, 0xFF, 0x80, 0x84, + 0xFF, 0x88, 0x8C, 0x90, 0x94, 0x98, 0x9C, 0xA0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xA4, 0xA8, 0xAC, + 0xFF, 0xB0, 0xB4, 0xB8, 0xBC, 0xC0, 0xC4, 0xC8, + 0xFF, 0xFF, 0xCC, 0xD0, 0xD4, 0xD8, 0xDC, 0xE0, + 0xFF, 0xE4, 0xE8, 0xEC, 0xF0, 0xF4, 0xF8, 0xFC }; // dos 3.3 to physical sector conversion const static uint8_t dephys[16] = { @@ -232,6 +234,8 @@ static bool _decodeData(const uint8_t trackBuffer[343], uint8_t output[256]) for (int i=0; i<342; i++) { uint8_t in = *(trackBuffer++) & 0x7F; // strip high bit workbuf[i] = _detrans[in]; + if (workbuf[i] == 0xFF) // bad data is untranslatable + return false; } // fixme: collapse this in to the previous loop @@ -343,7 +347,7 @@ nibErr denibblizeTrack(const uint8_t input[NIBTRACKSIZE], uint8_t rawTrackBuffer nibData[j] = input[(i+j)%NIBTRACKSIZE]; } if (!_decodeData(nibData, output)) { - continue; + return errorBadData; } i += 343; diff --git a/apple/woz.cpp b/apple/woz.cpp index 901c0cc..2f7760d 100644 --- a/apple/woz.cpp +++ b/apple/woz.cpp @@ -3,6 +3,7 @@ #include "crc32.h" #include "nibutil.h" #include "version.h" +#include "globals.h" // Block number we start packing data bits after (Woz 2.0 images) #define STARTBLOCK 3 @@ -13,16 +14,16 @@ return false; \ if (!write32(f, 0)) \ return false; \ - curpos = ftello(f); \ + curpos = g_filemanager->getSeekPosition(f); \ } #define END_SECTION(f) { \ - long endpos = ftello(f); \ - fseeko(f, curpos-4, SEEK_SET); \ + uint32_t endpos = g_filemanager->getSeekPosition(f); \ + g_filemanager->setSeekPosition(f, curpos-4); \ uint32_t chunksize = endpos - curpos; \ if (!write32(f, chunksize)) \ return false; \ - fseeko(f, 0, SEEK_END); \ + g_filemanager->seekToEnd(f); \ } Woz::Woz() @@ -95,49 +96,47 @@ uint8_t Woz::nextDiskByte(uint8_t track) return d; } -static bool write8(FILE *f, uint8_t v) +static bool write8(uint8_t fh, uint8_t v) { - if (fwrite(&v, 1, 1, f) != 1) + if (!g_filemanager->writeByte(fh, v)) return false; return true; } -static bool write16(FILE *f, uint16_t v) +static bool write16(uint8_t fh, uint16_t v) { - if (!write8(f, v & 0xFF)) + if (!write8(fh, v & 0xFF)) return false; v >>= 8; - if (!write8(f, v & 0xFF)) + if (!write8(fh, v & 0xFF)) return false; return true; } -static bool write32(FILE *f, uint32_t v) +static bool write32(uint8_t fh, uint32_t v) { for (int i=0; i<4; i++) { - if (!write8(f, v&0xFF)) + if (!write8(fh, v&0xFF)) return false; v >>= 8; } return true; } -static bool read8(FILE *f, uint8_t *toWhere) +static bool read8(uint8_t fd, uint8_t *toWhere) { - uint8_t r; - if (fread(&r, 1, 1, f) != 1) - return false; - *toWhere = r; + // FIXME: no error checking + *toWhere = g_filemanager->readByte(fd); return true; } -static bool read16(FILE *f, uint16_t *toWhere) +static bool read16(uint8_t fh, uint16_t *toWhere) { uint16_t ret = 0; for (int i=0; i<2; i++) { uint8_t r; - if (!read8(f, &r)) { + if (!read8(fh, &r)) { return false; } ret >>= 8; @@ -149,12 +148,12 @@ static bool read16(FILE *f, uint16_t *toWhere) return true; } -static bool read32(FILE *f, uint32_t *toWhere) +static bool read32(uint8_t fh, uint32_t *toWhere) { uint32_t ret = 0; for (int i=0; i<4; i++) { uint8_t r; - if (!read8(f, &r)) { + if (!read8(fh, &r)) { return false; } ret >>= 8; @@ -168,7 +167,7 @@ static bool read32(FILE *f, uint32_t *toWhere) bool Woz::writeFile(uint8_t version, const char *filename) { - FILE *f = NULL; + int8_t fh = -1; // filehandle (-1 == closed) bool retval = false; uint32_t tmp32; // scratch 32-bit value off_t crcPos, endPos; @@ -178,13 +177,17 @@ bool Woz::writeFile(uint8_t version, const char *filename) if (version > 2 || !version) { +#ifndef TEENSYDUINO fprintf(stderr, "ERROR: version must be 1 or 2\n"); +#endif goto done; } - f = fopen(filename, "w+"); - if (!f) { - perror("ERROR: Unable to open output file"); + fh = g_filemanager->openFile(filename); + if (fh==-1) { +#ifndef TEENSYDUINO + printf("ERROR: Unable to open output file\n"); +#endif goto done; } @@ -194,83 +197,102 @@ bool Woz::writeFile(uint8_t version, const char *filename) } else { tmp32 = 0x325A4F57; } - if (!write32(f, tmp32)) { + if (!write32(fh, tmp32)) { +#ifndef TEENSYDUINO fprintf(stderr, "ERROR: failed to write\n"); +#endif goto done; } tmp32 = 0x0A0D0AFF; - if (!write32(f, tmp32)) { + if (!write32(fh, tmp32)) { +#ifndef TEENSYDUINO fprintf(stderr, "ERROR: failed to write\n"); +#endif goto done; } // We'll come back and write the checksum later - crcPos = ftello(f); + crcPos = g_filemanager->getSeekPosition(fh); tmp32 = 0; - if (!write32(f, tmp32)) { + if (!write32(fh, tmp32)) { +#ifndef TEENSYDUINO fprintf(stderr, "ERROR: failed to write\n"); +#endif goto done; } - PREP_SECTION(f, 0x4F464E49); // 'INFO' - if (!writeInfoChunk(version, f)) { + PREP_SECTION(fh, 0x4F464E49); // 'INFO' + if (!writeInfoChunk(version, fh)) { +#ifndef TEENSYDUINO fprintf(stderr, "ERROR: failed to write INFO chunk\n"); +#endif goto done; } - END_SECTION(f); + END_SECTION(fh); - PREP_SECTION(f, 0x50414D54); // 'TMAP' - if (!writeTMAPChunk(version, f)) { + PREP_SECTION(fh, 0x50414D54); // 'TMAP' + if (!writeTMAPChunk(version, fh)) { +#ifndef TEENSYDUINO fprintf(stderr, "ERROR: failed to write TMAP chunk\n"); +#endif goto done; } - END_SECTION(f); + END_SECTION(fh); - PREP_SECTION(f, 0x534B5254); // 'TRKS' - if (!writeTRKSChunk(version, f)) { + PREP_SECTION(fh, 0x534B5254); // 'TRKS' + if (!writeTRKSChunk(version, fh)) { fprintf(stderr, "ERROR: failed to write TRKS chunk\n"); goto done; } - END_SECTION(f); + END_SECTION(fh); // Write the metadata if we have any if (metaData) { - PREP_SECTION(f, 0x4154454D); // 'META' - if (fwrite(metaData, 1, strlen(metaData), f) != strlen(metaData)) { - fprintf(stderr, "ERROR: failed to write META chunk\n"); - goto done; + PREP_SECTION(fh, 0x4154454D); // 'META' + for (int i=0; igetSeekPosition(fh); crcDataSize = endPos-crcPos-4; crcData = (uint8_t *)malloc(crcDataSize); if (!crcData) { +#ifndef TEENSYDUINO fprintf(stderr, "ERROR: failed to malloc crc data chunk\n"); +#endif goto done; } // Read the data in for checksumming - if (fseeko(f, crcPos+4, SEEK_SET)) { - fprintf(stderr, "ERROR: failed to fseek to crcPos+4 (0x%llX)\n", crcPos+4); - goto done; - } + // FIXME: no error checking on seek + g_filemanager->setSeekPosition(fh, crcPos+4); - tmp32 = fread(crcData, 1, crcDataSize, f); - if (tmp32 != crcDataSize) { - fprintf(stderr, "ERROR: failed to read in data for checksum [read %d, wanted %d]\n", tmp32, crcDataSize); - goto done; + for (int i=0; isetSeekPosition(fh, crcPos); + if (!write32(fh, tmp32)) { +#ifndef TEENSYDUINO fprintf(stderr, "ERROR: failed to write CRC\n"); +#endif goto done; } @@ -279,8 +301,9 @@ bool Woz::writeFile(uint8_t version, const char *filename) done: if (crcData) free(crcData); - if (f) - fclose(f); + if (fh != -1) { + g_filemanager->closeFile(fh); + } return retval; } @@ -317,9 +340,11 @@ bool Woz::readDskFile(const char *filename, uint8_t subtype) { bool retval = false; - FILE *f = fopen(filename, "r"); - if (!f) { + int8_t fh = g_filemanager->openFile(filename); + if (fh == -1) { +#ifndef TEENSYDUINO perror("Unable to open input file"); +#endif goto done; } @@ -328,15 +353,16 @@ bool Woz::readDskFile(const char *filename, uint8_t subtype) // Now read in the 35 tracks of data from the DSK file and convert them to NIB uint8_t sectorData[256*16]; for (int track=0; track<35; track++) { - uint32_t bytesRead = fread(sectorData, 1, 256*16, f); - if (bytesRead != 256*16) { - fprintf(stderr, "Failed to read DSK data; got %d bytes, wanted %d\n", bytesRead, 256); - goto done; + for (int i=0; i<256*16; i++) { + // FIXME: no error checking + sectorData[i] = g_filemanager->readByte(fh); } tracks[track].trackData = (uint8_t *)calloc(NIBTRACKSIZE, 1); if (!tracks[track].trackData) { +#ifndef TEENSYDUINO fprintf(stderr, "Failed to malloc track data\n"); +#endif goto done; } tracks[track].startingBlock = STARTBLOCK + 13*track; @@ -348,16 +374,18 @@ bool Woz::readDskFile(const char *filename, uint8_t subtype) retval = true; done: - if (f) - fclose(f); + if (fh != -1) + g_filemanager->closeFile(fh); return retval; } bool Woz::readNibFile(const char *filename) { - FILE *f = fopen(filename, "r"); - if (!f) { + int8_t fh = g_filemanager->openFile(filename); + if (fh == -1) { +#ifndef TEENSYDUINO perror("Unable to open input file"); +#endif return false; } @@ -365,16 +393,18 @@ bool Woz::readNibFile(const char *filename) // Now read in the 35 tracks of data from the nib file nibSector nibData[16]; + uint8_t *nibDataPtr = (uint8_t *)nibData; for (int track=0; track<35; track++) { - uint32_t bytesRead = fread(nibData, 1, NIBTRACKSIZE, f); - if (bytesRead != NIBTRACKSIZE) { - printf("Failed to read NIB data; got %d bytes, wanted %d\n", bytesRead, NIBTRACKSIZE); - return false; + for (int i=0; ireadByte(fh); } tracks[track].trackData = (uint8_t *)calloc(NIBTRACKSIZE, 1); if (!tracks[track].trackData) { +#ifndef TEENSYDUINO printf("Failed to malloc track data\n"); +#endif return false; } @@ -383,43 +413,53 @@ bool Woz::readNibFile(const char *filename) tracks[track].blockCount = 13; tracks[track].bitCount = NIBTRACKSIZE*8; } - fclose(f); + g_filemanager->closeFile(fh); return true; } bool Woz::readWozFile(const char *filename) { - FILE *f = fopen(filename, "r"); - if (!f) { + int8_t fh = g_filemanager->openFile(filename); + if (fh == -1) { +#ifndef TEENSYDUINO perror("Unable to open input file"); +#endif return false; } // Header uint32_t h; - read32(f, &h); + read32(fh, &h); if (h == 0x325A4F57 || h == 0x315A4F57) { +#ifndef TEENSYDUINO printf("WOZ%c disk image\n", (h & 0xFF000000)>>24); +#endif } else { +#ifndef TEENSYDUINO printf("Unknown disk image type; can't continue\n"); - fclose(f); +#endif + g_filemanager->closeFile(fh); return false; } uint32_t tmp; - if (!read32(f, &tmp)) { + if (!read32(fh, &tmp)) { +#ifndef TEENSYDUINO printf("Read failure\n"); - fclose(f); +#endif + g_filemanager->closeFile(fh); return false; } if (tmp != 0x0A0D0AFF) { +#ifndef TEENSYDUINO printf("WOZ header failure; exiting\n"); - fclose(f); +#endif + g_filemanager->closeFile(fh); return false; } uint32_t crc32; - read32(f, &crc32); + read32(fh, &crc32); // printf("Disk crc32 should be 0x%X\n", crc32); // FIXME: check CRC. Remember that 0x00 means "don't check CRC" @@ -431,45 +471,47 @@ bool Woz::readWozFile(const char *filename) #define cTRKS 4 while (1) { - if (fseeko(f, fpos, SEEK_SET)) { - break; - } + g_filemanager->setSeekPosition(fh, fpos); // FIXME: no error checking uint32_t chunkType; - if (!read32(f, &chunkType)) { + if (!read32(fh, &chunkType)) { break; } uint32_t chunkDataSize; - read32(f, &chunkDataSize); + read32(fh, &chunkDataSize); bool isOk; switch (chunkType) { case 0x4F464E49: // 'INFO' - isOk = parseInfoChunk(f, chunkDataSize); + isOk = parseInfoChunk(fh, chunkDataSize); haveData |= cINFO; break; case 0x50414D54: // 'TMAP' - isOk = parseTMAPChunk(f, chunkDataSize); + isOk = parseTMAPChunk(fh, chunkDataSize); haveData |= cTMAP; break; case 0x534B5254: // 'TRKS' - isOk = parseTRKSChunk(f, chunkDataSize); + isOk = parseTRKSChunk(fh, chunkDataSize); haveData |= cTRKS; break; case 0x4154454D: // 'META' - isOk = parseMetaChunk(f, chunkDataSize); + isOk = parseMetaChunk(fh, chunkDataSize); break; default: +#ifndef TEENSYDUINO printf("Unknown chunk type 0x%X\n", chunkType); - fclose(f); +#endif + g_filemanager->closeFile(fh); return false; break; } if (!isOk) { +#ifndef TEENSYDUINO printf("Chunk parsing [0x%X] failed; exiting\n", chunkType); - fclose(f); +#endif + g_filemanager->closeFile(fh); return false; } @@ -477,20 +519,26 @@ bool Woz::readWozFile(const char *filename) } if (haveData != 0x07) { +#ifndef TEENSYDUINO printf("ERROR: missing one or more critical sections\n"); +#endif return false; } for (int i=0; i<35; i++) { - if (!readQuarterTrackData(f, i*4)) { + if (!readQuarterTrackData(fh, i*4)) { +#ifndef TEENSYDUINO printf("Failed to read QTD for track %d\n", i); - fclose(f); +#endif + g_filemanager->closeFile(fh); return false; } } - fclose(f); + g_filemanager->closeFile(fh); +#ifndef TEENSYDUINO printf("File read successful\n"); +#endif return true; } @@ -500,7 +548,9 @@ bool Woz::readFile(const char *filename, uint8_t forceType) // Try to determine type from the file extension const char *p = strrchr(filename, '.'); if (!p) { +#ifndef TEENSYDUINO printf("Unable to determine file type of '%s'\n", filename); +#endif return false; } if (strcasecmp(p, ".woz") == 0) { @@ -513,37 +563,47 @@ bool Woz::readFile(const char *filename, uint8_t forceType) } else if (strcasecmp(p, ".nib") == 0) { forceType = T_NIB; } else { +#ifndef TEENSYDUINO printf("Unable to determine file type of '%s'\n", filename); +#endif return false; } } switch (forceType) { case T_WOZ: +#ifndef TEENSYDUINO printf("reading woz file %s\n", filename); +#endif return readWozFile(filename); case T_DSK: case T_PO: +#ifndef TEENSYDUINO printf("reading DSK file %s\n", filename); +#endif return readDskFile(filename, forceType); case T_NIB: +#ifndef TEENSYDUINO printf("reading NIB file %s\n", filename); +#endif return readNibFile(filename); default: +#ifndef TEENSYDUINO printf("Unknown disk type; unable to read\n"); +#endif return false; } } -bool Woz::parseTRKSChunk(FILE *f, uint32_t chunkSize) +bool Woz::parseTRKSChunk(int8_t fh, uint32_t chunkSize) { if (di.version == 2) { for (int i=0; i<160; i++) { - if (!read16(f, &tracks[i].startingBlock)) + if (!read16(fh, &tracks[i].startingBlock)) return false; - if (!read16(f, &tracks[i].blockCount)) + if (!read16(fh, &tracks[i].blockCount)) return false; - if (!read32(f, &tracks[i].bitCount)) + if (!read32(fh, &tracks[i].bitCount)) return false; tracks[i].startingByte = 0; // v1-specific } @@ -557,9 +617,9 @@ bool Woz::parseTRKSChunk(FILE *f, uint32_t chunkSize) tracks[trackNumber].startingByte = trackNumber * 6656 + 256; tracks[trackNumber].startingBlock = 0; // v2-specific tracks[trackNumber].blockCount = 13; - fseeko(f, (trackNumber * 6656 + 256) + 6648, SEEK_SET); + g_filemanager->setSeekPosition(fh, (trackNumber * 6656 + 256) + 6648); // FIXME: no error checking uint16_t numBits; - if (!read16(f, &numBits)) { + if (!read16(fh, &numBits)) { return false; } tracks[trackNumber].bitCount = numBits; @@ -570,15 +630,17 @@ bool Woz::parseTRKSChunk(FILE *f, uint32_t chunkSize) return true; } -bool Woz::parseTMAPChunk(FILE *f, uint32_t chunkSize) +bool Woz::parseTMAPChunk(int8_t fh, uint32_t chunkSize) { if (chunkSize != 0xa0) { +#ifndef TEENSYDUINO printf("TMAP chunk is the wrong size; aborting\n"); +#endif return false; } for (int i=0; i<40*4; i++) { - if (!read8(f, (uint8_t *)&quarterTrackMap[i])) + if (!read8(fh, (uint8_t *)&quarterTrackMap[i])) return false; chunkSize--; } @@ -587,54 +649,60 @@ bool Woz::parseTMAPChunk(FILE *f, uint32_t chunkSize) } // return true if successful -bool Woz::parseInfoChunk(FILE *f, uint32_t chunkSize) +bool Woz::parseInfoChunk(int8_t fh, uint32_t chunkSize) { if (chunkSize != 60) { +#ifndef TEENSYDUINO printf("INFO chunk size is not 60; aborting\n"); +#endif return false; } - if (!read8(f, &di.version)) + if (!read8(fh, &di.version)) return false; if (di.version > 2) { +#ifndef TEENSYDUINO printf("Incorrect version header; aborting\n"); +#endif return false; } - if (!read8(f, &di.diskType)) + if (!read8(fh, &di.diskType)) return false; if (di.diskType != 1) { +#ifndef TEENSYDUINO printf("Not a 5.25\" disk image; aborting\n"); +#endif return false; } - if (!read8(f, &di.writeProtected)) + if (!read8(fh, &di.writeProtected)) return false; - if (!read8(f, &di.synchronized)) + if (!read8(fh, &di.synchronized)) return false; - if (!read8(f, &di.cleaned)) + if (!read8(fh, &di.cleaned)) return false; di.creator[32] = 0; for (int i=0; i<32; i++) { - if (!read8(f, (uint8_t *)&di.creator[i])) + if (!read8(fh, (uint8_t *)&di.creator[i])) return false; } if (di.version >= 2) { - if (!read8(f, &di.diskSides)) + if (!read8(fh, &di.diskSides)) return false; - if (!read8(f, &di.bootSectorFormat)) + if (!read8(fh, &di.bootSectorFormat)) return false; - if (!read8(f, &di.optimalBitTiming)) + if (!read8(fh, &di.optimalBitTiming)) return false; - if (!read16(f, &di.compatHardware)) + if (!read16(fh, &di.compatHardware)) return false; - if (!read16(f, &di.requiredRam)) + if (!read16(fh, &di.requiredRam)) return false; - if (!read16(f, &di.largestTrack)) + if (!read16(fh, &di.largestTrack)) return false; } else { di.diskSides = 0; @@ -649,21 +717,22 @@ bool Woz::parseInfoChunk(FILE *f, uint32_t chunkSize) return true; } -bool Woz::parseMetaChunk(FILE *f, uint32_t chunkSize) +bool Woz::parseMetaChunk(int8_t fh, uint32_t chunkSize) { metaData = (char *)calloc(chunkSize+1, 1); if (!metaData) return false; - if (fread(metaData, 1, chunkSize, f) != chunkSize) - return false; + for (int i=0; ireadByte(fh); // FIXME: no error checking + } metaData[chunkSize] = 0; return true; } -bool Woz::readQuarterTrackData(FILE *f, uint8_t quartertrack) +bool Woz::readQuarterTrackData(int8_t fh, uint8_t quartertrack) { uint8_t targetImageTrack = quarterTrackMap[quartertrack]; if (targetImageTrack == 0xFF) { @@ -681,25 +750,20 @@ bool Woz::readQuarterTrackData(FILE *f, uint8_t quartertrack) if (di.version == 1) count = (tracks[targetImageTrack].bitCount / 8) + ((tracks[targetImageTrack].bitCount % 8) ? 1 : 0); tracks[targetImageTrack].trackData = (uint8_t *)calloc(count, 1); if (!tracks[targetImageTrack].trackData) { +#ifndef TEENSYDUINO perror("Failed to alloc buf to read track magnetic data"); +#endif return false; } if (di.version == 1) { - if (fseeko(f, tracks[targetImageTrack].startingByte, SEEK_SET)) { - perror("Failed to seek to start of block"); - return false; - } + g_filemanager->setSeekPosition(fh, tracks[targetImageTrack].startingByte); // FIXME: no error checking } else { - if (fseeko(f, bitsStartBlock*512, SEEK_SET)) { - perror("Failed to seek to start of block"); - return false; - } + g_filemanager->setSeekPosition(fh, bitsStartBlock*512); // FIXME: no error checking } - uint32_t didRead = fread(tracks[targetImageTrack].trackData, 1, count, f); - if (didRead != count) { - printf("Failed to read all track data for track [read %d, wanted %d]\n", didRead, count); - return false; + for (int i=0; ireadByte(fh); } return true; @@ -781,17 +845,17 @@ bool Woz::readSectorData(uint8_t track, uint8_t sector, nibSector *sectorData) return false; } -bool Woz::writeInfoChunk(uint8_t version, FILE *f) +bool Woz::writeInfoChunk(uint8_t version, int8_t fh) { - if (!write8(f, version) || - !write8(f, di.diskType) || - !write8(f, di.writeProtected) || - !write8(f, di.synchronized) || - !write8(f, di.cleaned)) + if (!write8(fh, version) || + !write8(fh, di.diskType) || + !write8(fh, di.writeProtected) || + !write8(fh, di.synchronized) || + !write8(fh, di.cleaned)) return false; for (int i=0; i<32; i++) { - if (!write8(f, di.creator[i])) + if (!write8(fh, di.creator[i])) return false; } @@ -800,37 +864,39 @@ bool Woz::writeInfoChunk(uint8_t version, FILE *f) if (di.diskSides == 0) di.diskSides = 1; - if ( !write8(f, di.diskSides) || - !write8(f, di.bootSectorFormat) || - !write8(f, di.optimalBitTiming) || - !write16(f, di.compatHardware) || - !write16(f, di.requiredRam) || - !write16(f, di.largestTrack)) + if ( !write8(fh, di.diskSides) || + !write8(fh, di.bootSectorFormat) || + !write8(fh, di.optimalBitTiming) || + !write16(fh, di.compatHardware) || + !write16(fh, di.requiredRam) || + !write16(fh, di.largestTrack)) return false; } // Padding for (int i=0; i<((version==1)?23:14); i++) { - if (!write8(f, 0)) + if (!write8(fh, 0)) return false; } return true; } -bool Woz::writeTMAPChunk(uint8_t version, FILE *f) +bool Woz::writeTMAPChunk(uint8_t version, int8_t fh) { for (int i=0; i<40*4; i++) { - if (!write8(f, quarterTrackMap[i])) + if (!write8(fh, quarterTrackMap[i])) return false; } return true; } -bool Woz::writeTRKSChunk(uint8_t version, FILE *f) +bool Woz::writeTRKSChunk(uint8_t version, int8_t fh) { if (version == 1) { +#ifndef TEENSYDUINO printf("V1 write is not implemented\n"); +#endif return false; } @@ -851,11 +917,11 @@ bool Woz::writeTRKSChunk(uint8_t version, FILE *f) tracks[i].bitCount = 0; } - if (!write16(f, tracks[i].startingBlock)) + if (!write16(fh, tracks[i].startingBlock)) return false; - if (!write16(f, tracks[i].blockCount)) + if (!write16(fh, tracks[i].blockCount)) return false; - if (!write32(f, tracks[i].bitCount)) + if (!write32(fh, tracks[i].bitCount)) return false; } @@ -863,13 +929,16 @@ bool Woz::writeTRKSChunk(uint8_t version, FILE *f) for (int i=0; i<160; i++) { if (tracks[i].startingBlock && tracks[i].blockCount) { - fseeko(f, tracks[i].startingBlock * 512, SEEK_SET); + g_filemanager->setSeekPosition(fh, tracks[i].startingBlock*512); // FIXME: no error checking uint32_t writeSize = (tracks[i].bitCount / 8) + ((tracks[i].bitCount % 8) ? 1 : 0); - if (fwrite(tracks[i].trackData, 1, writeSize, f) != writeSize) - return false; + for (int j=0; jwriteByte(fh, tracks[i].trackData[j])) { + return false; + } + } uint8_t c = 0; while (writeSize < tracks[i].blockCount * 512) { - if (fwrite(&c, 1, 1, f) != 1) + if (!write8(fh, c)) return false; writeSize++; } @@ -902,6 +971,7 @@ bool Woz::decodeWozTrackToDsk(uint8_t track, uint8_t subtype, uint8_t sectorData return true; } +#ifndef TEENSYDUINO void Woz::dumpInfo() { printf("WOZ image version %d\n", di.version); @@ -1074,6 +1144,7 @@ void Woz::dumpInfo() } } } +#endif bool Woz::isSynchronized() { diff --git a/apple/woz.h b/apple/woz.h index 9520fdd..e457186 100644 --- a/apple/woz.h +++ b/apple/woz.h @@ -46,7 +46,9 @@ class Woz { bool decodeWozTrackToNib(uint8_t track, nibSector sectorData[16]); bool decodeWozTrackToDsk(uint8_t track, uint8_t subtype, uint8_t sectorData[256*16]); +#ifndef TEENSYDUINO void dumpInfo(); +#endif bool isSynchronized(); @@ -59,16 +61,16 @@ class Woz { uint8_t fakeBit(); - bool parseTRKSChunk(FILE *f, uint32_t chunkSize); - bool parseTMAPChunk(FILE *f, uint32_t chunkSize); - bool parseInfoChunk(FILE *f, uint32_t chunkSize); - bool parseMetaChunk(FILE *f, uint32_t chunkSize); + bool parseTRKSChunk(int8_t fh, uint32_t chunkSize); + bool parseTMAPChunk(int8_t fh, uint32_t chunkSize); + bool parseInfoChunk(int8_t fh, uint32_t chunkSize); + bool parseMetaChunk(int8_t fh, uint32_t chunkSize); - bool writeInfoChunk(uint8_t version, FILE *f); - bool writeTMAPChunk(uint8_t version, FILE *f); - bool writeTRKSChunk(uint8_t version, FILE *f); + bool writeInfoChunk(uint8_t version, int8_t fh); + bool writeTMAPChunk(uint8_t version, int8_t fh); + bool writeTRKSChunk(uint8_t version, int8_t fh); - bool readQuarterTrackData(FILE *f, uint8_t quartertrack); + bool readQuarterTrackData(int8_t fh, uint8_t quartertrack); bool readSectorData(uint8_t track, uint8_t sector, nibSector *sectorData); void _initInfo(); diff --git a/cpu.cpp b/cpu.cpp index d4b555a..e0257b6 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -9,6 +9,13 @@ #include "globals.h" +// define DEBUGSTEPS to show disassembly of each instruction as it's processed +//#define DEBUGSTEPS +#ifdef DEBUGSTEPS +#include "disassembler.h" +extern Disassembler dis; +#endif + // To see calls to unimplemented opcodes, define this: //#define VERBOSE_CPU_ERRORS @@ -486,6 +493,36 @@ uint8_t Cpu::step() irqPending = false; irq(); } + +#ifdef DEBUGSTEPS + static uint8_t cmdbuf[10]; + static char buf[50]; + + uint16_t loc=g_cpu->pc; + for (int idx=0; idxgetMMU()->read(loc+idx); + } + dis.instructionToMnemonic(loc, cmdbuf, buf, sizeof(buf)); + while (strlen(buf) < 25) { + strcat(buf, " "); + } + printf("%s ;", buf); + + uint8_t p = g_cpu->flags; + printf("BS/BT: %02x/%02x A: %02x X: %02x Y: %02x SP: %02x Flags: %c%cx%c%c%c%c%c\n", + g_vm->getMMU()->read(0x3D), + g_vm->getMMU()->read(0x41), + g_cpu->a, g_cpu->x, g_cpu->y, g_cpu->sp, + p & (1<<7) ? 'N':' ', + p & (1<<6) ? 'V':' ', + p & (1<<4) ? 'B':' ', + p & (1<<3) ? 'D':' ', + p & (1<<2) ? 'I':' ', + p & (1<<1) ? 'Z':' ', + p & (1<<0) ? 'C':' ' + ); + +#endif uint8_t m = readmem(pc++); diff --git a/filemanager.h b/filemanager.h index 162f32b..5bf9098 100644 --- a/filemanager.h +++ b/filemanager.h @@ -112,6 +112,16 @@ class FileManager { virtual void getRootPath(char *toWhere, int8_t maxLen) = 0; + virtual uint32_t getSeekPosition(int8_t fd) { + return fileSeekPositions[fd]; + }; + + virtual void setSeekPosition(int8_t fd, uint32_t pos) { + fileSeekPositions[fd] = pos; + }; + + virtual void seekToEnd(int8_t fd) = 0; + protected: unsigned long fileSeekPositions[MAXFILES]; char cachedNames[MAXFILES][MAXPATH]; diff --git a/nix/nix-filemanager.cpp b/nix/nix-filemanager.cpp index 7bcd6dd..3118223 100644 --- a/nix/nix-filemanager.cpp +++ b/nix/nix-filemanager.cpp @@ -384,3 +384,14 @@ void NixFileManager::getRootPath(char *toWhere, int8_t maxLen) strcpy(toWhere, ROOTDIR); // strncpy(toWhere, ROOTDIR, maxLen); } + +void NixFileManager::seekToEnd(int8_t fd) +{ + // This could just be a stat call... + FILE *f = fopen(cachedNames[fd], "r"); + if (f) { + fseeko(f, 0, SEEK_END); + fileSeekPositions[fd] = ftello(f); + fclose(f); + } +} diff --git a/nix/nix-filemanager.h b/nix/nix-filemanager.h index c2e7aa4..c2c897f 100644 --- a/nix/nix-filemanager.h +++ b/nix/nix-filemanager.h @@ -29,6 +29,8 @@ class NixFileManager : public FileManager { void getRootPath(char *toWhere, int8_t maxLen); + virtual void seekToEnd(int8_t fd); + private: int8_t numCached;