fix position on track switch; small refactor; comments

This commit is contained in:
Christopher A. Mosher 2018-12-18 15:44:06 -05:00
parent 8a393af531
commit 745592a68c
9 changed files with 132 additions and 159 deletions

View File

@ -4,7 +4,7 @@ METASOURCES=AUTO
bin_PROGRAMS=epple2 bin_PROGRAMS=epple2
AM_CXXFLAGS=-std=c++14 -Wall -O3 AM_CXXFLAGS=-std=c++11 -Wall -O3
AM_CPPFLAGS=$(all_includes) AM_CPPFLAGS=$(all_includes)
epple2_LDFLAGS=$(all_libraries) epple2_LDFLAGS=$(all_libraries)

View File

@ -58,33 +58,14 @@ unsigned char DiskController::io(const unsigned short addr, const unsigned char
break; break;
case 6: case 6:
this->load = on; this->load = on;
// TODO use LSS // TODO when to do these GUI updates?
// if (on && this->write && writing) {
// set(data);
// this->gui.setIO(this->slot,getCurrentDriveNumber(),this->motorOn); // this->gui.setIO(this->slot,getCurrentDriveNumber(),this->motorOn);
// this->gui.setDirty(this->slot,getCurrentDriveNumber(),true); // this->gui.setDirty(this->slot,getCurrentDriveNumber(),true);
// } else if (!(on || this->write)) {
// data = get();
// }
break; break;
case 7: case 7:
this->write = on; this->write = on;
// TODO use LSS
// if (this->currentDrive->isWriteProtected()) {
// data |= 0x80;
// } else {
// data &= 0x7F;
// }
break; break;
} }
// if (this->motorOn) {
// if (this->dataRegister == 0xD5) {
// printf("\ndata register --> ");
// }
// if (this->dataRegister & 0x80) {
// printf("%02x", this->dataRegister);
// }
// }
return on ? d : this->dataRegister; return on ? d : this->dataRegister;
} }
@ -108,10 +89,10 @@ void DiskController::tick() {
} }
void DiskController::rotateCurrentDisk() { void DiskController::rotateCurrentDisk() {
++t; ++this->t;
if (t < 0 || 4 <= t) { // 4us interval between bits if (4 <= this->t) { // 4us interval between bits
this->currentDrive->rotateDiskOneBit(); // (will also generate a read-pulse when it reads a 1-bit) this->currentDrive->rotateDiskOneBit(); // (will also generate a read-pulse when it reads a 1-bit)
t = 0; this->t = 0;
} else { } else {
// clear the read pulse (to make it last only 1us) // clear the read pulse (to make it last only 1us)
this->currentDrive->clearPulse(); this->currentDrive->clearPulse();
@ -121,7 +102,6 @@ void DiskController::rotateCurrentDisk() {
void DiskController::stepLss() { void DiskController::stepLss() {
std::uint8_t adr = this->write<<3 | this->load<<2 | (this->dataRegister>>7)<<1 | this->currentDrive->readPulse(); 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); 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; this->seq = cmd & 0xF0u;
// LSS command functions (UA2, 9-15, Table 9.3) // LSS command functions (UA2, 9-15, Table 9.3)

View File

@ -101,7 +101,6 @@ public:
// we see more than three (emulating the MC3470, see UA2, 9-11) // we see more than three (emulating the MC3470, see UA2, 9-11)
++cContiguousZeroBits; ++cContiguousZeroBits;
if (3 < cContiguousZeroBits) { if (3 < cContiguousZeroBits) {
// if (cContiguousZeroBits == 4) printf("\n<GENERATING RANDOM BIT(S).....>\n");
if (randomBit()) { if (randomBit()) {
this->pulse = true; this->pulse = true;
} }
@ -117,23 +116,8 @@ public:
} }
void writeBit(bool on) { 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 #endif

View File

@ -34,28 +34,28 @@ static void setbth(std::uint8_t lssrom[], std::uint8_t x, std::uint8_t both) {
lssrom[x] = both; lssrom[x] = both;
} }
static void showua2seq(std::uint8_t lssrom[], std::uint8_t seq) { //static void showua2seq(std::uint8_t lssrom[], std::uint8_t seq) {
printf("| %02x %02x %02x %02x | %02x %02x %02x %02x", // printf("| %02x %02x %02x %02x | %02x %02x %02x %02x",
lssrom[seq|0x9], // lssrom[seq|0x9],
lssrom[seq|0xB], // lssrom[seq|0xB],
lssrom[seq|0xD], // lssrom[seq|0xD],
lssrom[seq|0xF], // lssrom[seq|0xF],
lssrom[seq|0x8], // lssrom[seq|0x8],
lssrom[seq|0xA], // lssrom[seq|0xA],
lssrom[seq|0xC], // lssrom[seq|0xC],
lssrom[seq|0xE] // lssrom[seq|0xE]
); // );
printf("| %02x %02x %02x %02x | %02x %02x %02x %02x |\n", // printf("| %02x %02x %02x %02x | %02x %02x %02x %02x |\n",
lssrom[seq|0x1], // lssrom[seq|0x1],
lssrom[seq|0x0], // lssrom[seq|0x0],
lssrom[seq|0x3], // lssrom[seq|0x3],
lssrom[seq|0x2], // lssrom[seq|0x2],
lssrom[seq|0x5], // lssrom[seq|0x5],
lssrom[seq|0x4], // lssrom[seq|0x4],
lssrom[seq|0x7], // lssrom[seq|0x7],
lssrom[seq|0x6] // lssrom[seq|0x6]
); // );
} //}
LSS::LSS(bool use13SectorDos32LSS): LSS::LSS(bool use13SectorDos32LSS):
use13SectorDos32LSS(use13SectorDos32LSS) { use13SectorDos32LSS(use13SectorDos32LSS) {
@ -175,15 +175,15 @@ LSS::LSS(bool use13SectorDos32LSS):
setseq(lss13rom,0x23u,0x30u); setseq(lss13rom,0x23u,0x30u);
setseq(lss13rom,0x33u,0xD0u); setseq(lss13rom,0x33u,0xD0u);
if (use13SectorDos32LSS) { // if (use13SectorDos32LSS) {
for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) { // for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) {
showua2seq(lss13rom,seq); // showua2seq(lss13rom,seq);
} // }
} else { // } else {
for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) { // for (unsigned int seq = 0; seq < 0x100u; seq += 0x10u) {
showua2seq(lssrom,seq); // showua2seq(lssrom,seq);
} // }
} // }
} }
LSS::~LSS() { LSS::~LSS() {

View File

@ -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) 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) 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) if (((rand() >> 9) & 0x1F) == 5)
on = !on; on = !on;

View File

@ -29,9 +29,9 @@ private:
unsigned short nextinit; unsigned short nextinit;
void putBytesUntilFull(int bit, int pat); void putBytesUntilFull(int bit, int pat);
void ramPattern1(const int bit) throw (done); void ramPattern1(const int bit);
void ramPattern2(const int bit) throw (done); void ramPattern2(const int bit);
void putn(const int c, bool on, const int bit) throw (done); void putn(const int c, bool on, const int bit);
public: public:
RAMInitializer(Memory& mem); RAMInitializer(Memory& mem);

View File

@ -26,9 +26,15 @@
* @author Chris Mosher * @author Chris Mosher
*/ */
/* /*
mags ps magval mags ps magval
3210 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 0001 0 1
0011 1 3 0011 1 3
0010 2 2 0010 2 2
@ -38,17 +44,19 @@ mags ps magval
1000 6 8 1000 6 8
1001 7 9 1001 7 9
(strange, but defined) strange, but still defined
1011 0 B 1011 0 B
0111 2 7 0111 2 7
1110 4 E 1110 4 E
1101 6 D 1101 6 D
(undefined, i.e., no movement) all off (no movement)
0000 ? 0 0000 ? 0
undefined
0101 ? 5 // <-- TODO pick one at random? 0101 ? 5 // <-- TODO pick one at random?
1010 ? A // <-- 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 "steppermotor.h"
#include "util.h" #include "util.h"
@ -76,7 +84,7 @@ void StepperMotor::setMagnet(const unsigned char magnet, const bool on) {
} }
const char newPos = mapMagPos[this->mags]; const char newPos = mapMagPos[this->mags];
char d; char d = 0;
if (newPos >= 0) { if (newPos >= 0) {
d = calcDeltaPos(this->pos,newPos); d = calcDeltaPos(this->pos,newPos);
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) else if (this->quarterTrack > QTRACK_MAX)
this->quarterTrack = QTRACK_MAX; this->quarterTrack = QTRACK_MAX;
} }
std::cout << " ARM: magnet " << (unsigned int)magnet << " " << (on ? "on " : "off" ); // std::cout << " ARM: magnet " << (unsigned int)magnet << " " << (on ? "on " : "off" );
std::cout << " [" << // std::cout << " [" <<
((mags&1)?"*":".") << // ((mags&1)?"*":".") <<
((mags&2)?"*":".") << // ((mags&2)?"*":".") <<
((mags&4)?"*":".") << // ((mags&4)?"*":".") <<
((mags&8)?"*":".") << // ((mags&8)?"*":".") <<
"]"; // "]";
if (d != 0) { // if (d != 0) {
std::cout << " track " << std::hex << (unsigned int)(this->quarterTrack >> 2); // std::cout << " track " << std::hex << (unsigned int)(this->quarterTrack >> 2);
int fract = this->quarterTrack & 3; // int fract = this->quarterTrack & 3;
if (fract != 0) { // if (fract != 0) {
std::cout << (fract == 1 ? " +.25" : fract == 2 ? " +.5" : " +.75"); // std::cout << (fract == 1 ? " +.25" : fract == 2 ? " +.5" : " +.75");
} // }
} // }
std::cout << std::endl; // 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);
// }
//}

View File

@ -22,6 +22,7 @@
#include <istream> #include <istream>
#include <ostream> #include <ostream>
#include <fstream> #include <fstream>
#include <cmath>
WozFile::WozFile() : lastQuarterTrack(0) { WozFile::WozFile() : lastQuarterTrack(0) {
unload(); unload();
@ -73,8 +74,8 @@ bool WozFile::load(const std::string& filePath) {
printf("INFO version %d\n", *buf); printf("INFO version %d\n", *buf);
five_25 = (buf[1]==1); five_25 = (buf[1]==1);
printf("Disk type: %s\n", five_25 ? "5.25" : buf[1]==2 ? "3.5" : "?"); printf("Disk type: %s\n", five_25 ? "5.25" : buf[1]==2 ? "3.5" : "?");
writable = !(buf[2]==1); this->writable = !(buf[2]==1);
printf("Write protected?: %s\n", writable ? "No" : "Yes"); printf("Write protected?: %s\n", this->writable ? "No" : "Yes");
printf("Imaged with cross-track sync?: %s\n", buf[3]==1 ? "Yes" : "No"); 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("MC3470 fake bits removed?: %s\n", buf[4]==1 ? "Yes" : "No");
printf("Creator: \"%.32s\"\n", buf+5); printf("Creator: \"%.32s\"\n", buf+5);
@ -103,7 +104,7 @@ bool WozFile::load(const std::string& filePath) {
} }
printf("\x1b[31;47m-------------------------------------------\x1b[0m\n"); printf("\x1b[31;47m-------------------------------------------\x1b[0m\n");
for (std::uint8_t qt(0); qt <= 140; ++qt) { for (std::uint8_t qt(0); qt <= 140; ++qt) {
tmap[qt] = buf[qt]; this->tmap[qt] = buf[qt];
} }
} }
delete[] buf; delete[] buf;
@ -115,18 +116,18 @@ bool WozFile::load(const std::string& filePath) {
if (chunk_size % 6656) { if (chunk_size % 6656) {
printf("chunk size is not an even multiple of 6656."); printf("chunk size is not an even multiple of 6656.");
} }
c_trks = chunk_size / 6656; this->c_trks = chunk_size / 6656;
printf("Count of tracks: 0x%02X\n", c_trks); printf("Count of tracks: 0x%02X\n", this->c_trks);
if (c_trks > 141) { if (this->c_trks > 141) {
printf("Error: cannot handle more than 141 tracks."); printf("Error: cannot handle more than 141 tracks.");
throw "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); printf("track 0x%02X:\n", t);
std::uint16_t usedBytes = *(std::uint16_t*)&buf[t*6656+6646+0]; std::uint16_t usedBytes = *(std::uint16_t*)&buf[t*6656+6646+0];
printf(" used bytes: 0x%0X\n", usedBytes); printf(" used bytes: 0x%0X\n", usedBytes);
trk_bits[t] = *(std::uint16_t*)&buf[t*6656+6646+2]; this->trk_bits[t] = *(std::uint16_t*)&buf[t*6656+6646+2];
printf(" count of bits: 0x%0X\n", trk_bits[t]); printf(" count of bits: 0x%0X\n", this->trk_bits[t]);
std::uint16_t spliceBit = *(std::uint16_t*)&buf[t*6656+6646+4]; std::uint16_t spliceBit = *(std::uint16_t*)&buf[t*6656+6646+4];
if (spliceBit == 0xFFFFu) { if (spliceBit == 0xFFFFu) {
printf(" no splice information exists\n"); printf(" no splice information exists\n");
@ -146,7 +147,7 @@ bool WozFile::load(const std::string& filePath) {
} }
printf("\n"); printf("\n");
for (int i(0); i < 6646; ++i) { for (int i(0); i < 6646; ++i) {
trks[t][i] = *base++; this->trks[t][i] = *base++;
} }
} }
delete[] buf; delete[] buf;
@ -251,15 +252,6 @@ static std::uint8_t cb(std::uint8_t bit) {
return 255u; // should never happen 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. * Rotate the floppy disk by one bit.
* In real life we don't care what track we're one, but for the * 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 return; // there's no disk to rotate
} }
// In WOZ track image, bits (i.e., magnetic field reversal on disk, // Move to next bit
// 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:
this->bit >>= 1; this->bit >>= 1;
// If we hit end of this byte, move on to beginning of next byte // 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->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) { if (this->tmap[currentQuarterTrack] == 0xFFu) {
return; 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) { if (currentQuarterTrack != this->lastQuarterTrack) {
double oldLen = this->trk_bits[this->tmap[this->lastQuarterTrack]]; double oldLen = this->trk_bits[this->tmap[this->lastQuarterTrack]];
double newLen = this->trk_bits[this->tmap[currentQuarterTrack]]; double newLen = this->trk_bits[this->tmap[currentQuarterTrack]];
double dif = newLen/oldLen; double ratio = newLen/oldLen;
if (dif < -0.000001 || 0.000001 < dif) { if (!(fabs(1-ratio) < 0.0001f)) {
// dumpQTrack(currentQuarterTrack); std::uint16_t newBit = (this->byt*8+bc(this->bit)) * ratio;
// printf(" new track: bit pos: %d ", this->byt*8+bc(this->bit));
std::uint16_t newBit = (this->byt*8+bc(this->bit)) * dif;
this->byt = newBit / 8; this->byt = newBit / 8;
this->bit = cb(newBit % 8); this->bit = cb(newBit % 8);
// printf("--> %d\n\n", this->byt*8+bc(this->bit));
} }
this->lastQuarterTrack = currentQuarterTrack; 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. // and if so, move back to the beginning.
// This is how we emulate a circular track on the floppy. // This is how we emulate a circular track on the floppy.
if (this->trk_bits[this->tmap[currentQuarterTrack]] <= this->byt*8+bc(this->bit)) { if (this->trk_bits[this->tmap[currentQuarterTrack]] <= this->byt*8+bc(this->bit)) {
// printf("\n<rewinding track here>\n");
this->byt = 0; this->byt = 0;
this->bit = 0x80u; 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) { bool WozFile::getBit(std::uint8_t currentQuarterTrack) {
if (!isLoaded()) { 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 return false; // there's no disk, so no pulse
} }
if (this->tmap[currentQuarterTrack] == 0xFFu) { if (this->tmap[currentQuarterTrack] == 0xFFu) {
// printf("\nreading (random) from empty q-track: %d\n", currentQuarterTrack); return false; // empty track
return false; // track doesn't exist }
}
if (this->c_trks <= this->tmap[currentQuarterTrack]) { // shouldn't happen 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); printf("INVALID 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;
} }
// 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; 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()) { if (!isLoaded()) {
return; // there's no disk to write data to return; // there's no disk to write data to
} }
if (!this->writable) { if (!this->writable) {
return; // write-protected 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 return; // TODO track doesn't exist: create a new one
} }
if (this->tmap[currentQuarterTrack] == 0xFFu) { if (this->tmap[currentQuarterTrack] == 0xFFu) {
// track does not exist, create new one // track does not exist, create new one
} }
// TODO extend track length if needed
// TODO extend track length if needed????
if (on) {
this->trks[this->tmap[currentQuarterTrack]][this->byt] |= this->bit; this->trks[this->tmap[currentQuarterTrack]][this->byt] |= this->bit;
} else {
this->trks[this->tmap[currentQuarterTrack]][this->byt] &= ~this->bit;
}
} }

View File

@ -59,6 +59,10 @@ class WozFile {
std::uint8_t bit; std::uint8_t bit;
std::uint16_t byt; 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; std::uint8_t lastQuarterTrack;
void checkForWriteProtection(); void checkForWriteProtection();
@ -89,7 +93,7 @@ public:
void rotateOneBit(std::uint8_t currentQuarterTrack); void rotateOneBit(std::uint8_t currentQuarterTrack);
bool getBit(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 #endif // WOZFILE_H