mirror of
https://github.com/JorjBauer/aiie.git
synced 2025-04-07 21:37:14 +00:00
fixes for disk writing and rotational speed
This commit is contained in:
parent
99c5e37159
commit
998c7cebc8
177
apple/diskii.cpp
177
apple/diskii.cpp
@ -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--;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,8 @@ class DiskII : public Slot {
|
||||
#ifndef TEENSYDUINO
|
||||
void convertDskToNib(const char *outFN);
|
||||
#endif
|
||||
|
||||
int64_t calcExpectedBits();
|
||||
|
||||
public:
|
||||
// debugging
|
||||
|
@ -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;
|
||||
|
244
apple/woz.cpp
244
apple/woz.cpp
@ -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 *)(§orData[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;
|
||||
}
|
||||
|
12
apple/woz.h
12
apple/woz.h
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user