fix drive motor on cancels pending off; fix LSS timing during switch changes; fix GUI disk dirty flag

This commit is contained in:
Christopher Mosher 2018-12-27 15:03:46 -05:00
parent 117d4af8ef
commit ee420e1c02
6 changed files with 87 additions and 35 deletions

View File

@ -63,17 +63,17 @@ Apple2::~Apple2()
} }
void Apple2::tick() void Apple2::tick() {
{
this->slts.tick();
this->cpu.tick(); this->cpu.tick();
this->video.tick(); this->slts.tick();
this->paddles.tick(); this->video.tick();
this->speaker.tick(); this->paddles.tick();
this->cassette.tick(); this->speaker.tick();
this->cassette.tick();
if (this->revision > 0) if (this->revision > 0) {
this->powerUpReset.tick(); this->powerUpReset.tick();
}
} }
void Apple2::powerOn() void Apple2::powerOn()

View File

@ -25,6 +25,7 @@ DiskController::DiskController(ScreenImage& gui, int slot, bool lss13):
currentDrive(&this->drive1), currentDrive(&this->drive1),
load(false), load(false),
write(false), write(false),
ioStepped(false),
lssp6rom(lss13), lssp6rom(lss13),
seq(0x20), // gotta start somewhere seq(0x20), // gotta start somewhere
t(0) { t(0) {
@ -39,6 +40,8 @@ unsigned char DiskController::io(const unsigned short addr, const unsigned char
const unsigned char q = (addr & 0x000E) >> 1; const unsigned char q = (addr & 0x000E) >> 1;
const bool on = (addr & 0x0001); const bool on = (addr & 0x0001);
// printf("Q%d<--%s\n", q, on?"ON":"OFF");
switch (q) { switch (q) {
case 0: case 0:
case 1: // TODO if phase-1 is on, it also acts as write-protect (UA2, 9-8) case 1: // TODO if phase-1 is on, it also acts as write-protect (UA2, 9-8)
@ -57,19 +60,22 @@ unsigned char DiskController::io(const unsigned short addr, const unsigned char
break; break;
case 6: case 6:
this->load = on; this->load = on;
// TODO when to do these GUI updates?
// this->gui.setDirty(this->slot,getCurrentDriveNumber(),true);
break; break;
case 7: case 7:
this->write = on; this->write = on;
break; break;
} }
// if (this->dataRegister == 0xD5u) { if (this->write && !this->load) {
// printf("\n"); this->gui.setDirty(this->slot,getCurrentDriveNumber(),true);
// } }
// if (this->dataRegister & 0x80u) {
// printf("%02X ", this->dataRegister); // UA2, 9-23, Figure 9.12
// } // 2 LSS cycles need to happen AFTER setting the Qx switch, and
// BEFORE reading LSS's update of the data register
this->ioStepped = false;
tick();
this->ioStepped = true; // flag that we ran it already
return on ? d : this->dataRegister; return on ? d : this->dataRegister;
} }
@ -81,8 +87,13 @@ unsigned char DiskController::io(const unsigned short addr, const unsigned char
* (When the motor is on, that is.) * (When the motor is on, that is.)
*/ */
void DiskController::tick() { void DiskController::tick() {
if (this->ioStepped) { // if we already ran it, above in io(), skip here
this->ioStepped = false;
return;
}
this->gui.setIO(this->slot, getCurrentDriveNumber(), this->motor.isOn()); this->gui.setIO(this->slot, getCurrentDriveNumber(), this->motor.isOn());
if (!this->motor.isOn()) { if (!this->motor.isOn()) {
this->ioStepped = false;
return; return;
} }
this->motor.tick(); // only need to send tick when motor is powered on this->motor.tick(); // only need to send tick when motor is powered on
@ -90,7 +101,6 @@ void DiskController::tick() {
rotateCurrentDisk(); rotateCurrentDisk();
// run two LSS cycles = 2MHz // run two LSS cycles = 2MHz
stepLss(); stepLss();
// pulse lasts only 500 nanoseconds (1 LSS clock cycle), so clear it now: // pulse lasts only 500 nanoseconds (1 LSS clock cycle), so clear it now:
this->currentDrive->clearPulse(); this->currentDrive->clearPulse();

View File

@ -42,6 +42,7 @@ private:
bool load; // Q6 bool load; // Q6
bool write; // Q7 bool write; // Q7
bool ioStepped;
/* /*
* Only one drive's motor can be on at a time, * Only one drive's motor can be on at a time,

View File

@ -35,6 +35,10 @@ bool DriveMotor::isOn() const {
void DriveMotor::power(bool on) { void DriveMotor::power(bool on) {
if (on) { if (on) {
this->on = true; this->on = true;
if (this->pendingTicks > 0) {
this->pendingTicks = 0;
// printf("MOTOR: cancel pending power off\n");
}
// printf("MOTOR: power on\n"); // printf("MOTOR: power on\n");
} else { } else {
// delay power-off by about one second (a little longer, for momentum) // delay power-off by about one second (a little longer, for momentum)

View File

@ -51,6 +51,12 @@ WozFile::WozFile() : tmap(0) {
WozFile::~WozFile() { WozFile::~WozFile() {
} }
static void print_compat(std::uint16_t compat, std::uint16_t mask, const char *name) {
if (compat & mask) {
printf(" Apple %s\n", name);
}
}
bool WozFile::load(const std::string& filePath) { bool WozFile::load(const std::string& filePath) {
std::ifstream in(filePath.c_str(),std::ios::binary|std::ios::in); std::ifstream in(filePath.c_str(),std::ios::binary|std::ios::in);
if (!in.is_open()) { if (!in.is_open()) {
@ -111,6 +117,23 @@ bool WozFile::load(const std::string& filePath) {
this->creator = std::string((char*)buf+5, 32); this->creator = std::string((char*)buf+5, 32);
printf("Creator: \"%.32s\"\n", buf+5); printf("Creator: \"%.32s\"\n", buf+5);
this->timing = buf[39]; this->timing = buf[39];
printf("Timing: %d/8 microseconds per bit\n", this->timing);
std::uint16_t compat = *((std::uint16_t*)buf+40);
printf("Campatible hardware: ");
if (!compat) {
printf("unknown\n");
} else {
printf("\n");
print_compat(compat, 0x0001, "][");
print_compat(compat, 0x0002, "][ plus");
print_compat(compat, 0x0004, "//e");
print_compat(compat, 0x0008, "//c");
print_compat(compat, 0x0010, "//e (enhanced)");
print_compat(compat, 0x0020, "IIGS");
print_compat(compat, 0x0040, "IIc Plus");
print_compat(compat, 0x0080, "///");
print_compat(compat, 0x0100, "/// plus");
}
delete[] buf; delete[] buf;
} }
break; break;
@ -118,13 +141,13 @@ bool WozFile::load(const std::string& filePath) {
this->tmap = new std::uint8_t[chunk_size]; this->tmap = new std::uint8_t[chunk_size];
in.read((char*)this->tmap, chunk_size); in.read((char*)this->tmap, chunk_size);
this->initalQtrack = 0; this->initialQtrack = 0;
while (this->initalQtrack < chunk_size && this->tmap[this->initalQtrack] == 0xFFu) { while (this->initialQtrack < chunk_size && this->tmap[this->initialQtrack] == 0xFFu) {
++this->initalQtrack; ++this->initialQtrack;
} }
if (this->initalQtrack == chunk_size) { if (this->initialQtrack == chunk_size) {
this->initalQtrack = 0xFFu; this->initialQtrack = 0xFFu;
printf("Could not find any initial track (%02X).\n", this->initalQtrack); printf("Could not find any initial track (%02X).\n", this->initialQtrack);
} }
this->finalQtrack = chunk_size-1; this->finalQtrack = chunk_size-1;
@ -147,10 +170,10 @@ bool WozFile::load(const std::string& filePath) {
printf("TMAP track 0x%02X : TRKS track index 0x%02X", t/100, tmap[qt]); printf("TMAP track 0x%02X : TRKS track index 0x%02X", t/100, tmap[qt]);
} }
printf("\x1b[0m"); printf("\x1b[0m");
if (qt == this->initalQtrack && qt == this->finalQtrack) { if (qt == this->initialQtrack && qt == this->finalQtrack) {
printf(" <-- lone track"); printf(" <-- lone track");
} else if (qt == this->initalQtrack) { } else if (qt == this->initialQtrack) {
printf(" <-- inital track"); printf(" <-- initial track");
} else if (qt == this->finalQtrack) { } else if (qt == this->finalQtrack) {
printf(" <-- final track"); printf(" <-- final track");
} }
@ -177,8 +200,9 @@ bool WozFile::load(const std::string& filePath) {
if (ts.blockCount) { if (ts.blockCount) {
printf("TRK index %02X: start byte in BITS %08x; %08x bytes; %08x bits ", qt, ts.blockFirst<<9, ts.blockCount<<9, ts.bitCount); printf("TRK index %02X: start byte in BITS %08x; %08x bytes; %08x bits ", qt, ts.blockFirst<<9, ts.blockCount<<9, ts.bitCount);
this->trk_bits[qt] = ts.bitCount; this->trk_bits[qt] = ts.bitCount;
this->trk[qt] = new std::uint8_t[ts.blockCount<<9]; this->trk_byts[qt] = ts.blockCount<<9;
memcpy(this->trk[qt], buf+C_QTRACK*8+(ts.blockFirst<<9), ts.blockCount<<9); this->trk[qt] = new std::uint8_t[this->trk_byts[qt]];
memcpy(this->trk[qt], buf+C_QTRACK*8+(ts.blockFirst<<9), this->trk_byts[qt]);
printf("(" printf("("
BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN
BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN
@ -272,12 +296,22 @@ void WozFile::save() {
if (isWriteProtected() || !isLoaded()) { if (isWriteProtected() || !isLoaded()) {
return; return;
} }
// std::ofstream out(filePath.c_str(),std::ios::binary); std::ofstream out(filePath.c_str(), std::ios::binary);
// TODO SAVE FILE!
// out.flush();
// out.close();
// this->modified = false; // TODO: SAVE WOZ 2.0 format FILE PROPERLY!
for (std::uint8_t qt(0); qt < C_QTRACK; ++qt) {
// staight dump of track FOR DEBUGGING ONLY
if (this->trk[qt]) {
printf("dumping q-track: %02X, %08X bytes\n", qt, this->trk_byts[qt]);
out.write(reinterpret_cast<char*>(this->trk[qt]), this->trk_byts[qt]);
}
}
out.flush();
out.close();
// TODO: this->modified = false;
} }
void WozFile::unload() { void WozFile::unload() {
@ -413,6 +447,7 @@ void WozFile::setBit(std::uint8_t currentQuarterTrack, bool on) {
return; // write-protected return; // write-protected
} }
// printf("%c",(on?'1':'0')); fflush(stdout);
if (on) { if (on) {
this->trk[this->tmap[currentQuarterTrack]][this->byt] |= this->bit; this->trk[this->tmap[currentQuarterTrack]][this->byt] |= this->bit;
} else { } else {

View File

@ -59,7 +59,7 @@ class WozFile {
// map of quarter-tracks from T00.00 through T39.75, values are indexes into trk // map of quarter-tracks from T00.00 through T39.75, values are indexes into trk
std::uint8_t* tmap; std::uint8_t* tmap;
// first actual quarter-track (e.g., 0 for normal 35-track disk), or 0xFF if no tracks // first actual quarter-track (e.g., 0 for normal 35-track disk), or 0xFF if no tracks
std::uint8_t initalQtrack; std::uint8_t initialQtrack;
// last actual quarter-track (e.g., 136 for normal 35-track disk), or 0xFF if no tracks // last actual quarter-track (e.g., 136 for normal 35-track disk), or 0xFF if no tracks
std::uint8_t finalQtrack; std::uint8_t finalQtrack;
@ -67,6 +67,8 @@ class WozFile {
std::uint8_t* trk[C_QTRACK]; std::uint8_t* trk[C_QTRACK];
// count of bits in each track // count of bits in each track
std::uint32_t trk_bits[C_QTRACK]; std::uint32_t trk_bits[C_QTRACK];
// count of allocated bytes
std::uint16_t trk_byts[C_QTRACK];
// bit and byt together represent the rotational position // bit and byt together represent the rotational position
// of the floppy disk. // of the floppy disk.