fixes for disk writing and rotational speed

This commit is contained in:
Jorj Bauer 2020-06-30 22:44:50 -04:00
parent 99c5e37159
commit 998c7cebc8
5 changed files with 300 additions and 160 deletions

View File

@ -470,8 +470,50 @@ bool DiskII::isWriteProtected()
return (writeProt ? 0xFF : 0x00); return (writeProt ? 0xFF : 0x00);
} }
int64_t DiskII::calcExpectedBits()
{
// If the disk isn't spinning, then it can't be expected to deliver data
if (!diskIsSpinningUntil[selectedDisk])
return 0;
// Handle potential messy counter rollover
if (driveSpinupCycles[selectedDisk] > g_cpu->cycles) {
driveSpinupCycles[selectedDisk] = g_cpu->cycles-1;
if (driveSpinupCycles[selectedDisk] == 0) // avoid sitting on 0
driveSpinupCycles[selectedDisk]++;
}
uint32_t cyclesPassed = g_cpu->cycles - driveSpinupCycles[selectedDisk];
// This constant defines how fast the disk drive "spins".
// 4.0 is good for DOS 3.3 writes, and reads as 205ms in
// Copy 2+'s drive speed verifier.
// 3.99: 204.5ms
// 3.90: 199.9ms
// 3.91: 200.5ms
// 3.51: 176ms, and is too fast for DOS to write properly.
uint64_t expectedDiskBits = (float)cyclesPassed / 3.90;
return expectedDiskBits - deliveredDiskBits[selectedDisk];
}
void DiskII::setWriteMode(bool enable) void DiskII::setWriteMode(bool enable)
{ {
if (enable) {
// At this point we need to update the track pointer so we know
// where we're going to start writing bits.
int64_t db = calcExpectedBits();
if (db > 0) {
// make sure the disk is at the right point for our program counter's time
// before we start writing data.
deliveredDiskBits[selectedDisk] += db;
while (db) {
sequencer <<= 1;
sequencer |= disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]);
db--;
}
}
}
writeMode = enable; writeMode = enable;
} }
@ -574,85 +616,86 @@ uint8_t DiskII::readOrWriteByte()
return 0xFF; return 0xFF;
} }
uint32_t curCycles = g_cpu->cycles; int32_t bitsToDeliver;
// FIXME: for writes, we need to check s/t like ... if (diskIsSpinningUntil[selectedDisk] >= curCycles) { return } ... if (diskIsSpinningUntil[selectedDisk] < g_cpu->cycles) {
// Uum, disk isn't spinning?
if (writeMode && !writeProt) {
// It's a write request. Inject 'readWriteLatch'.
disk[selectedDisk]->writeNextWozByte(curWozTrack[selectedDisk], readWriteLatch);
goto done; goto done;
} }
if (diskIsSpinningUntil[selectedDisk] >= curCycles) { bitsToDeliver = calcExpectedBits();
// Figure out how many cycles we missed since the last disk read, if (writeMode && !writeProt) {
// and pop the right number of bits off the woz track. // It's a write request.
// Handle rollover, which is a mess. // Write requests from DOS 3.3 start with 40 self-sync bytes
if (driveSpinupCycles[selectedDisk] > g_cpu->cycles) { // (cf. Beneath Apple DOS, p.3-8 and 3-9). These 0XFF bytes are
// printf("Cycle rollover\n"); // written in a 40-cycle loop, where a bit is written every 4
driveSpinupCycles[selectedDisk] = g_cpu->cycles-1; // FIXME: is the -1 correct? What if we were @ 0? // cycles; it intentionally lets 2 0-bits slip in there to
#ifndef TEENSYDUINO // provide the self-sync pattern.
exit(2); // for debugging, FIXME *** //
#endif // So the timing here is important. Figure out how many bits
// should have been laid down to the track, and those are 0s.
int64_t expectedBits = calcExpectedBits();
while (expectedBits > 0) {
disk[selectedDisk]->writeNextWozBit(curWozTrack[selectedDisk], 0);
expectedBits--;
deliveredDiskBits[selectedDisk]++;
} }
uint32_t cyclesPassed = g_cpu->cycles - driveSpinupCycles[selectedDisk]; disk[selectedDisk]->writeNextWozByte(curWozTrack[selectedDisk], readWriteLatch);
// FIXME: this is a bit of a magic constant, which makes the drive deliveredDiskBits[selectedDisk] += 8;
// test in Copy2+ at 179.4ms per revolution (334.4rpm). I'd like to goto done;
// understand that better and get to to the proper 200ms (300rpm). }
uint64_t expectedDiskBits = (float) cyclesPassed / 3.51;
int64_t bitsToDeliver = expectedDiskBits - deliveredDiskBits[selectedDisk];
if (bitsToDeliver > 0) { if (bitsToDeliver > 0) {
// We're expected to deliver some bits to the Disk II sequencer. // We're expected to deliver some bits to the Disk II sequencer.
// Instead of piecemeal delivering a small number of bits (which we // Instead of piecemeal delivering a small number of bits (which we
// could do, but it's kinda busywork) - instead, we'll do one of two // could do, but it's kinda busywork) - instead, we'll do one of two
// possible things. // possible things.
// //
// The first: if we're expecting a small number of bits to be delivered, // The first: if we're expecting a small number of bits to be delivered,
// then we'll grab the next byte from the nibble stream and return it. // then we'll grab the next byte from the nibble stream and return it.
// This itself has three possible cases - // This itself has three possible cases -
// (a) we should be delivering less than a full byte, but we're // (a) we should be delivering less than a full byte, but we're
// actually going to deliver a full byte. bitsToDeliver will // actually going to deliver a full byte. bitsToDeliver will
// become negative, because we're delivering these too early. // become negative, because we're delivering these too early.
// The next call will probably see that it has nothing to deliver // The next call will probably see that it has nothing to deliver
// and, as long as the disk image we're using doesn't have a // and, as long as the disk image we're using doesn't have a
// really fine tolerance on the delivery rate of the bits, // really fine tolerance on the delivery rate of the bits,
// it will all come out in the wash. // it will all come out in the wash.
// (b) we should be delivering exactly a byte, and we're doing the // (b) we should be delivering exactly a byte, and we're doing the
// absolute right thing. // absolute right thing.
// (c) we are more than 1 byte, but less than 2 bytes, behind. If // (c) we are more than 1 byte, but less than 2 bytes, behind. If
// this is the case, we're probably making up for a timing // this is the case, we're probably making up for a timing
// problem in this code - where the bits would now have been // problem in this code - where the bits would now have been
// lost. By returning the first byte that we found, we're hoping // lost. By returning the first byte that we found, we're hoping
// that the next call will be closer to on time, and we will // that the next call will be closer to on time, and we will
// eventually catch back up to the stream. Hopefully this makes // eventually catch back up to the stream. Hopefully this makes
// the stream a little more resilient - and the error isn't // the stream a little more resilient - and the error isn't
// so far off that the reader notices something is weird on the // so far off that the reader notices something is weird on the
// timing. (Standard RWTS doesn't, but some copy protection // timing. (Standard RWTS doesn't, but some copy protection
// might.) // might.)
if (bitsToDeliver < 16) { if (bitsToDeliver < 16) {
while (bitsToDeliver > -16 && ((sequencer & 0x80) == 0)) { while (bitsToDeliver > -16 && ((sequencer & 0x80) == 0)) {
sequencer <<= 1;
sequencer |= disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]);
bitsToDeliver--;
deliveredDiskBits[selectedDisk]++;
}
goto done;
}
// If we reach here, we're throwing away a bunch of missed data.
// This might be normal (where the machine wasn't listening for the data),
// or it might be exceptional (something wrong with the tuning of data
// delivery, based on the magic constant in expectedDiskBits above)...
deliveredDiskBits[selectedDisk] += bitsToDeliver;
while (bitsToDeliver) {
sequencer <<= 1; sequencer <<= 1;
sequencer |= disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]); sequencer |= disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]);
bitsToDeliver--; bitsToDeliver--;
deliveredDiskBits[selectedDisk]++;
} }
goto done;
}
// If we reach here, we're throwing away a bunch of missed data.
// This might be normal (where the machine wasn't listening for the data),
// or it might be exceptional (something wrong with the tuning of data
// delivery, based on the magic constant in expectedDiskBits above)...
deliveredDiskBits[selectedDisk] += bitsToDeliver;
while (bitsToDeliver) {
sequencer <<= 1;
sequencer |= disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]);
bitsToDeliver--;
} }
} }

