diff --git a/src/Makefile.am b/src/Makefile.am index 28f1495..f8a883c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,7 @@ METASOURCES=AUTO bin_PROGRAMS=epple2 -AM_CXXFLAGS=-std=c++14 -Wall -O3 +AM_CXXFLAGS=-std=c++11 -Wall -O3 AM_CPPFLAGS=$(all_includes) epple2_LDFLAGS=$(all_libraries) diff --git a/src/diskcontroller.cpp b/src/diskcontroller.cpp index 198e770..b7382cf 100644 --- a/src/diskcontroller.cpp +++ b/src/diskcontroller.cpp @@ -58,33 +58,14 @@ unsigned char DiskController::io(const unsigned short addr, const unsigned char break; case 6: this->load = on; - // TODO use LSS -// if (on && this->write && writing) { -// set(data); -// this->gui.setIO(this->slot,getCurrentDriveNumber(),this->motorOn); -// this->gui.setDirty(this->slot,getCurrentDriveNumber(),true); -// } else if (!(on || this->write)) { -// data = get(); -// } + // TODO when to do these GUI updates? +// this->gui.setIO(this->slot,getCurrentDriveNumber(),this->motorOn); +// this->gui.setDirty(this->slot,getCurrentDriveNumber(),true); break; case 7: this->write = on; - // TODO use LSS -// if (this->currentDrive->isWriteProtected()) { -// data |= 0x80; -// } else { -// data &= 0x7F; -// } break; } -// if (this->motorOn) { -// if (this->dataRegister == 0xD5) { -// printf("\ndata register --> "); -// } -// if (this->dataRegister & 0x80) { -// printf("%02x", this->dataRegister); -// } -// } return on ? d : this->dataRegister; } @@ -108,10 +89,10 @@ void DiskController::tick() { } void DiskController::rotateCurrentDisk() { - ++t; - if (t < 0 || 4 <= t) { // 4us interval between bits + ++this->t; + if (4 <= this->t) { // 4us interval between bits this->currentDrive->rotateDiskOneBit(); // (will also generate a read-pulse when it reads a 1-bit) - t = 0; + this->t = 0; } else { // clear the read pulse (to make it last only 1us) this->currentDrive->clearPulse(); @@ -121,7 +102,6 @@ void DiskController::rotateCurrentDisk() { void DiskController::stepLss() { std::uint8_t adr = this->write<<3 | this->load<<2 | (this->dataRegister>>7)<<1 | this->currentDrive->readPulse(); std::uint8_t cmd = this->lssp6rom.read(this->seq|adr); -// if (cmd & 3) printf("LSS ROM command byte: 0x%2x\n", cmd); this->seq = cmd & 0xF0u; // LSS command functions (UA2, 9-15, Table 9.3) diff --git a/src/drive.h b/src/drive.h index 80e7c5a..38e5862 100644 --- a/src/drive.h +++ b/src/drive.h @@ -101,7 +101,6 @@ public: // we see more than three (emulating the MC3470, see UA2, 9-11) ++cContiguousZeroBits; if (3 < cContiguousZeroBits) { -// if (cContiguousZeroBits == 4) printf("\n\n"); if (randomBit()) { this->pulse = true; } @@ -117,23 +116,8 @@ public: } void writeBit(bool on) { - this->disk.setBit(this->arm.getQuarterTrack()); + this->disk.setBit(this->arm.getQuarterTrack(), on); } - // unsigned char get() const - // { - // return this->disk.get(this->arm.getTrack()); - // } - - // void set(unsigned char value) - // { - // this->disk.put(this->arm.getTrack(),value); - // } - - - -// const WozFile& getDiskBytes() { -// return this->disk; -// } }; #endif diff --git a/src/lss.cpp b/src/lss.cpp index 394323e..d398665 100644 --- a/src/lss.cpp +++ b/src/lss.cpp @@ -34,28 +34,28 @@ static void setbth(std::uint8_t lssrom[], std::uint8_t x, std::uint8_t both) { lssrom[x] = both; } -static void showua2seq(std::uint8_t lssrom[], std::uint8_t seq) { - printf("| %02x %02x %02x %02x | %02x %02x %02x %02x", - lssrom[seq|0x9], - lssrom[seq|0xB], - lssrom[seq|0xD], - lssrom[seq|0xF], - lssrom[seq|0x8], - lssrom[seq|0xA], - lssrom[seq|0xC], - lssrom[seq|0xE] - ); - printf("| %02x %02x %02x %02x | %02x %02x %02x %02x |\n", - lssrom[seq|0x1], - lssrom[seq|0x0], - lssrom[seq|0x3], - lssrom[seq|0x2], - lssrom[seq|0x5], - lssrom[seq|0x4], - lssrom[seq|0x7], - lssrom[seq|0x6] - ); -} +//static void showua2seq(std::uint8_t lssrom[], std::uint8_t seq) { +// printf("| %02x %02x %02x %02x | %02x %02x %02x %02x", +// lssrom[seq|0x9], +// lssrom[seq|0xB], +// lssrom[seq|0xD], +// lssrom[seq|0xF], +// lssrom[seq|0x8], +// lssrom[seq|0xA], +// lssrom[seq|0xC], +// lssrom[seq|0xE] +// ); +// printf("| %02x %02x %02x %02x | %02x %02x %02x %02x |\n", +// lssrom[seq|0x1], +// lssrom[seq|0x0], +// lssrom[seq|0x3], +// lssrom[seq|0x2], +// lssrom[seq|0x5], +// lssrom[seq|0x4], +// lssrom[seq|0x7], +// lssrom[seq|0x6] +// ); +//} LSS::LSS(bool use13SectorDos32LSS): use13SectorDos32LSS(use13SectorDos32LSS) { @@ -175,15 +175,15 @@ LSS::LSS(bool use13SectorDos32LSS): setseq(lss13rom,0x23u,0x30u); setseq(lss13rom,0x33u,0xD0u); - if (use13SectorDos32LSS) { - for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) { - showua2seq(lss13rom,seq); - } - } else { - for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) { - showua2seq(lssrom,seq); - } - } +// if (use13SectorDos32LSS) { +// for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) { +// showua2seq(lss13rom,seq); +// } +// } else { +// for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) { +// showua2seq(lssrom,seq); +// } +// } } LSS::~LSS() { diff --git a/src/raminitializer.cpp b/src/raminitializer.cpp index 7c34c38..520465c 100644 --- a/src/raminitializer.cpp +++ b/src/raminitializer.cpp @@ -62,7 +62,7 @@ void RAMInitializer::putBytesUntilFull(int bit, int pat) } } -void RAMInitializer::ramPattern1(const int bit) throw (done) +void RAMInitializer::ramPattern1(const int bit) { for (int k = 0; k < 2; ++k) { @@ -100,7 +100,7 @@ void RAMInitializer::ramPattern1(const int bit) throw (done) } } -void RAMInitializer::ramPattern2(const int bit) throw (done) +void RAMInitializer::ramPattern2(const int bit) { for (int i = 0; i < 0x40; ++i) { @@ -111,7 +111,7 @@ void RAMInitializer::ramPattern2(const int bit) throw (done) -void RAMInitializer::putn(const int c, bool on, const int bit) throw (done) +void RAMInitializer::putn(const int c, bool on, const int bit) { if (((rand() >> 9) & 0x1F) == 5) on = !on; diff --git a/src/raminitializer.h b/src/raminitializer.h index 91585fb..0efc5b4 100644 --- a/src/raminitializer.h +++ b/src/raminitializer.h @@ -29,9 +29,9 @@ private: unsigned short nextinit; void putBytesUntilFull(int bit, int pat); - void ramPattern1(const int bit) throw (done); - void ramPattern2(const int bit) throw (done); - void putn(const int c, bool on, const int bit) throw (done); + void ramPattern1(const int bit); + void ramPattern2(const int bit); + void putn(const int c, bool on, const int bit); public: RAMInitializer(Memory& mem); diff --git a/src/steppermotor.cpp b/src/steppermotor.cpp index c979925..5e1f84c 100644 --- a/src/steppermotor.cpp +++ b/src/steppermotor.cpp @@ -26,9 +26,15 @@ * @author Chris Mosher */ /* + + mags ps magval 3210 ---- -- ------ + +Each postition is a quarter track. +One complete cycle through the 4 phases will +move the arm 2 tracks. (UA2, 9-7.) 0001 0 1 0011 1 3 0010 2 2 @@ -38,17 +44,19 @@ mags ps magval 1000 6 8 1001 7 9 -(strange, but defined) +strange, but still defined 1011 0 B 0111 2 7 1110 4 E 1101 6 D -(undefined, i.e., no movement) +all off (no movement) 0000 ? 0 + +undefined 0101 ? 5 // <-- TODO pick one at random? 1010 ? A // <-- TODO pick one at random? -1111 ? F +1111 ? F // TODO what to do here? */ #include "steppermotor.h" #include "util.h" @@ -76,7 +84,7 @@ void StepperMotor::setMagnet(const unsigned char magnet, const bool on) { } const char newPos = mapMagPos[this->mags]; - char d; + char d = 0; if (newPos >= 0) { d = calcDeltaPos(this->pos,newPos); this->pos = newPos; @@ -87,19 +95,28 @@ void StepperMotor::setMagnet(const unsigned char magnet, const bool on) { else if (this->quarterTrack > QTRACK_MAX) this->quarterTrack = QTRACK_MAX; } - std::cout << " ARM: magnet " << (unsigned int)magnet << " " << (on ? "on " : "off" ); - std::cout << " [" << - ((mags&1)?"*":".") << - ((mags&2)?"*":".") << - ((mags&4)?"*":".") << - ((mags&8)?"*":".") << - "]"; - if (d != 0) { - std::cout << " track " << std::hex << (unsigned int)(this->quarterTrack >> 2); - int fract = this->quarterTrack & 3; - if (fract != 0) { - std::cout << (fract == 1 ? " +.25" : fract == 2 ? " +.5" : " +.75"); - } - } - std::cout << std::endl; +// std::cout << " ARM: magnet " << (unsigned int)magnet << " " << (on ? "on " : "off" ); +// std::cout << " [" << +// ((mags&1)?"*":".") << +// ((mags&2)?"*":".") << +// ((mags&4)?"*":".") << +// ((mags&8)?"*":".") << +// "]"; +// if (d != 0) { +// std::cout << " track " << std::hex << (unsigned int)(this->quarterTrack >> 2); +// int fract = this->quarterTrack & 3; +// if (fract != 0) { +// std::cout << (fract == 1 ? " +.25" : fract == 2 ? " +.5" : " +.75"); +// } +// } +// std::cout << std::endl; } +//static void dumpQTrack(std::uint8_t currentQuarterTrack) { +// if (currentQuarterTrack % 4) { +// const std::uint8_t hundredths((currentQuarterTrack%4) * 25); +// printf("track 0x%02X +.%02d\n", currentQuarterTrack/4, hundredths); +// } else { +// printf("track 0x%02X\n", currentQuarterTrack/4); +// } +//} + diff --git a/src/wozfile.cpp b/src/wozfile.cpp index 08494db..f568110 100644 --- a/src/wozfile.cpp +++ b/src/wozfile.cpp @@ -22,6 +22,7 @@ #include #include #include +#include WozFile::WozFile() : lastQuarterTrack(0) { unload(); @@ -73,8 +74,8 @@ bool WozFile::load(const std::string& filePath) { printf("INFO version %d\n", *buf); five_25 = (buf[1]==1); printf("Disk type: %s\n", five_25 ? "5.25" : buf[1]==2 ? "3.5" : "?"); - writable = !(buf[2]==1); - printf("Write protected?: %s\n", writable ? "No" : "Yes"); + this->writable = !(buf[2]==1); + printf("Write protected?: %s\n", this->writable ? "No" : "Yes"); printf("Imaged with cross-track sync?: %s\n", buf[3]==1 ? "Yes" : "No"); printf("MC3470 fake bits removed?: %s\n", buf[4]==1 ? "Yes" : "No"); printf("Creator: \"%.32s\"\n", buf+5); @@ -103,7 +104,7 @@ bool WozFile::load(const std::string& filePath) { } printf("\x1b[31;47m-------------------------------------------\x1b[0m\n"); for (std::uint8_t qt(0); qt <= 140; ++qt) { - tmap[qt] = buf[qt]; + this->tmap[qt] = buf[qt]; } } delete[] buf; @@ -115,18 +116,18 @@ bool WozFile::load(const std::string& filePath) { if (chunk_size % 6656) { printf("chunk size is not an even multiple of 6656."); } - c_trks = chunk_size / 6656; - printf("Count of tracks: 0x%02X\n", c_trks); - if (c_trks > 141) { + this->c_trks = chunk_size / 6656; + printf("Count of tracks: 0x%02X\n", this->c_trks); + if (this->c_trks > 141) { printf("Error: cannot handle more than 141 tracks."); throw "Error: cannot handle more than 141 tracks"; } - for (std::uint8_t t(0); t < c_trks; ++t) { + for (std::uint8_t t(0); t < this->c_trks; ++t) { printf("track 0x%02X:\n", t); std::uint16_t usedBytes = *(std::uint16_t*)&buf[t*6656+6646+0]; printf(" used bytes: 0x%0X\n", usedBytes); - trk_bits[t] = *(std::uint16_t*)&buf[t*6656+6646+2]; - printf(" count of bits: 0x%0X\n", trk_bits[t]); + this->trk_bits[t] = *(std::uint16_t*)&buf[t*6656+6646+2]; + printf(" count of bits: 0x%0X\n", this->trk_bits[t]); std::uint16_t spliceBit = *(std::uint16_t*)&buf[t*6656+6646+4]; if (spliceBit == 0xFFFFu) { printf(" no splice information exists\n"); @@ -146,7 +147,7 @@ bool WozFile::load(const std::string& filePath) { } printf("\n"); for (int i(0); i < 6646; ++i) { - trks[t][i] = *base++; + this->trks[t][i] = *base++; } } delete[] buf; @@ -251,15 +252,6 @@ static std::uint8_t cb(std::uint8_t bit) { return 255u; // should never happen } -static void dumpQTrack(std::uint8_t currentQuarterTrack) { - if (currentQuarterTrack % 4) { - const std::uint8_t hundredths((currentQuarterTrack%4) * 25); - printf(" Reading from <---------- track 0x%02X +.%02d\n", currentQuarterTrack/4, hundredths); - } else { - printf(" Reading from <---------- track 0x%02X\n", currentQuarterTrack/4); - } -} - /* * Rotate the floppy disk by one bit. * In real life we don't care what track we're one, but for the @@ -274,14 +266,7 @@ void WozFile::rotateOneBit(std::uint8_t currentQuarterTrack) { return; // there's no disk to rotate } - // In WOZ track image, bits (i.e., magnetic field reversal on disk, - // or lack thereof) are packed into bytes, high bit to low bit. - // Really, it's the stream of bits returned by the MC3470 (but also - // possibly with random bits zeroed out). -// std::uint16_t before = (this->byt*8+bc(this->bit)); -// printf("disk at bit: %d\n", this->byt*8+bc(this->bit)); - - // Move to next bit: + // Move to next bit this->bit >>= 1; // If we hit end of this byte, move on to beginning of next byte @@ -290,78 +275,81 @@ void WozFile::rotateOneBit(std::uint8_t currentQuarterTrack) { this->bit = 0x80u; } + // this is an empty track, so any of the following byte/bit + // adjustments don't apply now (they will be handled the + // next time we hit a non-empty track) if (this->tmap[currentQuarterTrack] == 0xFFu) { return; } + // If we changed tracks since the last time we were called, + // we may need to adjust the rotational position. The new + // position will be at the same relative position as the + // previous, based on each track's length (tracks can be of + // different lengths in the WOZ image). if (currentQuarterTrack != this->lastQuarterTrack) { double oldLen = this->trk_bits[this->tmap[this->lastQuarterTrack]]; double newLen = this->trk_bits[this->tmap[currentQuarterTrack]]; - double dif = newLen/oldLen; - if (dif < -0.000001 || 0.000001 < dif) { -// dumpQTrack(currentQuarterTrack); -// printf(" new track: bit pos: %d ", this->byt*8+bc(this->bit)); - std::uint16_t newBit = (this->byt*8+bc(this->bit)) * dif; + double ratio = newLen/oldLen; + if (!(fabs(1-ratio) < 0.0001f)) { + std::uint16_t newBit = (this->byt*8+bc(this->bit)) * ratio; this->byt = newBit / 8; this->bit = cb(newBit % 8); -// printf("--> %d\n\n", this->byt*8+bc(this->bit)); } this->lastQuarterTrack = currentQuarterTrack; } - // Check for hitting the end of our track image, + // Check for hitting the end of our track, // and if so, move back to the beginning. // This is how we emulate a circular track on the floppy. if (this->trk_bits[this->tmap[currentQuarterTrack]] <= this->byt*8+bc(this->bit)) { -// printf("\n\n"); this->byt = 0; this->bit = 0x80u; } - -// std::uint16_t after = (this->byt*8+bc(this->bit)); -// if (!(after % 0x100u)) { -// printf("\nnow at bit %04x\n", after); -// } -// if (after != before+1) { -// printf("\nbit changing from %04x to %04x\n", before, after); -// } } + bool WozFile::getBit(std::uint8_t currentQuarterTrack) { if (!isLoaded()) { - printf("\nNO DISK TO READ FROM (will generate random data)\n"); + printf("No disk to read from; will generate random data.\n"); return false; // there's no disk, so no pulse } + if (this->tmap[currentQuarterTrack] == 0xFFu) { -// printf("\nreading (random) from empty q-track: %d\n", currentQuarterTrack); - return false; // track doesn't exist - } - if (this->c_trks <= this->tmap[currentQuarterTrack]) { // shouldn't happen - printf("\nBAD TRACK quarterTrack %d mapped to TRKS index %d (count of tracks: %d)\n", currentQuarterTrack, this->tmap[currentQuarterTrack], this->c_trks); - return false; // track doesn't exist + return false; // empty track + } + + if (this->c_trks <= this->tmap[currentQuarterTrack]) { // shouldn't happen + printf("INVALID quarterTrack %d mapped to TRKS index %d (count of tracks: %d)\n", currentQuarterTrack, this->tmap[currentQuarterTrack], this->c_trks); + return false; } -// if (!(this->byt % 128) && this->bit == 0x01) { -// printf("\ngetBit--> "); -// } -// printf("%02x", this->byt*8+bc(this->bit)); return this->trks[this->tmap[currentQuarterTrack]][this->byt] & this->bit; } -void WozFile::setBit(std::uint8_t currentQuarterTrack) { +void WozFile::setBit(std::uint8_t currentQuarterTrack, bool on) { if (!isLoaded()) { return; // there's no disk to write data to } + if (!this->writable) { return; // write-protected } - if (this->c_trks <= this->tmap[currentQuarterTrack]) { // shouldn't happen + + if (this->c_trks <= this->tmap[currentQuarterTrack]) { return; // TODO track doesn't exist: create a new one } + if (this->tmap[currentQuarterTrack] == 0xFFu) { // track does not exist, create new one } - // TODO extend track length if needed - this->trks[this->tmap[currentQuarterTrack]][this->byt] |= this->bit; + + // TODO extend track length if needed???? + + if (on) { + this->trks[this->tmap[currentQuarterTrack]][this->byt] |= this->bit; + } else { + this->trks[this->tmap[currentQuarterTrack]][this->byt] &= ~this->bit; + } } diff --git a/src/wozfile.h b/src/wozfile.h index 9e43c9b..ae2a8bb 100644 --- a/src/wozfile.h +++ b/src/wozfile.h @@ -59,6 +59,10 @@ class WozFile { std::uint8_t bit; std::uint16_t byt; + // We need to store which track were on, only so we can detect + // a change in tracks, and if so adjust our current byt/bit + // to be proportional with the new track. This is discussed + // in the WOZ file spec. std::uint8_t lastQuarterTrack; void checkForWriteProtection(); @@ -89,7 +93,7 @@ public: void rotateOneBit(std::uint8_t currentQuarterTrack); bool getBit(std::uint8_t currentQuarterTrack); - void setBit(std::uint8_t currentQuarterTrack); + void setBit(std::uint8_t currentQuarterTrack, bool on); }; #endif // WOZFILE_H