diff --git a/apple2e.cpp b/apple2e.cpp index 3bfd7ee..275bcb0 100644 --- a/apple2e.cpp +++ b/apple2e.cpp @@ -204,14 +204,15 @@ struct SoftSwitch int set_address; int read_address; bool read_also_changes; - bool enabled = false; + bool enabled; bool implemented; - SoftSwitch(const char* name_, int clear, int on, int read, bool read_changes, vector& s, bool implemented_ = false) : + SoftSwitch(const char* name_, int clear, int on, int read, bool read_changes, vector& s, bool initialValue, bool implemented_ = false) : name(name_), clear_address(clear), set_address(on), read_address(read), read_also_changes(read_changes), + enabled(initialValue), implemented(implemented_) { s.push_back(this); @@ -304,7 +305,7 @@ and a ".dsk" floppy image is only 143360 bytes. */ constexpr int sectorSize = 256; constexpr int sectorsPerTrack = 16; -constexpr int tracksPerFloppy = 35; +// constexpr int tracksPerFloppy = 35; const uint8_t sectorHeader[21] = { @@ -349,7 +350,7 @@ constexpr size_t nybblizedTrackSize = trackGapSize + sectorsPerTrack * nybblized void nybblizeSector(int trackIndex, int sectorIndex, const uint8_t *sectorBytes, uint8_t *sectorNybblized) { - memset(sectorNybblized, 0xFF, nybblizedSectorSize); // Doesn't matter if 00s or FFs... + // memset(sectorNybblized, 0xFF, nybblizedSectorSize); // Doesn't matter if 00s or FFs... uint8_t *p = sectorNybblized; @@ -381,7 +382,7 @@ void nybblizeSector(int trackIndex, int sectorIndex, const uint8_t *sectorBytes, memcpy(p + 0x56, sectorBytes, 256); // XOR the data block with itself, offset by one byte, - // creating a 343rd byte which is used as a cheksum. + // creating a 343rd byte which is used as a checksum. p[342] = 0x00; @@ -397,7 +398,6 @@ void nybblizeSector(int trackIndex, int sectorIndex, const uint8_t *sectorBytes, // Done with the nybblization, now for the epilogue... memcpy(p, sectorFooter, sizeof(sectorFooter)); - // p += 48; } bool nybblizeTrackFromFile(FILE *floppyImageFile, int trackIndex, uint8_t *nybblizedTrack, const int *skew) @@ -421,7 +421,9 @@ bool nybblizeTrackFromFile(FILE *floppyImageFile, int trackIndex, uint8_t *nybbl return false; } - nybblizeSector(trackIndex, sectorIndex, sectorBytes, nybblizedTrack + trackGapSize + sectorIndex * nybblizedSectorSize); + uint8_t *sectorDest = nybblizedTrack + trackGapSize + sectorIndex * nybblizedSectorSize; + + nybblizeSector(trackIndex, sectorIndex, sectorBytes, sectorDest); } return true; } @@ -536,8 +538,11 @@ struct DISKIIboard : board_base uint8_t readNextTrackByte() { - if(headMode != READ || !driveMotorEnabled[driveSelected] || !floppyPresent[driveSelected]) + // bool dataValid = (headMode != READ || !driveMotorEnabled[driveSelected] || !floppyPresent[driveSelected]); + bool dataValid = floppyPresent[driveSelected]; + if(!dataValid) { return 0x00; + } if(trackBytesOutOfDate) { readDriveTrack(); @@ -546,6 +551,10 @@ struct DISKIIboard : board_base uint8_t data = trackBytes[trackByteIndex]; + if(false) { + printf("read track %d byte %d (sector %ld byte %ld), yields %d (%02X)\n", nybblizedTrackIndex / 2, trackByteIndex, trackByteIndex / floppy::nybblizedSectorSize, trackByteIndex % floppy::nybblizedSectorSize, data, data); + } + trackByteIndex = (trackByteIndex + 1) % floppy::nybblizedTrackSize; return data; @@ -569,6 +578,7 @@ struct DISKIIboard : board_base nybblizedTrackIndex = currentTrackNumber[driveSelected]; nybblizedDriveIndex = driveSelected; + trackByteIndex = 0; return true; } @@ -663,11 +673,13 @@ struct DISKIIboard : board_base if(debug & DEBUG_FLOPPY) printf("floppy select first drive\n"); driveSelected = 0; trackBytesOutOfDate = true; + data = 0; return true; } else if(addr == SELECT + 1) { if(debug & DEBUG_FLOPPY) printf("floppy select second drive\n"); driveSelected = 1; trackBytesOutOfDate = true; + data = 0; return true; } else if(addr == ENABLE) { if(debug & DEBUG_FLOPPY) printf("floppy switch off\n"); @@ -675,6 +687,7 @@ struct DISKIIboard : board_base floppy_activity(driveSelected, false); // go disable reading // disable other drive? + data = 0; return true; } else if(addr == ENABLE + 1) { if(debug & DEBUG_FLOPPY) printf("floppy switch on\n"); @@ -682,6 +695,7 @@ struct DISKIIboard : board_base floppy_activity(driveSelected, true); // go enable reading // disable other drive? + data = 0; return true; } if(debug & DEBUG_WARN) printf("DISK II unhandled read from %04X (%s)\n", addr, io.at(addr).c_str()); @@ -690,8 +704,8 @@ struct DISKIIboard : board_base } virtual void reset(void) { - driveMotorEnabled[0] = false; // Is this safe? - driveMotorEnabled[1] = false; // Is this safe? + driveMotorEnabled[0] = false; // Is this what the drive HW does? + driveMotorEnabled[1] = false; // Is this what the drive HW does? driveSelected = 0; trackBytesOutOfDate = true; floppy_activity(0, false); @@ -740,7 +754,7 @@ void initialize_audio_waveform() } int hires_blanking_address_base[262]; -extern int hires_visible_address_base[262]; +extern const int hires_visible_address_base[262]; static void generate_hires_scanout_addresses() __attribute__((constructor)); void generate_hires_scanout_addresses() @@ -762,7 +776,7 @@ int get_hires_scanout_address(int byte_in_frame) return 0x2000 + (hires_visible_address_base[line_in_frame] + byte_in_line - 25) % 0x2000; } -static int text_blanking_address_base[] = +const static int text_blanking_address_base[] = { 0x1468, 0x14E8, @@ -799,7 +813,7 @@ static int text_blanking_address_base[] = 0x17E0, // last text line is actually scanned 14 times so add another row }; -static int text_visible_address_base[] = +const static int text_visible_address_base[] = { 0x0400, 0x0480, @@ -855,20 +869,19 @@ struct MAINboard : board_base vector switches; SoftSwitch* switches_by_address[256]; - // SoftSwitch(const char* name_, int clear, int on, int read, bool read_changes, vector& s, bool implemented_ = false) : // Inside the Apple //e, page 379 - SoftSwitch CXROM {"CXROM", 0xC006, 0xC007, 0xC015, false, switches, true}; - SoftSwitch STORE80 {"STORE80", 0xC000, 0xC001, 0xC018, false, switches, true}; - SoftSwitch RAMRD {"RAMRD", 0xC002, 0xC003, 0xC013, false, switches, true}; - SoftSwitch RAMWRT {"RAMWRT", 0xC004, 0xC005, 0xC014, false, switches, true}; - SoftSwitch ALTZP {"ALTZP", 0xC008, 0xC009, 0xC016, false, switches, true}; - SoftSwitch C3ROM {"C3ROM", 0xC00A, 0xC00B, 0xC017, false, switches, true}; - SoftSwitch ALTCHAR {"ALTCHAR", 0xC00E, 0xC00F, 0xC01E, false, switches, true}; - SoftSwitch VID80 {"VID80", 0xC00C, 0xC00D, 0xC01F, false, switches, true}; - SoftSwitch TEXT {"TEXT", 0xC050, 0xC051, 0xC01A, true, switches, true}; - SoftSwitch MIXED {"MIXED", 0xC052, 0xC053, 0xC01B, true, switches, true}; - SoftSwitch PAGE2 {"PAGE2", 0xC054, 0xC055, 0xC01C, true, switches, true}; - SoftSwitch HIRES {"HIRES", 0xC056, 0xC057, 0xC01D, true, switches, true}; + SoftSwitch SLOTCXROM {"SLOTCXROM", 0xC007, 0xC006, 0xC015, false, switches, false, true}; + SoftSwitch STORE80 {"STORE80", 0xC000, 0xC001, 0xC018, false, switches, false, true}; + SoftSwitch RAMRD {"RAMRD", 0xC002, 0xC003, 0xC013, false, switches, false, true}; + SoftSwitch RAMWRT {"RAMWRT", 0xC004, 0xC005, 0xC014, false, switches, false, true}; + SoftSwitch ALTZP {"ALTZP", 0xC008, 0xC009, 0xC016, false, switches, false, true}; + SoftSwitch C3ROM {"C3ROM", 0xC00A, 0xC00B, 0xC017, false, switches, false, true}; + SoftSwitch ALTCHAR {"ALTCHAR", 0xC00E, 0xC00F, 0xC01E, false, switches, false, true}; + SoftSwitch VID80 {"VID80", 0xC00C, 0xC00D, 0xC01F, false, switches, false, true}; + SoftSwitch TEXT {"TEXT", 0xC050, 0xC051, 0xC01A, true, switches, false, true}; + SoftSwitch MIXED {"MIXED", 0xC052, 0xC053, 0xC01B, true, switches, false, true}; + SoftSwitch PAGE2 {"PAGE2", 0xC054, 0xC055, 0xC01C, true, switches, false, true}; + SoftSwitch HIRES {"HIRES", 0xC056, 0xC057, 0xC01D, true, switches, false, true}; vector regions; std::array read_regions_by_page; @@ -910,10 +923,10 @@ struct MAINboard : board_base enabled_func always_disabled = []{return false;}; bool internal_C800_ROM_selected = false; - backed_region rom_C100 = {"rom_C100", 0xC100, 0x0200, ROM, ®ions, [&]{return CXROM;}, always_disabled}; - backed_region rom_C300 = {"rom_C300", 0xC300, 0x0100, ROM, ®ions, [&]{return CXROM || (!CXROM && !C3ROM);}, always_disabled}; - backed_region rom_C400 = {"rom_C400", 0xC400, 0x0400, ROM, ®ions, [&]{return CXROM;}, always_disabled}; - backed_region rom_C800 = {"rom_C800", 0xC800, 0x0800, ROM, ®ions, [&]{return CXROM || (!CXROM && !C3ROM && internal_C800_ROM_selected);}, always_disabled}; + backed_region rom_C100 = {"rom_C100", 0xC100, 0x0200, ROM, ®ions, [&]{return !SLOTCXROM;}, always_disabled}; + backed_region rom_C300 = {"rom_C300", 0xC300, 0x0100, ROM, ®ions, [&]{return !SLOTCXROM || (SLOTCXROM && !C3ROM);}, always_disabled}; + backed_region rom_C400 = {"rom_C400", 0xC400, 0x0400, ROM, ®ions, [&]{return !SLOTCXROM;}, always_disabled}; + backed_region rom_C800 = {"rom_C800", 0xC800, 0x0800, ROM, ®ions, [&]{return !SLOTCXROM || (SLOTCXROM && !C3ROM && internal_C800_ROM_selected);}, always_disabled}; backed_region rom_CXXX_default = {"rom_CXXX_default", 0xC100, 0x0F00, ROM, ®ions, [&]{return true;}, always_disabled}; enabled_func read_from_aux_ram = [&]{return RAMRD;}; @@ -962,18 +975,46 @@ struct MAINboard : board_base backed_region hires_page2 = {"hires_page2", 0x4000, 0x2000, RAM, ®ions, read_from_main_ram, write_to_main_ram}; backed_region hires_page2x = {"hires_page2x", 0x4000, 0x2000, RAM, ®ions, read_from_aux_ram, write_to_aux_ram}; - set ignore_mmio = {0xC058, 0xC05A, 0xC05D, 0xC05F, 0xC061, 0xC062}; + set ignore_mmio = { + 0xC058, // CLRAN0 through Apple //e + 0xC05A, // CLRAN1 through Apple //e + 0xC05D, // SETAN2 through Apple //e + 0xC05F, // SETAN3 through Apple //e + 0xC060, // TAPEIN through Apple //e + 0xC061, // RDBTN0 Open Apple on and after Apple //e + 0xC062, // BUTN1 Solid Apple on and after Apple //e + }; set banking_read_switches = { - 0xC080, 0xC081, 0xC082, 0xC083, 0xC084, 0xC085, 0xC086, 0xC087, - 0xC088, 0xC089, 0xC08A, 0xC08B, 0xC08C, 0xC08D, 0xC08E, 0xC08F, + 0xC080, + 0xC081, + 0xC082, + 0xC083, + 0xC084, + 0xC085, + 0xC086, + 0xC087, + 0xC088, + 0xC089, + 0xC08A, + 0xC08B, + 0xC08C, + 0xC08D, + 0xC08E, + 0xC08F, }; set banking_write_switches = { - 0xC006, 0xC007, - 0xC000, 0xC001, - 0xC002, 0xC003, - 0xC004, 0xC005, - 0xC008, 0xC009, - 0xC00A, 0xC00B, + 0xC006, + 0xC007, + 0xC000, + 0xC001, + 0xC002, + 0xC003, + 0xC004, + 0xC005, + 0xC008, + 0xC009, + 0xC00A, + 0xC00B, }; deque keyboard_buffer; @@ -1100,7 +1141,7 @@ struct MAINboard : board_base // Partially from Apple //e Technical Reference // XXX need to double-check these against the actual hardware ALTZP.enabled = false; - CXROM.enabled = false; + SLOTCXROM.enabled = false; RAMRD.enabled = false; RAMWRT.enabled = false; C3ROM.enabled = false; @@ -1191,14 +1232,14 @@ struct MAINboard : board_base data = sw->enabled ? 0x80 : 0x00; if(debug & DEBUG_SWITCH) printf("Read status of %s = %02X\n", sw->name.c_str(), data); return true; - } else if(sw->read_also_changes && addr == sw->set_address) { + } else if(sw->read_also_changes && (addr == sw->set_address)) { if(!sw->implemented) { printf("%s ; set is unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); } data = result; sw->enabled = true; if(debug & DEBUG_SWITCH) printf("Set %s\n", sw->name.c_str()); post_soft_switch_mode_change(); return true; - } else if(sw->read_also_changes && addr == sw->clear_address) { + } else if(sw->read_also_changes && (addr == sw->clear_address)) { if(!sw->implemented) { printf("%s ; unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); } data = result; sw->enabled = false; @@ -1588,7 +1629,7 @@ string read_bus_and_disassemble(bus_frontend &bus, int pc) buf[1] = bus.read(pc + 1); buf[2] = bus.read(pc + 2); buf[3] = bus.read(pc + 3); - tie(bytes, dis) = disassemble_6502(pc - 1, buf); + tie(bytes, dis) = disassemble_6502(pc, buf); return dis; } @@ -1975,6 +2016,8 @@ int main(int argc, char **argv) clk_t cpu_previous_cycles = 0; averaged_sequence cpu_speed_averaged; + std::set breakpoints; + while(1) { if(!debugging) { @@ -2049,6 +2092,7 @@ int main(int argc, char **argv) } else { + int steps = 1; printf("> "); char line[512]; if(fgets(line, sizeof(line) - 1, stdin) == NULL) { @@ -2059,6 +2103,20 @@ int main(int argc, char **argv) printf("continuing\n"); debugging = false; continue; + } else if(strncmp(line, "step", 4) == 0) { + if(line[5] != '\0') { + steps = atoi(line + 5); + printf("run for %d steps\n", steps); + } + } else if(strncmp(line, "break", 5) == 0) { + if(line[6] != '\0') { + uint16_t addr = strtoul(line + 5, NULL, 0); + printf("breakpoint at 0x%04X\n", addr); + breakpoints.insert(addr); + } else { + printf("expected breakpoint address\n"); + } + continue; } else if(strcmp(line, "fast") == 0) { printf("run flat out\n"); run_fast = true; @@ -2086,31 +2144,48 @@ int main(int argc, char **argv) cpu.nmi(); continue; } - if(debug & DEBUG_DECODE) { - string dis = read_bus_and_disassemble(bus, + for(int i = 0; i < steps; i++) { + if(debug & DEBUG_DECODE) { + string dis = read_bus_and_disassemble(bus, #ifdef SUPPORT_FAKE_6502 - use_fake6502 ? pc : + use_fake6502 ? pc : #endif - cpu.pc); - printf("%s\n", dis.c_str()); - } - -#ifdef SUPPORT_FAKE_6502 - if(use_fake6502) { - clockticks6502 = 0; - step6502(); - clk.add_cpu_cycles(clockticks6502); - } else -#endif - { - cpu.cycle(); - if(debug & DEBUG_STATE) - print_cpu_state(cpu); - } - mainboard->sync(); + cpu.pc); + printf("%s\n", dis.c_str()); + } + +#ifdef SUPPORT_FAKE_6502 + if(use_fake6502) { + clockticks6502 = 0; + step6502(); + clk.add_cpu_cycles(clockticks6502); + } else +#endif + { + cpu.cycle(); + if(debug & DEBUG_STATE) + print_cpu_state(cpu); + } + if((i % 10000) == 0) { + mainboard->sync(); + } + if((i % 100000) == 0) { + APPLE2Einterface::iterate(mode_history, clk.clock_cpu, 1.023); + mode_history.clear(); + } + + uint16_t pcnow = +#ifdef SUPPORT_FAKE_6502 + use_fake6502 ? pc : +#endif + cpu.pc; + printf("%04X, %zd\n", pcnow, breakpoints.count(pcnow)); + if(breakpoints.count(pcnow) > 0) { + printf("break at 0x%4X\n", pcnow); + break; + } + } - APPLE2Einterface::iterate(mode_history, clk.clock_cpu, 1.023); - mode_history.clear(); } } @@ -2118,7 +2193,7 @@ int main(int argc, char **argv) return 0; } -int hires_visible_address_base[262] = +const int hires_visible_address_base[262] = { 0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x0080, 0x0480, 0x0880, 0x0C80, 0x1080, 0x1480, 0x1880, 0x1C80,