View File

@ -52,6 +52,8 @@ class DiskII : public Slot {
void convertDskToNib(const char *outFN); void convertDskToNib(const char *outFN);
#endif #endif
int64_t calcExpectedBits();
public: public:
// debugging // debugging
WozSerializer *disk[2]; WozSerializer *disk[2];

View File

@ -20,7 +20,7 @@ bool WozSerializer::Serialize(int8_t fd)
// If we're being asked to serialize, make sure we've flushed any data first // If we're being asked to serialize, make sure we've flushed any data first
flush(); flush();
uint8_t buf[13] = { WOZMAGIC, uint8_t buf[17] = { WOZMAGIC,
(trackPointer >> 24) & 0xFF, (trackPointer >> 24) & 0xFF,
(trackPointer >> 16) & 0xFF, (trackPointer >> 16) & 0xFF,
(trackPointer >> 8) & 0xFF, (trackPointer >> 8) & 0xFF,
@ -29,11 +29,15 @@ bool WozSerializer::Serialize(int8_t fd)
(trackBitCounter >> 16) & 0xFF, (trackBitCounter >> 16) & 0xFF,
(trackBitCounter >> 8) & 0xFF, (trackBitCounter >> 8) & 0xFF,
(trackBitCounter ) & 0xFF, (trackBitCounter ) & 0xFF,
(lastReadPointer >> 24) & 0xFF,
(lastReadPointer >> 16) & 0xFF,
(lastReadPointer >> 8) & 0xFF,
(lastReadPointer ) & 0xFF,
trackByte, trackByte,
trackBitIdx, trackBitIdx,
trackLoopCounter, trackLoopCounter,
WOZMAGIC }; WOZMAGIC };
if (g_filemanager->write(fd, buf, 13) != 13) if (g_filemanager->write(fd, buf, 17) != 17)
return false; return false;
return true; return true;
@ -42,8 +46,8 @@ bool WozSerializer::Serialize(int8_t fd)
bool WozSerializer::Deserialize(int8_t fd) bool WozSerializer::Deserialize(int8_t fd)
{ {
// Before deserializing, the caller has to re-load the right disk image! // Before deserializing, the caller has to re-load the right disk image!
uint8_t buf[13]; uint8_t buf[17];
if (g_filemanager->read(fd, buf, 13) != 13) if (g_filemanager->read(fd, buf, 17) != 17)
return false; return false;
if (buf[0] != WOZMAGIC) if (buf[0] != WOZMAGIC)
@ -59,10 +63,15 @@ bool WozSerializer::Deserialize(int8_t fd)
trackBitCounter <<= 8; trackBitCounter |= buf[7]; trackBitCounter <<= 8; trackBitCounter |= buf[7];
trackBitCounter <<= 8; trackBitCounter |= buf[8]; trackBitCounter <<= 8; trackBitCounter |= buf[8];
trackByte = buf[9]; lastReadPointer = buf[9];
trackBitIdx = buf[10]; lastReadPointer <<= 8; lastReadPointer |= buf[10];
trackLoopCounter = buf[11]; lastReadPointer <<= 8; lastReadPointer |= buf[11];
if (buf[12] != WOZMAGIC) lastReadPointer <<= 8; lastReadPointer |= buf[12];
trackByte = buf[13];
trackBitIdx = buf[14];
trackLoopCounter = buf[15];
if (buf[16] != WOZMAGIC)
return false; return false;
return true; return true;

View File

@ -39,7 +39,7 @@ Woz::Woz(bool verbose, uint8_t dumpflags)
metaData = NULL; metaData = NULL;
this->verbose = verbose; this->verbose = verbose;
this->dumpflags = dumpflags; this->dumpflags = dumpflags;
trackDirty = false; dataTrackDirty = -1;
memset(&quarterTrackMap, 255, sizeof(quarterTrackMap)); memset(&quarterTrackMap, 255, sizeof(quarterTrackMap));
memset(&di, 0, sizeof(diskInfo)); memset(&di, 0, sizeof(diskInfo));
@ -74,36 +74,25 @@ bool Woz::writeNextWozBit(uint8_t datatrack, uint8_t bit)
return true; return true;
} }
if (!tracks[datatrack].trackData) { // trackByte is undefined if trackBitIdx == 0x80; otherwise, it
fprintf(stderr, "ERROR: tried to writeNextWozBit to a data track that's not loaded, and we can't possibly tell which QT that should be\n"); // contains tracks[datatrack].trackData[trackPointer]. Make sure
return false; // to keep this up to date b/c we might try to read the next bit.
}
if (trackBitCounter >= tracks[datatrack].bitCount) {
printf("WRITE counter reset [%u > %u]\n", trackBitCounter, tracks[datatrack].bitCount);
trackPointer = 0;
trackBitIdx = 0x80;
trackBitCounter = 0;
}
if (trackBitIdx == 0x80) { if (trackBitIdx == 0x80) {
trackByte = tracks[datatrack].trackData[trackPointer++]; loadTrackByte(datatrack);
} }
// Modify trackByte based on the bit write
if (bit) if (bit)
trackByte |= trackBitIdx; trackByte |= trackBitIdx;
else else
trackByte &= ~trackBitIdx; trackByte &= ~trackBitIdx;
tracks[datatrack].trackData[trackPointer-1] = trackByte; // Update the datatrack with the current trackByte
trackBitCounter++; tracks[datatrack].trackData[lastReadPointer] = trackByte;
trackDirty = true; advanceBitStream(datatrack);
trackBitIdx >>= 1; dataTrackDirty = datatrack;
if (!trackBitIdx) {
trackBitIdx = 0x80;
}
return true; return true;
} }
@ -125,58 +114,61 @@ bool Woz::writeNextWozByte(uint8_t datatrack, uint8_t b)
// We could be byte-aligned, but it's not guaranteed, so this // We could be byte-aligned, but it's not guaranteed, so this
// handles it bitwise. // handles it bitwise.
#if 0
printf("track %d write byte 0x%.2X @ ptr[%d] bitidx==0x%.2X ctr=%d\n", datatrack, b, trackPointer, trackBitIdx, trackBitCounter);
// Debugging: aligning to bytes so I can see the effective bitstream
if (trackBitIdx != 0x80) {
while (trackBitIdx) {
trackBitCounter++;
trackBitIdx >>= 1;
}
trackBitIdx = 0x80;
}
// end debugging
#endif
for (uint8_t i=0; i<8; i++) { for (uint8_t i=0; i<8; i++) {
writeNextWozBit(datatrack, b & (1 << (7-i)) ? 1 : 0); writeNextWozBit(datatrack, b & (1 << (7-i)) ? 1 : 0);
} }
return true; return true;
} }
void Woz::loadTrackByte(uint8_t datatrack)
{
// need another byte out of the track stream
if (tracks[datatrack].trackData) {
lastReadPointer = trackPointer;
trackByte = tracks[datatrack].trackData[trackPointer];
} else {
loadMissingTrackFromImage(datatrack);
if (tracks[datatrack].trackData) {
loadTrackByte(datatrack);
return;
}
trackPointer = 0;
trackLoopCounter++;
}
}
void Woz::advanceBitStream(uint8_t datatrack)
{
trackBitCounter++;
trackBitIdx >>= 1;
if (!trackBitIdx) {
trackBitIdx = 0x80;
trackPointer++;
}
// This could have " || trackPointer >= tracks[datatrack].bitCount/8" but
// it should be totally redundant
if (trackBitCounter >= tracks[datatrack].bitCount) {
trackPointer = 0;
trackBitIdx = 0x80;
trackBitCounter = 0;
trackLoopCounter++;
}
}
uint8_t Woz::getNextWozBit(uint8_t datatrack) uint8_t Woz::getNextWozBit(uint8_t datatrack)
{ {
if (datatrack >= 160) { if (datatrack >= 160) {
return 0; return 0;
} }
if (!tracks[datatrack].trackData) {
// fprintf(stderr, "ERROR: getNextWozBit was called without the track being cached, and it can't possibly know which QT to load it from\n");
return 0;
}
if (trackBitIdx == 0x80) { if (trackBitIdx == 0x80) {
// need another byte out of the track stream loadTrackByte(datatrack);
if (tracks[datatrack].trackData) {
trackByte = tracks[datatrack].trackData[trackPointer++];
if (trackPointer >= tracks[datatrack].bitCount / 8) {
trackPointer = 0;
trackLoopCounter++;
}
} else {
trackPointer = 0;
trackLoopCounter++;
}
} }
uint8_t ret = (trackByte & trackBitIdx) ? 1 : 0; uint8_t ret = (trackByte & trackBitIdx) ? 1 : 0;
trackBitIdx >>= 1; advanceBitStream(datatrack);
if (!trackBitIdx) {
trackBitIdx = 0x80;
}
return ret; return ret;
} }
@ -200,6 +192,9 @@ bool Woz::skipByte(uint8_t datatrack)
{ {
// head_window = 0; // FIXME kludgy, but okay if we don't need just one bit after this // head_window = 0; // FIXME kludgy, but okay if we don't need just one bit after this
trackPointer++; trackPointer++;
lastReadPointer=trackPointer;
trackBitIdx = 0x80;
if (trackPointer >= tracks[datatrack].bitCount / 8) { if (trackPointer >= tracks[datatrack].bitCount / 8) {
trackPointer = 0; trackPointer = 0;
trackLoopCounter++; trackLoopCounter++;
@ -318,7 +313,7 @@ bool Woz::writeFile(const char *filename, uint8_t forceType)
// Try to determine type from the file extension // Try to determine type from the file extension
const char *p = strrchr(filename, '.'); const char *p = strrchr(filename, '.');
if (!p) { if (!p) {
printf("Unable to determine file type of '%s'\n", filename); fprintf(stderr, "Unable to determine file type of '%s'\n", filename);
return false; return false;
} }
if (strcasecmp(p, ".woz") == 0) { if (strcasecmp(p, ".woz") == 0) {
@ -331,7 +326,7 @@ bool Woz::writeFile(const char *filename, uint8_t forceType)
} else if (strcasecmp(p, ".nib") == 0) { } else if (strcasecmp(p, ".nib") == 0) {
forceType = T_NIB; forceType = T_NIB;
} else { } else {
printf("Unable to determine file type of '%s'\n", filename); fprintf(stderr, "Unable to determine file type of '%s'\n", filename);
return false; return false;
} }
} }
@ -345,7 +340,7 @@ bool Woz::writeFile(const char *filename, uint8_t forceType)
case T_NIB: case T_NIB:
return writeNibFile(filename); return writeNibFile(filename);
default: default:
printf("Unknown disk type; unable to write\n"); fprintf(stderr, "Unknown disk type; unable to write\n");
return false; return false;
} }
} }
@ -477,6 +472,19 @@ bool Woz::writeWozFile(int fdout, uint8_t subtype)
return retval; return retval;
} }
bool Woz::writeWozTrack(int fdout, uint8_t trackToWrite, uint8_t imageType)
{
// FIXME: when we separate WOZ1 and WOZ2, return false here if it's WOZ1
// (since we're only writing WOZ2 images)
if (imageType != T_WOZ)
return false;
printf("writeWozTrack not implemented yet\n");
// FIXME: not implemented
return false;
}
bool Woz::writeDskFile(const char *filename, uint8_t subtype) bool Woz::writeDskFile(const char *filename, uint8_t subtype)
{ {
int fdout = open(filename, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR); int fdout = open(filename, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);
@ -509,7 +517,30 @@ bool Woz::writeDskFile(int fdout, uint8_t subtype)
exit(1); exit(1);
} }
} }
close(fdout); return true;
}
// FIXME: should this be a physical track?
bool Woz::writeDskTrack(int fdout, uint8_t trackToWrite, uint8_t imageType)
{
if (imageType != T_DSK && imageType != T_PO) {
return false;
}
uint8_t sectorData[256*16];
if (lseek(fdout, 256*16*trackToWrite, SEEK_SET) != 256*16*trackToWrite) {
perror("lseek");
return false;
}
if (!decodeWozTrackToDsk(trackToWrite, imageType, sectorData)) {
printf("failed to decode to dsk\n");
return false;
}
if (write(fdout, sectorData, 256*16) != 256*16) {
printf("write failed\n");
return false;
}
return true; return true;
} }
@ -544,7 +575,25 @@ bool Woz::writeNibFile(int fdout)
exit(1); exit(1);
} }
} }
close(fdout); return true;
}
// FIXME: should this be a physical track?
bool Woz::writeNibTrack(int fdout, uint8_t trackToWrite, uint8_t imageType)
{
if (imageType != T_NIB)
return false;
if (lseek(fdout, NIBTRACKSIZE * trackToWrite, SEEK_SET) !=
NIBTRACKSIZE * trackToWrite)
return false;
nibSector nibData[16];
if (!decodeWozTrackToNib(trackToWrite, nibData))
return false;
if (write(fdout, nibData, NIBTRACKSIZE) != NIBTRACKSIZE)
return false;
return true; return true;
} }
@ -577,7 +626,7 @@ void Woz::_initInfo()
} }
} }
// Only used if we didn't preload a data track; the load we perfrom // Only used if we didn't preload a data track; the load we perform
// differs based on the image type we originally read from // differs based on the image type we originally read from
bool Woz::loadMissingTrackFromImage(uint8_t datatrack) bool Woz::loadMissingTrackFromImage(uint8_t datatrack)
{ {
@ -616,7 +665,7 @@ bool Woz::loadMissingTrackFromImage(uint8_t datatrack)
lseek(fd, 256*16*phystrack, SEEK_SET); lseek(fd, 256*16*phystrack, SEEK_SET);
if (read(fd, sectorData, 256*16) != 256*16) { if (read(fd, sectorData, 256*16) != 256*16) {
fprintf(stderr, "Failed to read sector\n"); fprintf(stderr, "Failed to read track\n");
return false; return false;
} }
@ -671,7 +720,7 @@ bool Woz::readDskFile(const char *filename, bool preloadTracks, uint8_t subtype)
if (fd != -1) close(fd); if (fd != -1) close(fd);
fd = open(filename, O_RDWR, S_IRUSR|S_IWUSR); fd = open(filename, O_RDWR, S_IRUSR|S_IWUSR);
if (fd == -1) { if (fd == -1) {
perror("Unable to open input file"); perror("Unable to open input file");
goto done; goto done;
} }
@ -725,13 +774,13 @@ bool Woz::readNibFile(const char *filename, bool preloadTracks)
for (int phystrack=0; phystrack<35; phystrack++) { for (int phystrack=0; phystrack<35; phystrack++) {
uint32_t bytesRead = read(fd, nibData, NIBTRACKSIZE); uint32_t bytesRead = read(fd, nibData, NIBTRACKSIZE);
if (bytesRead != NIBTRACKSIZE) { if (bytesRead != NIBTRACKSIZE) {
printf("Failed to read NIB data; got %d bytes, wanted %d\n", bytesRead, NIBTRACKSIZE); fprintf(stderr, "Failed to read NIB data; got %d bytes, wanted %d\n", bytesRead, NIBTRACKSIZE);
return false; return false;
} }
uint8_t datatrack = quarterTrackMap[phystrack * 4]; uint8_t datatrack = quarterTrackMap[phystrack * 4];
tracks[datatrack].trackData = (uint8_t *)calloc(NIBTRACKSIZE, 1); tracks[datatrack].trackData = (uint8_t *)calloc(NIBTRACKSIZE, 1);
if (!tracks[datatrack].trackData) { if (!tracks[datatrack].trackData) {
printf("Failed to malloc track data\n"); fprintf(stderr, "Failed to malloc track data\n");
return false; return false;
} }
@ -769,7 +818,7 @@ bool Woz::readWozFile(const char *filename, bool preloadTracks)
printf("WOZ%c disk image\n", (h & 0xFF000000)>>24); printf("WOZ%c disk image\n", (h & 0xFF000000)>>24);
} }
} else { } else {
printf("Unknown disk image type; can't continue\n"); fprintf(stderr, "Unknown disk image type; can't continue\n");
if (preloadTracks && fd != -1) if (preloadTracks && fd != -1)
close(fd); close(fd);
return false; return false;
@ -777,13 +826,13 @@ bool Woz::readWozFile(const char *filename, bool preloadTracks)
uint32_t tmp; uint32_t tmp;
if (!read32(fd, &tmp)) { if (!read32(fd, &tmp)) {
printf("Read failure\n"); fprintf(stderr, "Read failure\n");
if (preloadTracks && fd != -1) if (preloadTracks && fd != -1)
close(fd); close(fd);
return false; return false;
} }
if (tmp != 0x0A0D0AFF) { if (tmp != 0x0A0D0AFF) {
printf("WOZ header failure; exiting\n"); fprintf(stderr, "WOZ header failure; exiting\n");
if (preloadTracks && fd != -1) if (preloadTracks && fd != -1)
close(fd); close(fd);
return false; return false;
@ -1151,7 +1200,7 @@ bool Woz::readNibSectorData(uint8_t phystrack, uint8_t sector, nibSector *sector
if (!tracks[dataTrack].trackData) { if (!tracks[dataTrack].trackData) {
// Load the cached track for this phys Nib track. // Load the cached track for this phys Nib track.
if (!loadMissingTrackFromImage(dataTrack)) { if (!loadMissingTrackFromImage(dataTrack)) {
fprintf(stderr, "Failed to read track %d\n", dataTrack); fprintf(stderr, "Failed to load track data for track %d\n", dataTrack);
return false; return false;
} }
} }
@ -1189,6 +1238,7 @@ bool Woz::readNibSectorData(uint8_t phystrack, uint8_t sector, nibSector *sector
sectorData->sectorEpilog[2] == 0xeb) { sectorData->sectorEpilog[2] == 0xeb) {
// Header is integral. See if it's our sector: // Header is integral. See if it's our sector:
uint8_t sectorNum = de44(sectorData->sector44); uint8_t sectorNum = de44(sectorData->sector44);
printf("Denib: found track/sector %d/%d\n", de44(sectorData->track44), sectorNum);
if (sectorNum != sector) { if (sectorNum != sector) {
continue; continue;
} }
@ -1223,6 +1273,16 @@ bool Woz::readNibSectorData(uint8_t phystrack, uint8_t sector, nibSector *sector
} }
} }
/* Debugging: dump the track, b/c we failed to find a sector */
printf("Broken NIB track:\n");
printf("@d=(");
for (int i=0; i<tracks[dataTrack].bitCount / 8; i+=16) {
for (int j=0; j < 16 && j+i < tracks[dataTrack].bitCount/8; j++) {
printf("0x%.2X, ", tracks[dataTrack].trackData[i+j]);
}
printf("\n");
}
printf(")\n");
return false; return false;
} }
@ -1349,6 +1409,8 @@ bool Woz::decodeWozTrackToNib(uint8_t phystrack, nibSector sectorData[16])
{ {
for (int sector=0; sector<16; sector++) { for (int sector=0; sector<16; sector++) {
if (!readNibSectorData(phystrack, sector, (nibSector *)(&sectorData[sector]))) { if (!readNibSectorData(phystrack, sector, (nibSector *)(&sectorData[sector]))) {
printf("Failed to read nib sector data for track %d sector %d\n",
phystrack, sector);
return false; return false;
} }
} }
@ -1360,11 +1422,16 @@ bool Woz::decodeWozTrackToDsk(uint8_t phystrack, uint8_t subtype, uint8_t sector
{ {
// First read it to a NIB; then convert the NIB to a DSK. // First read it to a NIB; then convert the NIB to a DSK.
nibSector nibData[16]; nibSector nibData[16];
if (!decodeWozTrackToNib(phystrack, nibData)) if (!decodeWozTrackToNib(phystrack, nibData)) {
printf("failed to decode to Nib\n");
return false; return false;
}
if (denibblizeTrack((const uint8_t *)nibData, sectorData, subtype, phystrack) != errorNone) nibErr ret = denibblizeTrack((const uint8_t *)nibData, sectorData, subtype, phystrack);
if (ret != errorNone) {
printf("Failed to denibblize track: %d\n", ret);
return false; return false;
}
return true; return true;
} }
@ -1602,24 +1669,33 @@ uint8_t Woz::dataTrackNumberForQuarterTrack(uint16_t qt)
bool Woz::flush() bool Woz::flush()
{ {
if (trackDirty) { // This has to flush just one track to the file. If it tried to do more,
printf("FLUSH!\n"); // it would wind up trying to preload the tracks that aren't loaded; and
trackDirty = false; // that would notice that the current track is dirty, so it would call
// From the imageType, call the appropriate function to write. // flush() again; and then we'd be looping infinitely.
// FIXME: this assumes we have an open fd, which means we didn't preload
// the whole image
if (dataTrackDirty != -1) {
printf("FLUSH track %d\n", dataTrackDirty);
// From the imageType, call the appropriate function to write a track
switch (imageType) { switch (imageType) {
case T_WOZ: case T_WOZ:
return writeWozFile(fd, imageType); return writeWozTrack(fd, dataTrackDirty, imageType);
case T_DSK: case T_DSK:
case T_PO: case T_PO:
return writeDskFile(fd, imageType); return writeDskTrack(fd, dataTrackDirty, imageType);
case T_NIB: case T_NIB:
return writeNibFile(fd); return writeNibTrack(fd, dataTrackDirty, imageType);
default: default:
fprintf(stderr, "Error: unknown imageType; can't flush\n"); fprintf(stderr, "Error: unknown imageType; can't flush\n");
return false; return false;
} }
// fsync(fd); // FIXME should not be needed
} }
dataTrackDirty = -1;
/* NOTREACHED */ /* NOTREACHED */
return false; return false;
} }

View File

@ -59,6 +59,8 @@ class Woz {
bool flush(); bool flush();
void debug();
//protected: //protected:
// Interface for AiiE // Interface for AiiE
bool writeNextWozBit(uint8_t datatrack, uint8_t bit); bool writeNextWozBit(uint8_t datatrack, uint8_t bit);
@ -68,6 +70,9 @@ class Woz {
bool skipByte(uint8_t datatrack); bool skipByte(uint8_t datatrack);
private: private:
void loadTrackByte(uint8_t datatrack);
void advanceBitStream(uint8_t datatrack);
bool readWozFile(const char *filename, bool preloadTracks); bool readWozFile(const char *filename, bool preloadTracks);
bool readDskFile(const char *filename, bool preloadTracks, uint8_t subtype); bool readDskFile(const char *filename, bool preloadTracks, uint8_t subtype);
bool readNibFile(const char *filename, bool preloadTracks); bool readNibFile(const char *filename, bool preloadTracks);
@ -82,6 +87,10 @@ class Woz {
bool writeNibFile(const char *filename); bool writeNibFile(const char *filename);
bool writeNibFile(int fd); bool writeNibFile(int fd);
bool writeWozTrack(int fd, uint8_t trackToWrite, uint8_t imageType);
bool writeDskTrack(int fd, uint8_t trackToWrite, uint8_t imageType);
bool writeNibTrack(int fd, uint8_t trackToWrite, uint8_t imageType);
uint8_t fakeBit(); uint8_t fakeBit();
bool parseTRKSChunk(uint32_t chunkSize); bool parseTRKSChunk(uint32_t chunkSize);
@ -109,7 +118,7 @@ class Woz {
uint8_t dumpflags; uint8_t dumpflags;
bool autoFlushTrackData; bool autoFlushTrackData;
bool trackDirty; int8_t dataTrackDirty; // -1 means "none"
uint8_t quarterTrackMap[40*4]; uint8_t quarterTrackMap[40*4];
diskInfo di; diskInfo di;
@ -120,6 +129,7 @@ protected:
int fd; int fd;
uint32_t trackPointer; uint32_t trackPointer;
uint32_t lastReadPointer;
uint32_t trackBitCounter; uint32_t trackBitCounter;
uint8_t trackByte; uint8_t trackByte;
uint8_t trackBitIdx; uint8_t trackBitIdx;