woz uses built-in file management system

This commit is contained in:
Jorj Bauer 2019-02-20 11:51:55 -05:00
parent 03b0a141bc
commit 687a096702
8 changed files with 327 additions and 193 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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; i<strlen(metaData); i++) {
if (!write8(fh, metaData[i])) {
#ifndef TEENSYDUINO
fprintf(stderr, "ERROR: failed to write META chunk\n");
#endif
goto done;
}
}
END_SECTION(f);
END_SECTION(fh);
}
// FIXME: missing the WRIT chunk, if it exists
// Fix up the checksum
endPos = ftello(f);
endPos = g_filemanager->getSeekPosition(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; i<crcDataSize; i++) {
if (!read8(fh, &crcData[i])) {
#ifndef TEENSYDUINO
fprintf(stderr, "ERROR: failed to read in data for checksum [read %d, wanted %d]\n", tmp32, crcDataSize);
#endif
goto done;
}
}
tmp32 = compute_crc_32(crcData, crcDataSize);
// Write it back out
fseeko(f, crcPos, SEEK_SET);
if (!write32(f, tmp32)) {
g_filemanager->setSeekPosition(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; i<NIBTRACKSIZE; i++) {
// FIXME: no error checking
nibDataPtr[i] = g_filemanager->readByte(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; i<chunkSize; i++) {
metaData[i] = g_filemanager->readByte(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; i<count; i++) {
// FIXME: no error checking
tracks[targetImageTrack].trackData[i] = g_filemanager->readByte(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; j<writeSize; j++) {
if (!g_filemanager->writeByte(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()
{

View File

@ -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();

37
cpu.cpp
View File

@ -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; idx<sizeof(cmdbuf); idx++) {
cmdbuf[idx] = g_vm->getMMU()->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++);

View File

@ -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];

View File

@ -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);
}
}

View File

@ -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;