mirror of
https://github.com/JorjBauer/aiie.git
synced 2024-10-31 09:15:51 +00:00
fixes for disk writing and rotational speed
This commit is contained in:
parent
99c5e37159
commit
998c7cebc8
175
apple/diskii.cpp
175
apple/diskii.cpp
@ -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--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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];
|
||||||
|
@ -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;
|
||||||
|
234
apple/woz.cpp
234
apple/woz.cpp
@ -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 *)(§orData[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;
|
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;
|
||||||
}
|
}
|
||||||
|
12
apple/woz.h
12
apple/woz.h
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user