diff --git a/ESP32/console_esp32.cpp b/ESP32/console_esp32.cpp index f63c22f..ba5912c 100644 --- a/ESP32/console_esp32.cpp +++ b/ESP32/console_esp32.cpp @@ -110,7 +110,7 @@ void console_esp32::panel_update_thread() int run_mode = current_PSW >> 14; uint16_t current_PC = c->getPC(); - uint32_t full_addr = b->calculate_physical_address(run_mode, current_PC, false, false, true, i_space); + uint32_t full_addr = b->getMMU()->calculate_physical_address(c, run_mode, current_PC, false, false, true, i_space); uint16_t current_instr = b->read_word(current_PC); diff --git a/ESP32/main.ino b/ESP32/main.ino index 890003f..d935d5d 100644 --- a/ESP32/main.ino +++ b/ESP32/main.ino @@ -44,6 +44,7 @@ #include "kw11-l.h" #include "loaders.h" #include "memory.h" +#include "tm-11.h" #include "tty.h" #include "utils.h" #include "version.h" @@ -364,6 +365,9 @@ void setup() { tty_ = new tty(cnsl, b); b->add_tty(tty_); + Serial.println(F("* Adding TM-11")); + b->add_tm11(new tm_11(b)); + Serial.println(F("* Starting KW11-L")); b->getKW11_L()->begin(cnsl); diff --git a/ESP32/platformio.ini b/ESP32/platformio.ini index 7b310ee..890e60c 100644 --- a/ESP32/platformio.ini +++ b/ESP32/platformio.ini @@ -65,3 +65,18 @@ lib_deps = greiman/SdFat@^2.1.2 build_flags = -std=gnu++17 -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99 -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -DCONFIG_SPIRAM_USE_MALLOC build_unflags = -std=gnu++11 extra_scripts = pre:prepare.py + +[env:lolin_s2_mini] +platform = espressif32 +board = lolin_s2_mini +build_src_filter = +<*> -<.git/> -<.svn/> - - - - - - - - +framework = arduino +monitor_speed = 115200 +upload_speed = 1000000 +board_build.filesystem = littlefs +lib_deps = greiman/SdFat@^2.1.2 + adafruit/Adafruit NeoPixel + bblanchon/ArduinoJson@^6.19.4 +build_flags = -std=gnu++17 -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99 -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -DCONFIG_SPIRAM_USE_MALLOC +build_unflags = -std=gnu++11 +extra_scripts = pre:prepare.py diff --git a/RP2040/breakpoint.cpp b/RP2040/breakpoint.cpp new file mode 120000 index 0000000..f2da141 --- /dev/null +++ b/RP2040/breakpoint.cpp @@ -0,0 +1 @@ +../breakpoint.cpp \ No newline at end of file diff --git a/RP2040/breakpoint.h b/RP2040/breakpoint.h new file mode 120000 index 0000000..7375cc3 --- /dev/null +++ b/RP2040/breakpoint.h @@ -0,0 +1 @@ +../breakpoint.h \ No newline at end of file diff --git a/RP2040/breakpoint_and.cpp b/RP2040/breakpoint_and.cpp new file mode 120000 index 0000000..a852384 --- /dev/null +++ b/RP2040/breakpoint_and.cpp @@ -0,0 +1 @@ +../breakpoint_and.cpp \ No newline at end of file diff --git a/RP2040/breakpoint_and.h b/RP2040/breakpoint_and.h new file mode 120000 index 0000000..f2dd9b4 --- /dev/null +++ b/RP2040/breakpoint_and.h @@ -0,0 +1 @@ +../breakpoint_and.h \ No newline at end of file diff --git a/RP2040/breakpoint_memory.cpp b/RP2040/breakpoint_memory.cpp new file mode 120000 index 0000000..d828241 --- /dev/null +++ b/RP2040/breakpoint_memory.cpp @@ -0,0 +1 @@ +../breakpoint_memory.cpp \ No newline at end of file diff --git a/RP2040/breakpoint_memory.h b/RP2040/breakpoint_memory.h new file mode 120000 index 0000000..c5b08ad --- /dev/null +++ b/RP2040/breakpoint_memory.h @@ -0,0 +1 @@ +../breakpoint_memory.h \ No newline at end of file diff --git a/RP2040/breakpoint_or.cpp b/RP2040/breakpoint_or.cpp new file mode 120000 index 0000000..3790a41 --- /dev/null +++ b/RP2040/breakpoint_or.cpp @@ -0,0 +1 @@ +../breakpoint_or.cpp \ No newline at end of file diff --git a/RP2040/breakpoint_or.h b/RP2040/breakpoint_or.h new file mode 120000 index 0000000..196a64e --- /dev/null +++ b/RP2040/breakpoint_or.h @@ -0,0 +1 @@ +../breakpoint_or.h \ No newline at end of file diff --git a/RP2040/breakpoint_parser.cpp b/RP2040/breakpoint_parser.cpp new file mode 120000 index 0000000..881330e --- /dev/null +++ b/RP2040/breakpoint_parser.cpp @@ -0,0 +1 @@ +../breakpoint_parser.cpp \ No newline at end of file diff --git a/RP2040/breakpoint_parser.h b/RP2040/breakpoint_parser.h new file mode 120000 index 0000000..f409493 --- /dev/null +++ b/RP2040/breakpoint_parser.h @@ -0,0 +1 @@ +../breakpoint_parser.h \ No newline at end of file diff --git a/RP2040/breakpoint_register.cpp b/RP2040/breakpoint_register.cpp new file mode 120000 index 0000000..711d9b4 --- /dev/null +++ b/RP2040/breakpoint_register.cpp @@ -0,0 +1 @@ +../breakpoint_register.cpp \ No newline at end of file diff --git a/RP2040/breakpoint_register.h b/RP2040/breakpoint_register.h new file mode 120000 index 0000000..29e0d15 --- /dev/null +++ b/RP2040/breakpoint_register.h @@ -0,0 +1 @@ +../breakpoint_register.h \ No newline at end of file diff --git a/RP2040/mmu.cpp b/RP2040/mmu.cpp new file mode 120000 index 0000000..b83d63b --- /dev/null +++ b/RP2040/mmu.cpp @@ -0,0 +1 @@ +../mmu.cpp \ No newline at end of file diff --git a/RP2040/mmu.h b/RP2040/mmu.h new file mode 120000 index 0000000..cc56dfb --- /dev/null +++ b/RP2040/mmu.h @@ -0,0 +1 @@ +../mmu.h \ No newline at end of file diff --git a/cpu.cpp b/cpu.cpp index 103dc01..6eca7c0 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -18,6 +18,12 @@ #define IS_0(x, wm) ((wm) == wm_byte ? ((x) & 0xff) == 0 : (x) == 0) +// see https://retrocomputing.stackexchange.com/questions/6960/what-was-the-clock-speed-and-ips-for-the-original-pdp-11 +constexpr const double pdp11_clock_cycle = 150; // ns, for the 11/70 +constexpr const double pdp11_MHz = 1000.0 / pdp11_clock_cycle; +constexpr const double pdp11_avg_cycles_per_instruction = (1 + 5) / 2.0; +constexpr const double pdp11_estimated_mips = pdp11_MHz / pdp11_avg_cycles_per_instruction; + cpu::cpu(bus *const b, std::atomic_uint32_t *const event) : b(b), event(event) { reset(); @@ -97,15 +103,15 @@ std::tuple cpu::get_mips_rel_speed(c double mips = t_diff ? instr_count / double(t_diff) : 0; - // see https://retrocomputing.stackexchange.com/questions/6960/what-was-the-clock-speed-and-ips-for-the-original-pdp-11 - constexpr double pdp11_clock_cycle = 150; // ns, for the 11/70 - constexpr double pdp11_MHz = 1000.0 / pdp11_clock_cycle; - constexpr double pdp11_avg_cycles_per_instruction = (1 + 5) / 2.0; - constexpr double pdp11_estimated_mips = pdp11_MHz / pdp11_avg_cycles_per_instruction; - return { mips, mips * 100 / pdp11_estimated_mips, instr_count, t_diff, wait_time }; } +uint32_t cpu::get_effective_run_time(const uint64_t instruction_count) const +{ + // division is to go from ns to ms + return instruction_count * pdp11_avg_cycles_per_instruction * pdp11_clock_cycle / 1000000l; +} + void cpu::add_to_stack_trace(const uint16_t p) { auto da = disassemble(p); diff --git a/cpu.h b/cpu.h index 9c5c40f..56e37eb 100644 --- a/cpu.h +++ b/cpu.h @@ -133,6 +133,8 @@ public: uint64_t get_instructions_executed_count() const; uint64_t get_wait_time() const { return wait_time; } std::tuple get_mips_rel_speed(const std::optional & instruction_count, const std::optional & t_diff_1s) const; + // how many ms would've really passed when executing `instruction_count` instructions + uint32_t get_effective_run_time(const uint64_t instruction_count) const; bool get_debug() const { return debug_mode; } void set_debug(const bool d) { debug_mode = d; stacktrace.clear(); } diff --git a/debugger.cpp b/debugger.cpp index cf57419..d751945 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -78,55 +78,102 @@ std::optional select_nbd_server(console *const cnsl) } #endif -std::optional select_host_file(console *const c) +void start_disk(console *const cnsl) { - for(;;) { -#if defined(linux) - DIR *dir = opendir("."); - if (!dir) { - c->put_string_lf("Cannot access directory"); - return { }; - } - - dirent *dr = nullptr; - while((dr = readdir(dir))) { - struct stat st { }; - - if (stat(dr->d_name, &st) == 0) - c->put_string_lf(format("%s\t\t%ld", dr->d_name, st.st_size)); - } - - closedir(dir); -#elif defined(BUILD_FOR_RP2040) - File root = SD.open("/"); - - for(;;) { - auto entry = root.openNextFile(); - if (!entry) - break; - - if (!entry.isDirectory()) { - c->put_string(entry.name()); - c->put_string("\t\t"); - c->put_string_lf(format("%ld", entry.size())); - } - - entry.close(); - } -#elif defined(_WIN32) +#if IS_POSIX + return; #else - SD.ls("/", LS_DATE | LS_SIZE | LS_R); + static bool disk_started = false; + if (disk_started) + return; + +#if defined(ESP32) + cnsl->put_string_lf(format("MISO: %d", int(MISO))); + cnsl->put_string_lf(format("MOSI: %d", int(MOSI))); + cnsl->put_string_lf(format("SCK : %d", int(SCK ))); + cnsl->put_string_lf(format("SS : %d", int(SS ))); + #endif - c->flush_input(); +#if defined(SHA2017) + if (SD.begin(21, SD_SCK_MHZ(10))) + disk_started = true; + else + SD.initErrorHalt(); +#elif !defined(BUILD_FOR_RP2040) + if (SD.begin(SS, SD_SCK_MHZ(15))) + disk_started = true; + else { + auto err = SD.sdErrorCode(); + if (err) + cnsl->put_string_lf(format("SDerror: 0x%x, data: 0x%x", err, SD.sdErrorData())); + else + cnsl->put_string_lf("Failed to initialize SD card"); + } +#endif +#endif +} - std::string selected_file = c->read_line("Enter filename (or empty to abort): "); +void ls_l(console *const cnsl) +{ + start_disk(cnsl); + +#if IS_POSIX || defined(_WIN32) + cnsl->put_string_lf("Files in current directory: "); +#else + cnsl->put_string_lf("Files on SD-card:"); +#endif + +#if defined(linux) + DIR *dir = opendir("."); + if (!dir) { + cnsl->put_string_lf("Cannot access directory"); + return; + } + + dirent *dr = nullptr; + while((dr = readdir(dir))) { + struct stat st { }; + + if (stat(dr->d_name, &st) == 0) + cnsl->put_string_lf(format("%s\t\t%ld", dr->d_name, st.st_size)); + } + + closedir(dir); +#elif defined(BUILD_FOR_RP2040) + File root = SD.open("/"); + + for(;;) { + auto entry = root.openNextFile(); + if (!entry) + break; + + if (!entry.isDirectory()) { + cnsl->put_string(entry.name()); + cnsl->put_string("\t\t"); + cnsl->put_string_lf(format("%ld", entry.size())); + } + + entry.close(); + } +#elif defined(_WIN32) +#else + SD.ls("/", LS_DATE | LS_SIZE | LS_R); +#endif +} + +std::optional select_host_file(console *const cnsl) +{ + for(;;) { + cnsl->flush_input(); + + std::string selected_file = cnsl->read_line("Enter filename (or empty to abort): "); if (selected_file.empty()) return { }; - c->put_string("Opening file: "); - c->put_string_lf(selected_file.c_str()); + cnsl->put_string("Opening file: "); + cnsl->put_string_lf(selected_file.c_str()); bool can_open_file = false; @@ -143,41 +190,19 @@ std::optional select_host_file(console *const c) if (can_open_file) return selected_file; - c->put_string_lf("open failed"); + cnsl->put_string_lf("open failed"); + + ls_l(cnsl); } } // disk image files -std::optional select_disk_file(console *const c) +std::optional select_disk_file(console *const cnsl) { -#if IS_POSIX || defined(_WIN32) - c->put_string_lf("Files in current directory: "); -#else - c->put_string_lf(format("MISO: %d", int(MISO))); - c->put_string_lf(format("MOSI: %d", int(MOSI))); - c->put_string_lf(format("SCK : %d", int(SCK ))); - c->put_string_lf(format("SS : %d", int(SS ))); - - c->put_string_lf("Files on SD-card:"); - -#if defined(SHA2017) - if (!SD.begin(21, SD_SCK_MHZ(10))) - SD.initErrorHalt(); -#elif !defined(BUILD_FOR_RP2040) - if (!SD.begin(SS, SD_SCK_MHZ(15))) { - auto err = SD.sdErrorCode(); - if (err) - c->put_string_lf(format("SDerror: 0x%x, data: 0x%x", err, SD.sdErrorData())); - else - c->put_string_lf("Failed to initialize SD card"); - - return { }; - } -#endif -#endif + start_disk(cnsl); for(;;) { - auto selected_file = select_host_file(c); + auto selected_file = select_host_file(cnsl); if (selected_file.has_value() == false) break; @@ -189,8 +214,8 @@ std::optional select_disk_file(console *const c) #endif if (!temp->begin(false)) { - c->put_string("Cannot use: "); - c->put_string_lf(selected_file.value().c_str()); + cnsl->put_string("Cannot use: "); + cnsl->put_string_lf(selected_file.value().c_str()); delete temp; @@ -987,6 +1012,19 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto continue; } + else if (parts[0] == "bic" && parts.size() == 2) { + auto rc = load_tape(b, parts[1].c_str()); + if (rc.has_value()) { + c->setPC(rc.value()); + + cnsl->put_string_lf("BIC/LDA file loaded"); + } + else { + cnsl->put_string_lf("BIC/LDA failed to load"); + } + + continue; + } else if (parts[0] == "lt") { if (parts.size() == 2) tm11_load_tape(cnsl, b, parts[1]); @@ -995,6 +1033,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto continue; } + else if (cmd == "dir" || cmd == "ls") { + ls_l(cnsl); + + continue; + } else if (cmd == "ult") { tm11_unload_tape(b); @@ -1038,28 +1081,30 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto " follows v/p (virtual/physical), all octal values, mmr0-3 and psw are", " registers", "trace/t - toggle tracing", - "setll - set loglevel: terminal,file", - "setsl - set syslog target: requires a hostname and a loglevel", + "setll x,y - set loglevel: terminal,file", + "setsl x,y - set syslog target: requires a hostname and a loglevel", "turbo - toggle turbo mode (cannot be interrupted)", "debug - enable CPU debug mode", "bt - show backtrace - need to enable debug first", - "strace - start tracing from address - invoke without address to disable", - "trl - set trace run-level (0...3), empty for all", + "strace x - start tracing from address - invoke without address to disable", + "trl x - set trace run-level (0...3), empty for all", "regdump - dump register contents", "mmudump - dump MMU settings (PARs/PDRs)", - "mmures - resolve a virtual address", + "mmures x - resolve a virtual address", "qi - show queued interrupts", - "setpc - set PC to value", - "setmem - set memory (a=) to value (v=), both in octal, one byte", - "toggle - set switch (s=, 0...15 (decimal)) of the front panel to state (t=, 0 or 1)", + "setpc x - set PC to value", + "setmem ... - set memory (a=) to value (v=), both in octal, one byte", + "toggle ... - set switch (s=, 0...15 (decimal)) of the front panel to state (t=, 0 or 1)", "cls - clear screen", - "lt - load tape (parameter is filename)", + "dir - list files", + "bic x - run BIC/LDA file", + "lt x - load tape (parameter is filename)", "ult - unload tape", "stats - show run statistics", - "ramsize - set ram size (page count (8 kB))", - "bl - set bootload (rl02 or rk05)", + "ramsize x - set ram size (page count (8 kB), decimal)", + "bl - set bootloader (rl02 or rk05)", #if IS_POSIX - "ser - serialize state to a file", + "ser x - serialize state to a file", // "dser - deserialize state from a file", #endif "dp - disable panel", @@ -1068,11 +1113,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto "startnet - start network", "chknet - check network status", #if defined(CONSOLE_SERIAL_RX) - "serspd - set serial speed in bps (8N1 are default)", + "serspd x - set serial speed in bps (8N1 are default)", #endif #endif "cfgdisk - configure disk", - "log - log a message to the logfile", + "log ... - log a message to the logfile", nullptr }; diff --git a/kw11-l.cpp b/kw11-l.cpp index 2d23054..8a102a1 100644 --- a/kw11-l.cpp +++ b/kw11-l.cpp @@ -62,28 +62,40 @@ void kw11_l::reset() lf_csr = 0; } +void kw11_l::do_interrupt() +{ + set_lf_crs_b7(); + + if (get_lf_crs() & 64) + b->getCpu()->queue_interrupt(6, 0100); +} + void kw11_l::operator()() { set_thread_name("kek:kw-11l"); TRACE("Starting KW11-L thread"); + uint64_t prev_cycle_count = b->getCpu()->get_instructions_executed_count(); + uint64_t interval_prev_cycle_count = prev_cycle_count; + while(!stop_flag) { if (*cnsl->get_running_flag()) { - set_lf_crs_b7(); - - if (get_lf_crs() & 64) - b->getCpu()->queue_interrupt(6, 0100); + myusleep(1000000 / 100); // 100 Hz - // TODO: depending on cpu cycles processed -#if defined(ESP32) - myusleep(1000000 / 20); // 50ms -#else - myusleep(1000000 / 50); // 20ms -#endif + uint64_t current_cycle_count = b->getCpu()->get_instructions_executed_count(); + uint32_t took_ms = b->getCpu()->get_effective_run_time(current_cycle_count - prev_cycle_count); + + if (took_ms >= 1000 / 50 || current_cycle_count - interval_prev_cycle_count == 0) { + do_interrupt(); + + prev_cycle_count = current_cycle_count; + } + + interval_prev_cycle_count = current_cycle_count; } else { - myusleep(1000000 / 10); // 100ms + myusleep(1000000 / 10); // 10 Hz } } diff --git a/kw11-l.h b/kw11-l.h index 8c2f8f7..a0398b4 100644 --- a/kw11-l.h +++ b/kw11-l.h @@ -28,6 +28,8 @@ private: uint8_t get_lf_crs(); void set_lf_crs_b7(); + void do_interrupt(); + public: kw11_l(bus *const b); virtual ~kw11_l(); diff --git a/mmu.cpp b/mmu.cpp index a4d64c8..65c341a 100644 --- a/mmu.cpp +++ b/mmu.cpp @@ -48,6 +48,11 @@ uint16_t mmu::read_par(const uint32_t a, const int run_mode) return t; } +void mmu::setMMR0_as_is(uint16_t value) +{ + MMR0 = value; +} + void mmu::setMMR0(uint16_t value) { value &= ~(3 << 10); // bit 10 & 11 always read as 0 @@ -350,7 +355,7 @@ uint32_t mmu::calculate_physical_address(cpu *const c, const int run_mode, const temp |= d << 4; - setMMR0(temp); + setMMR0_as_is(temp); TRACE("MMR0: %06o", temp); } @@ -389,7 +394,7 @@ uint32_t mmu::calculate_physical_address(cpu *const c, const int run_mode, const temp &= ~(3 << 5); temp |= run_mode << 5; - setMMR0(temp); + setMMR0_as_is(temp); } if (is_write) @@ -427,7 +432,7 @@ uint32_t mmu::calculate_physical_address(cpu *const c, const int run_mode, const temp &= ~(1 << 4); temp |= d << 4; - setMMR0(temp); + setMMR0_as_is(temp); } if (is_write) diff --git a/mmu.h b/mmu.h index d79b8dc..27074cf 100644 --- a/mmu.h +++ b/mmu.h @@ -99,6 +99,7 @@ public: uint16_t getMMR3() const { return MMR3; } uint16_t getMMR(int nr) const { const uint16_t *const mmrs[] { &MMR0, &MMR1, &MMR2, &MMR3 }; return *mmrs[nr]; } + void setMMR0_as_is(uint16_t value); void setMMR0(const uint16_t value); void setMMR1(const uint16_t value); void setMMR2(const uint16_t value); diff --git a/rk05.cpp b/rk05.cpp index a30d407..1cd9e22 100644 --- a/rk05.cpp +++ b/rk05.cpp @@ -62,17 +62,17 @@ uint16_t rk05::read_word(const uint16_t addr) if (addr == RK05_DS) { // 0177400 setBit(registers[reg], 11, true); // disk on-line - setBit(registers[reg], 8, true); // sector ok - setBit(registers[reg], 7, true); // drive ready - setBit(registers[reg], 6, true); // seek ready - setBit(registers[reg], 4, true); // heads in position + setBit(registers[reg], 8, true); // sector ok + setBit(registers[reg], 7, true); // drive ready + setBit(registers[reg], 6, true); // seek ready + setBit(registers[reg], 4, true); // heads in position } else if (addr == RK05_ERROR) // 0177402 registers[reg] = 0; else if (addr == RK05_CS) { // 0177404 setBit(registers[reg], 15, false); // clear error setBit(registers[reg], 14, false); // clear hard error - setBit(registers[reg], 7, true); // controller ready + setBit(registers[reg], 7, true); // controller ready } uint16_t vtemp = registers[reg]; @@ -139,45 +139,56 @@ void rk05::write_word(const uint16_t addr, const uint16_t v) if (func == 0) { // controller reset TRACE("RK05 invoke %d (controller reset)", func); + registers[(RK05_ERROR - RK05_BASE) / 2] = 0; } else if (func == 1) { // write *disk_write_acitivity = true; TRACE("RK05 drive %d position sec %d surf %d cyl %d, reclen %zo, WRITE to %o, mem: %o", device, sector, surface, cylinder, reclen, diskoffb, memoff); - uint32_t work_reclen = reclen; - uint32_t work_memoff = memoff; - uint32_t work_diskoffb = diskoffb; + if (device >= fhs.size()) { + registers[(RK05_ERROR - RK05_BASE) / 2] |= 128; // non existing disk + registers[(RK05_CS - RK05_BASE) / 2] |= 3 << 14; // an error occured + } + else { + uint32_t work_reclen = reclen; + uint32_t work_memoff = memoff; + uint32_t work_diskoffb = diskoffb; - assert(sizeof(xfer_buffer) == 512); + assert(sizeof(xfer_buffer) == 512); - while(work_reclen > 0) { - uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), work_reclen); - work_reclen -= cur; + while(work_reclen > 0) { + uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), work_reclen); + work_reclen -= cur; - for(size_t i=0; ireadUnibusByte(work_memoff++); + for(size_t i=0; ireadUnibusByte(work_memoff++); - if (!fhs.at(device)->write(work_diskoffb, cur, xfer_buffer, 512)) - DOLOG(ll_error, true, "RK05(%d) write error %s to %u len %u", device, strerror(errno), work_diskoffb, cur); + if (!fhs.at(device)->write(work_diskoffb, cur, xfer_buffer, 512)) { + DOLOG(ll_error, true, "RK05(%d) write error %s to %u len %u", device, strerror(errno), work_diskoffb, cur); + registers[(RK05_ERROR - RK05_BASE) / 2] |= 32; // non existing sector + registers[(RK05_CS - RK05_BASE) / 2] |= 3 << 14; // an error occured + break; + } - work_diskoffb += cur; + work_diskoffb += cur; - if (v & 2048) - TRACE("RK05 inhibit BA increase"); - else - update_bus_address(cur); + if (v & 2048) + TRACE("RK05 inhibit BA increase"); + else + update_bus_address(cur); - if (++sector >= 12) { - sector = 0; - if (++surface >= 2) { - surface = 0; - cylinder++; + if (++sector >= 12) { + sector = 0; + if (++surface >= 2) { + surface = 0; + cylinder++; + } } } - } - registers[(RK05_DA - RK05_BASE) / 2] = sector | (surface << 4) | (cylinder << 5); + registers[(RK05_DA - RK05_BASE) / 2] = sector | (surface << 4) | (cylinder << 5); + } *disk_write_acitivity = false; } @@ -186,40 +197,48 @@ void rk05::write_word(const uint16_t addr, const uint16_t v) TRACE("RK05 drive %d position sec %d surf %d cyl %d, reclen %zo, READ from %o, mem: %o", device, sector, surface, cylinder, reclen, diskoffb, memoff); - uint32_t temp_diskoffb = diskoffb; + if (device >= fhs.size()) { + registers[(RK05_ERROR - RK05_BASE) / 2] |= 128; // non existing disk + registers[(RK05_CS - RK05_BASE) / 2] |= 3 << 14; // an error occured + } + else { + uint32_t temp_diskoffb = diskoffb; - uint32_t temp_reclen = reclen; - uint32_t p = memoff; - while(temp_reclen > 0) { - uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), temp_reclen); + uint32_t temp_reclen = reclen; + uint32_t p = memoff; + while(temp_reclen > 0) { + uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), temp_reclen); - if (!fhs.at(device)->read(temp_diskoffb, cur, xfer_buffer, 512)) { - DOLOG(ll_error, true, "RK05 read error %s from %u len %u", strerror(errno), temp_diskoffb, cur); - break; - } + if (!fhs.at(device)->read(temp_diskoffb, cur, xfer_buffer, 512)) { + DOLOG(ll_error, true, "RK05 read error %s from %u len %u", strerror(errno), temp_diskoffb, cur); + registers[(RK05_ERROR - RK05_BASE) / 2] |= 32; // non existing sector + registers[(RK05_CS - RK05_BASE) / 2] |= 3 << 14; // an error occured + break; + } - temp_diskoffb += cur; + temp_diskoffb += cur; - for(uint32_t i=0; iwriteUnibusByte(p++, xfer_buffer[i]); + for(uint32_t i=0; iwriteUnibusByte(p++, xfer_buffer[i]); - if ((v & 2048) == 0) - update_bus_address(2); - } + if ((v & 2048) == 0) + update_bus_address(2); + } - temp_reclen -= cur; + temp_reclen -= cur; - if (++sector >= 12) { - sector = 0; + if (++sector >= 12) { + sector = 0; - if (++surface >= 2) { - surface = 0; - cylinder++; + if (++surface >= 2) { + surface = 0; + cylinder++; + } } } - } - registers[(RK05_DA - RK05_BASE) / 2] = sector | (surface << 4) | (cylinder << 5); + registers[(RK05_DA - RK05_BASE) / 2] = sector | (surface << 4) | (cylinder << 5); + } *disk_read_acitivity = false; } diff --git a/tm-11.cpp b/tm-11.cpp index e41eb67..20eba66 100644 --- a/tm-11.cpp +++ b/tm-11.cpp @@ -1,4 +1,4 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #include