fix drive motor on cancels pending off; fix LSS timing during switch changes; fix GUI disk dirty flag
This commit is contained in:
parent
117d4af8ef
commit
ee420e1c02
|
@ -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()
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue