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);
}
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)
{
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;
}
@ -574,85 +616,86 @@ uint8_t DiskII::readOrWriteByte()
return 0xFF;
}
uint32_t curCycles = g_cpu->cycles;
// FIXME: for writes, we need to check s/t like ... if (diskIsSpinningUntil[selectedDisk] >= curCycles) { return } ...
if (writeMode && !writeProt) {
// It's a write request. Inject 'readWriteLatch'.
disk[selectedDisk]->writeNextWozByte(curWozTrack[selectedDisk], readWriteLatch);
int32_t bitsToDeliver;
if (diskIsSpinningUntil[selectedDisk] < g_cpu->cycles) {
// Uum, disk isn't spinning?
goto done;
}
if (diskIsSpinningUntil[selectedDisk] >= curCycles) {
bitsToDeliver = calcExpectedBits();
if (writeMode && !writeProt) {
// It's a write request.
// Figure out how many cycles we missed since the last disk read,
// and pop the right number of bits off the woz track.
// Write requests from DOS 3.3 start with 40 self-sync bytes
// (cf. Beneath Apple DOS, p.3-8 and 3-9). These 0XFF bytes are
// written in a 40-cycle loop, where a bit is written every 4
// cycles; it intentionally lets 2 0-bits slip in there to
// provide the self-sync pattern.
//
// So the timing here is important. Figure out how many bits
// should have been laid down to the track, and those are 0s.
// Handle rollover, which is a mess.
if (driveSpinupCycles[selectedDisk] > g_cpu->cycles) {
// printf("Cycle rollover\n");
driveSpinupCycles[selectedDisk] = g_cpu->cycles-1; // FIXME: is the -1 correct? What if we were @ 0?
#ifndef TEENSYDUINO
exit(2); // for debugging, FIXME ***
#endif
int64_t expectedBits = calcExpectedBits();
while (expectedBits > 0) {
disk[selectedDisk]->writeNextWozBit(curWozTrack[selectedDisk], 0);
expectedBits--;
deliveredDiskBits[selectedDisk]++;
}
uint32_t cyclesPassed = g_cpu->cycles - driveSpinupCycles[selectedDisk];
// FIXME: this is a bit of a magic constant, which makes the drive
// test in Copy2+ at 179.4ms per revolution (334.4rpm). I'd like to
// understand that better and get to to the proper 200ms (300rpm).
uint64_t expectedDiskBits = (float) cyclesPassed / 3.51;
int64_t bitsToDeliver = expectedDiskBits - deliveredDiskBits[selectedDisk];
disk[selectedDisk]->writeNextWozByte(curWozTrack[selectedDisk], readWriteLatch);
deliveredDiskBits[selectedDisk] += 8;
goto done;
}
if (bitsToDeliver > 0) {
// We're expected to deliver some bits to the Disk II sequencer.
// 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
// possible things.
//
// 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.
// This itself has three possible cases -
// (a) we should be delivering less than a full byte, but we're
// actually going to deliver a full byte. bitsToDeliver will
// become negative, because we're delivering these too early.
// 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
// really fine tolerance on the delivery rate of the bits,
// it will all come out in the wash.
// (b) we should be delivering exactly a byte, and we're doing the
// absolute right thing.
// (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
// problem in this code - where the bits would now have been
// 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
// eventually catch back up to the stream. Hopefully this makes
// the stream a little more resilient - and the error isn't
// so far off that the reader notices something is weird on the
// timing. (Standard RWTS doesn't, but some copy protection
// might.)
if (bitsToDeliver < 16) {
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) {
if (bitsToDeliver > 0) {
// We're expected to deliver some bits to the Disk II sequencer.
// 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
// possible things.
//
// 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.
// This itself has three possible cases -
// (a) we should be delivering less than a full byte, but we're
// actually going to deliver a full byte. bitsToDeliver will
// become negative, because we're delivering these too early.
// 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
// really fine tolerance on the delivery rate of the bits,
// it will all come out in the wash.
// (b) we should be delivering exactly a byte, and we're doing the
// absolute right thing.
// (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
// problem in this code - where the bits would now have been
// 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
// eventually catch back up to the stream. Hopefully this makes
// the stream a little more resilient - and the error isn't
// so far off that the reader notices something is weird on the
// timing. (Standard RWTS doesn't, but some copy protection
// might.)
if (bitsToDeliver < 16) {
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 |= disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]);
bitsToDeliver--;
}
}

View File

@ -51,6 +51,8 @@ class DiskII : public Slot {
#ifndef TEENSYDUINO
void convertDskToNib(const char *outFN);
#endif
int64_t calcExpectedBits();
public:
// debugging

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

View File

@ -39,7 +39,7 @@ Woz::Woz(bool verbose, uint8_t dumpflags)
metaData = NULL;
this->verbose = verbose;
this->dumpflags = dumpflags;
trackDirty = false;
dataTrackDirty = -1;
memset(&quarterTrackMap, 255, sizeof(quarterTrackMap));
memset(&di, 0, sizeof(diskInfo));
@ -74,36 +74,25 @@ bool Woz::writeNextWozBit(uint8_t datatrack, uint8_t bit)
return true;
}
if (!tracks[datatrack].trackData) {
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");
return false;
}
if (trackBitCounter >= tracks[datatrack].bitCount) {
printf("WRITE counter reset [%u > %u]\n", trackBitCounter, tracks[datatrack].bitCount);
trackPointer = 0;
trackBitIdx = 0x80;
trackBitCounter = 0;
}
// trackByte is undefined if trackBitIdx == 0x80; otherwise, it
// contains tracks[datatrack].trackData[trackPointer]. Make sure
// to keep this up to date b/c we might try to read the next bit.
if (trackBitIdx == 0x80) {
trackByte = tracks[datatrack].trackData[trackPointer++];
loadTrackByte(datatrack);
}
// Modify trackByte based on the bit write
if (bit)
trackByte |= trackBitIdx;
else
trackByte &= ~trackBitIdx;
// Update the datatrack with the current trackByte
tracks[datatrack].trackData[lastReadPointer] = trackByte;
advanceBitStream(datatrack);
tracks[datatrack].trackData[trackPointer-1] = trackByte;
trackBitCounter++;
trackDirty = true;
trackBitIdx >>= 1;
if (!trackBitIdx) {
trackBitIdx = 0x80;
}
dataTrackDirty = datatrack;
return true;
}
@ -122,61 +111,64 @@ bool Woz::writeNextWozByte(uint8_t datatrack, uint8_t b)
fprintf(stderr, "ERROR: tried to write to a track that's not loaded, and it's not possible to tell what QT was meant\n");
return false;
}
// We could be byte-aligned, but it's not guaranteed, so this
// 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++) {
writeNextWozBit(datatrack, b & (1 << (7-i)) ? 1 : 0);
}
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)
{
if (datatrack >= 160) {
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) {
loadTrackByte(datatrack);
}
if (trackBitIdx == 0x80) {
// need another byte out of the track stream
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;
trackBitIdx >>= 1;
if (!trackBitIdx) {
trackBitIdx = 0x80;
}
advanceBitStream(datatrack);
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
trackPointer++;
lastReadPointer=trackPointer;
trackBitIdx = 0x80;
if (trackPointer >= tracks[datatrack].bitCount / 8) {
trackPointer = 0;
trackLoopCounter++;
@ -318,7 +313,7 @@ bool Woz::writeFile(const char *filename, uint8_t forceType)
// Try to determine type from the file extension
const char *p = strrchr(filename, '.');
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;
}
if (strcasecmp(p, ".woz") == 0) {
@ -331,7 +326,7 @@ bool Woz::writeFile(const char *filename, uint8_t forceType)
} else if (strcasecmp(p, ".nib") == 0) {
forceType = T_NIB;
} else {
printf("Unable to determine file type of '%s'\n", filename);
fprintf(stderr, "Unable to determine file type of '%s'\n", filename);
return false;
}
}
@ -345,7 +340,7 @@ bool Woz::writeFile(const char *filename, uint8_t forceType)
case T_NIB:
return writeNibFile(filename);
default:
printf("Unknown disk type; unable to write\n");
fprintf(stderr, "Unknown disk type; unable to write\n");
return false;
}
}
@ -477,6 +472,19 @@ bool Woz::writeWozFile(int fdout, uint8_t subtype)
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)
{
int fdout = open(filename, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);
@ -509,10 +517,33 @@ bool Woz::writeDskFile(int fdout, uint8_t subtype)
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;
}
bool Woz::writeNibFile(const char *filename)
{
int fdout = open(filename, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);
@ -544,7 +575,25 @@ bool Woz::writeNibFile(int fdout)
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;
}
@ -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
bool Woz::loadMissingTrackFromImage(uint8_t datatrack)
{
@ -616,7 +665,7 @@ bool Woz::loadMissingTrackFromImage(uint8_t datatrack)
lseek(fd, 256*16*phystrack, SEEK_SET);
if (read(fd, sectorData, 256*16) != 256*16) {
fprintf(stderr, "Failed to read sector\n");
fprintf(stderr, "Failed to read track\n");
return false;
}
@ -671,7 +720,7 @@ bool Woz::readDskFile(const char *filename, bool preloadTracks, uint8_t subtype)
if (fd != -1) close(fd);
fd = open(filename, O_RDWR, S_IRUSR|S_IWUSR);
if (fd == -1) {
perror("Unable to open input file");
perror("Unable to open input file");
goto done;
}
@ -725,13 +774,13 @@ bool Woz::readNibFile(const char *filename, bool preloadTracks)
for (int phystrack=0; phystrack<35; phystrack++) {
uint32_t bytesRead = read(fd, nibData, 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;
}
uint8_t datatrack = quarterTrackMap[phystrack * 4];
tracks[datatrack].trackData = (uint8_t *)calloc(NIBTRACKSIZE, 1);
if (!tracks[datatrack].trackData) {
printf("Failed to malloc track data\n");
fprintf(stderr, "Failed to malloc track data\n");
return false;
}
@ -769,7 +818,7 @@ bool Woz::readWozFile(const char *filename, bool preloadTracks)
printf("WOZ%c disk image\n", (h & 0xFF000000)>>24);
}
} else {
printf("Unknown disk image type; can't continue\n");
fprintf(stderr, "Unknown disk image type; can't continue\n");
if (preloadTracks && fd != -1)
close(fd);
return false;
@ -777,13 +826,13 @@ bool Woz::readWozFile(const char *filename, bool preloadTracks)
uint32_t tmp;
if (!read32(fd, &tmp)) {
printf("Read failure\n");
fprintf(stderr, "Read failure\n");
if (preloadTracks && fd != -1)
close(fd);
return false;
}
if (tmp != 0x0A0D0AFF) {
printf("WOZ header failure; exiting\n");
fprintf(stderr, "WOZ header failure; exiting\n");
if (preloadTracks && fd != -1)
close(fd);
return false;
@ -1151,7 +1200,7 @@ bool Woz::readNibSectorData(uint8_t phystrack, uint8_t sector, nibSector *sector
if (!tracks[dataTrack].trackData) {
// Load the cached track for this phys Nib track.
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;
}
}
@ -1189,6 +1238,7 @@ bool Woz::readNibSectorData(uint8_t phystrack, uint8_t sector, nibSector *sector
sectorData->sectorEpilog[2] == 0xeb) {
// Header is integral. See if it's our sector:
uint8_t sectorNum = de44(sectorData->sector44);
printf("Denib: found track/sector %d/%d\n", de44(sectorData->track44), sectorNum);
if (sectorNum != sector) {
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;
}
@ -1349,6 +1409,8 @@ bool Woz::decodeWozTrackToNib(uint8_t phystrack, nibSector sectorData[16])
{
for (int sector=0; sector<16; 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;
}
}
@ -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.
nibSector nibData[16];
if (!decodeWozTrackToNib(phystrack, nibData))
if (!decodeWozTrackToNib(phystrack, nibData)) {
printf("failed to decode to Nib\n");
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 true;
}
@ -1602,24 +1669,33 @@ uint8_t Woz::dataTrackNumberForQuarterTrack(uint16_t qt)
bool Woz::flush()
{
if (trackDirty) {
printf("FLUSH!\n");
trackDirty = false;
// From the imageType, call the appropriate function to write.
// This has to flush just one track to the file. If it tried to do more,
// it would wind up trying to preload the tracks that aren't loaded; and
// that would notice that the current track is dirty, so it would call
// 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) {
case T_WOZ:
return writeWozFile(fd, imageType);
return writeWozTrack(fd, dataTrackDirty, imageType);
case T_DSK:
case T_PO:
return writeDskFile(fd, imageType);
return writeDskTrack(fd, dataTrackDirty, imageType);
case T_NIB:
return writeNibFile(fd);
return writeNibTrack(fd, dataTrackDirty, imageType);
default:
fprintf(stderr, "Error: unknown imageType; can't flush\n");
return false;
}
// fsync(fd); // FIXME should not be needed
}
dataTrackDirty = -1;
/* NOTREACHED */
return false;
}

View File

@ -59,6 +59,8 @@ class Woz {
bool flush();
void debug();
//protected:
// Interface for AiiE
bool writeNextWozBit(uint8_t datatrack, uint8_t bit);
@ -68,6 +70,9 @@ class Woz {
bool skipByte(uint8_t datatrack);
private:
void loadTrackByte(uint8_t datatrack);
void advanceBitStream(uint8_t datatrack);
bool readWozFile(const char *filename, bool preloadTracks);
bool readDskFile(const char *filename, bool preloadTracks, uint8_t subtype);
bool readNibFile(const char *filename, bool preloadTracks);
@ -81,6 +86,10 @@ class Woz {
bool writeDskFile(int fd, uint8_t subtype);
bool writeNibFile(const char *filename);
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();
@ -109,7 +118,7 @@ class Woz {
uint8_t dumpflags;
bool autoFlushTrackData;
bool trackDirty;
int8_t dataTrackDirty; // -1 means "none"
uint8_t quarterTrackMap[40*4];
diskInfo di;
@ -120,6 +129,7 @@ protected:
int fd;
uint32_t trackPointer;
uint32_t lastReadPointer;
uint32_t trackBitCounter;
uint8_t trackByte;
uint8_t trackBitIdx;