diff --git a/ESP32/platformio.ini b/ESP32/platformio.ini index 84f18b8..11392d1 100644 --- a/ESP32/platformio.ini +++ b/ESP32/platformio.ini @@ -17,8 +17,8 @@ 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 -build_unflags = -std=gnu++11 +build_flags = -std=gnu++2a -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99 +build_unflags = -std=gnu++11 -std=gnu++17 extra_scripts = pre:prepare.py [env:SHA2017-badge] @@ -32,8 +32,8 @@ 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 -DSHA2017 -ggdb3 -D_GLIBCXX_USE_C99 -ISHAdisplay/Arduino/libraries/epd2in9-badge -ISHAdisplay/Arduino/libraries/epdpaint -ISHAdisplay/components/epaper-29-dke -build_unflags = -std=gnu++11 +build_flags = -std=gnu++2a -DESP32=1 -DSHA2017 -ggdb3 -D_GLIBCXX_USE_C99 -ISHAdisplay/Arduino/libraries/epd2in9-badge -ISHAdisplay/Arduino/libraries/epdpaint -ISHAdisplay/components/epaper-29-dke +build_unflags = -std=gnu++11 -std=gnu++17 upload_protocol = esptool [env:ESP32-ttgo-t-beam] diff --git a/breakpoint_register.cpp b/breakpoint_register.cpp index d0f893a..20b2cc2 100644 --- a/breakpoint_register.cpp +++ b/breakpoint_register.cpp @@ -79,7 +79,7 @@ std::pair > breakpoint_registe return { nullptr, "register: key or value missing" }; auto values_in = parts.at(1); - auto v_parts = split(values_in, ","); + auto v_parts = split(std::move(values_in), ","); std::set values; for(auto & v: v_parts) values.insert(std::stoi(v, nullptr, 8)); diff --git a/bus.cpp b/bus.cpp index 604651a..ef194a2 100644 --- a/bus.cpp +++ b/bus.cpp @@ -287,6 +287,11 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm return 0; } + if (a >= 0172100 && a <= 0172137) { // MM11-LP parity + if (!peek_only) DOLOG(debug, false, "READ-I/O MM11-LP parity (%06o): %o", a, 1); + return 1; + } + if (word_mode == wm_byte) { if (a == ADDR_PSW) { // PSW uint8_t temp = c->getPSW(); @@ -621,6 +626,7 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c uint32_t io_base = get_io_base(); bool is_io = m_offset >= io_base; + [[unlikely]] if (trap_on_failure) { { auto rc = get_trap_action(run_mode, d, apf, is_write); @@ -652,14 +658,14 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c DOLOG(debug, false, "MMR0: %06o", MMR0); if (trap_action == T_TRAP_250) { - DOLOG(debug, false, "Page access %d: trap 0250", access_control); + DOLOG(debug, false, "Page access %d (for virtual address %06o): trap 0250", access_control, a); c->trap(0250); // trap throw 5; } else { // T_ABORT_4 - DOLOG(debug, false, "Page access %d: trap 004", access_control); + DOLOG(debug, false, "Page access %d (for virtual address %06o): trap 004", access_control, a); c->trap(004); // abort @@ -668,6 +674,7 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c } } + [[unlikely]] if (m_offset >= n_pages * 8192l && !is_io) { DOLOG(debug, !peek_only, "bus::calculate_physical_address %o >= %o", m_offset, n_pages * 8192l); DOLOG(debug, false, "TRAP(04) (throw 6) on address %06o", a); @@ -988,6 +995,11 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 return { false }; } + if (a >= 0172100 && a <= 0172137) { // MM11-LP parity + DOLOG(debug, false, "WRITE-I/O MM11-LP parity (%06o): %o", a, value); + return { false }; + } + /// MMU /// // supervisor if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) { diff --git a/cpu.cpp b/cpu.cpp index a714569..8ae9891 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -127,9 +127,9 @@ std::vector > cpu::get_stack_trace() const void cpu::reset() { memset(regs0_5, 0x00, sizeof regs0_5); - memset(sp, 0x00, sizeof sp); - pc = 0; - psw = 0; // 7 << 5; + memset(sp, 0x00, sizeof sp); + pc = 0; + psw = 0; // 7 << 5; fpsr = 0; init_interrupt_queue(); } @@ -149,6 +149,8 @@ uint16_t cpu::getRegister(const int nr, const rm_selection_t mode_selection) con return sp[getPSW_runmode()]; } + assert(nr == 7); + return pc; } @@ -166,6 +168,7 @@ void cpu::setRegister(const int nr, const uint16_t value, const rm_selection_t m sp[getPSW_runmode()] = value; } else { + assert(nr == 7); pc = value; } } @@ -210,6 +213,8 @@ uint16_t cpu::addRegister(const int nr, const rm_selection_t mode_selection, con return sp[getPSW_runmode()] += value; } + assert(nr == 7); + return pc += value; } @@ -222,8 +227,10 @@ void cpu::lowlevel_register_set(const uint8_t set, const uint8_t reg, const uint regs0_5[set][reg] = value; else if (reg == 6) sp[set == 0 ? 0 : 3] = value; - else + else { + assert(reg == 7); pc = value; + } } uint16_t cpu::lowlevel_register_get(const uint8_t set, const uint8_t reg) @@ -237,6 +244,8 @@ uint16_t cpu::lowlevel_register_get(const uint8_t set, const uint8_t reg) if (reg == 6) return sp[set == 0 ? 0 : 3]; + assert(reg == 7); + return pc; } @@ -337,6 +346,8 @@ bool cpu::check_pending_interrupts() const for(uint8_t i=start_level; i < 8; i++) { auto interrupts = queued_interrupts.find(i); + assert(interrupts != queued_interrupts.end()); + if (interrupts->second.empty() == false) return true; } @@ -372,8 +383,8 @@ bool cpu::execute_any_pending_interrupt() uint8_t current_level = getPSW_spl(); // uint8_t start_level = current_level <= 3 ? 0 : current_level + 1; - // uint8_t start_level = current_level + 1; - uint8_t start_level = current_level; + // PDP-11_70_Handbook_1977-78.pdf page 1-5, "processor priority" + uint8_t start_level = current_level + 1; for(uint8_t i=0; i < 8; i++) { auto interrupts = queued_interrupts.find(i); @@ -381,7 +392,7 @@ bool cpu::execute_any_pending_interrupt() if (interrupts->second.empty() == false) { any_queued_interrupts = true; - if (i < start_level) + if (i < start_level) // at leas we know now that there's an interrupt scheduled continue; if (can_trigger == false) { @@ -399,6 +410,9 @@ bool cpu::execute_any_pending_interrupt() trap(v, i, true); + // when there are more interrupts scheduled, invoke them asap + trap_delay = initial_trap_delay; + #if defined(BUILD_FOR_RP2040) xSemaphoreGive(qi_lock); #endif @@ -407,6 +421,9 @@ bool cpu::execute_any_pending_interrupt() } } + if (any_queued_interrupts && trap_delay.has_value() == false) + trap_delay = initial_trap_delay; + #if defined(BUILD_FOR_RP2040) xSemaphoreGive(qi_lock); #endif @@ -789,6 +806,8 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) addToMMR1(g_dst); uint16_t shift = g_dst.value.value() & 077; + DOLOG(debug, true, "shift %06o with %d", R, shift); + bool sign = SIGN(R, wm_word); if (shift == 0) { @@ -812,14 +831,14 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) setPSW_v(SIGN(R, wm_word) != SIGN(oldR, wm_word)); } else { - int shift_n = 64 - shift; - uint32_t sign_extend = sign ? 0x8000 : 0; + int shift_n = 64 - shift; + uint32_t sign_extend = sign ? 0x8000 : 0; - for(int i=0; i>= 1; - R |= sign_extend; - } + for(int i=0; i>= 1; + R |= sign_extend; + } setPSW_v(SIGN(R, wm_word) != SIGN(oldR, wm_word)); } @@ -863,8 +882,7 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) int shift_n = (64 - shift) - 1; // extend sign-bit - if (sign) // convert to unsigned 64b int & extend sign - { + if (sign) { // convert to unsigned 64b int & extend sign R0R1 = (uint64_t(R0R1) | 0xffffffff00000000ll) >> shift_n; setPSW_c(R0R1 & 1); @@ -1555,8 +1573,11 @@ bool cpu::condition_code_operations(const uint16_t instr) } if ((instr & ~7) == 0000230) { // SPLx - int level = instr & 7; - setPSW_spl(level); + if (getPSW_runmode() == 0) { // only in kernel mode + int level = instr & 7; + + setPSW_spl(level); + } // // trap via vector 010 only(?) on an 11/60 and not(?) on an 11/70 // trap(010); @@ -1610,7 +1631,10 @@ bool cpu::misc_operations(const uint16_t instr) { switch(instr) { case 0b0000000000000000: // HALT - *event = EVENT_HALT; + if (getPSW_runmode() == 0) // only in kernel mode + *event = EVENT_HALT; + else + trap(4); return true; case 0b0000000000000001: // WAIT @@ -1664,8 +1688,11 @@ bool cpu::misc_operations(const uint16_t instr) return true; case 0b0000000000000101: // RESET - b->init(); - init_interrupt_queue(); + if (getPSW_runmode() == 0) { // only in kernel mode + b->init(); + + init_interrupt_queue(); + } return true; } @@ -2041,7 +2068,7 @@ std::map > cpu::disassemble(const uint16_t } if (text.empty() && name.empty() == false) - text = name + space + src_text + comma + dst_text.operand; + text = name + space + src_text + comma + dst_text.operand; // TODO: swap for ASH, ASHC if (text.empty() == false && next_word != -1) instruction_words.push_back(next_word); @@ -2307,7 +2334,7 @@ std::map > cpu::disassemble(const uint16_t // PSW std::string psw_str = format("%d%d|%d|%d|%c%c%c%c%c", psw >> 14, (psw >> 12) & 3, (psw >> 11) & 1, (psw >> 5) & 7, psw & 16?'t':'-', psw & 8?'n':'-', psw & 4?'z':'-', psw & 2 ? 'v':'-', psw & 1 ? 'c':'-'); - out.insert({ "psw", { psw_str } }); + out.insert({ "psw", { std::move(psw_str) } }); out.insert({ "psw-value", { format("%06o", psw) } }); // values worked with diff --git a/cpu.h b/cpu.h index e5010f2..c968ca2 100644 --- a/cpu.h +++ b/cpu.h @@ -126,8 +126,6 @@ public: 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; - std::map > get_queued_interrupts() const { return queued_interrupts; } - bool get_debug() const { return debug_mode; } void set_debug(const bool d) { debug_mode = d; stacktrace.clear(); } std::vector > get_stack_trace() const; @@ -141,6 +139,9 @@ public: void init_interrupt_queue(); void queue_interrupt(const uint8_t level, const uint8_t vector); + std::map > get_queued_interrupts() const { return queued_interrupts; } + std::optional get_interrupt_delay_left() const { return trap_delay; } + bool check_if_interrupts_pending() const { return any_queued_interrupts; } void trap(uint16_t vector, const int new_ipl = -1, const bool is_interrupt = false); bool is_it_a_trap() const { return it_is_a_trap; } diff --git a/debugger.cpp b/debugger.cpp index 49f5255..3cac428 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -720,6 +720,14 @@ void show_queued_interrupts(console *const cnsl, cpu *const c) { cnsl->put_string_lf(format("Current level: %d", c->getPSW_spl())); + auto delay = c->get_interrupt_delay_left(); + if (delay.has_value()) + cnsl->put_string_lf(format("Current delay left: %d", delay.value())); + else + cnsl->put_string_lf("No delay"); + + cnsl->put_string_lf(format("Interrupt pending flag: %d", c->check_if_interrupts_pending())); + auto queued_interrupts = c->get_queued_interrupts(); for(auto & level: queued_interrupts) { @@ -1049,6 +1057,37 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto continue; } + else if (parts[0] == "setll" && parts.size() == 2) { + auto ll_parts = split(parts[1], ","); + + if (ll_parts.size() != 2) + cnsl->put_string_lf("Loglevel for either screen or file missing"); + else { + log_level_t ll_screen = parse_ll(ll_parts[0]); + log_level_t ll_file = parse_ll(ll_parts[1]); + + setll(ll_screen, ll_file); + } + } + else if (parts[0] == "setll" && parts.size() == 2) { + auto ll_parts = split(parts[1], ","); + + if (ll_parts.size() != 2) + cnsl->put_string_lf("Loglevel for either screen or file missing"); + else { + log_level_t ll_screen = parse_ll(ll_parts[0]); + log_level_t ll_file = parse_ll(ll_parts[1]); + + setll(ll_screen, ll_file); + } + + continue; + } + else if (parts[0] == "setsl" && parts.size() == 3) { + setloghost(parts.at(1).c_str(), parse_ll(parts[2])); + + continue; + } else if (cmd == "qi") { show_queued_interrupts(cnsl, c); @@ -1087,6 +1126,8 @@ 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", "turbo - toggle turbo mode (cannot be interrupted)", "debug - enable CPU debug mode", "bt - show backtrace - need to enable debug first", diff --git a/disk_backend_nbd.cpp b/disk_backend_nbd.cpp index 3067bc7..7e3c7fd 100644 --- a/disk_backend_nbd.cpp +++ b/disk_backend_nbd.cpp @@ -119,13 +119,14 @@ bool disk_backend_nbd::connect(const bool retry) } } - if (memcmp(nbd_hello.magic1, "NBDMAGIC", 8) != 0) { + if (fd != -1 && memcmp(nbd_hello.magic1, "NBDMAGIC", 8) != 0) { close(fd); fd = -1; DOLOG(warning, true, "disk_backend_nbd::connect: magic invalid"); } - DOLOG(info, false, "NBD size: %u", NTOHLL(nbd_hello.size)); + if (fd != -1) + DOLOG(info, false, "NBD size: %u", NTOHLL(nbd_hello.size)); } while(fd == -1 && retry); diff --git a/log.cpp b/log.cpp index a1ca6ce..a8053a5 100644 --- a/log.cpp +++ b/log.cpp @@ -1,4 +1,4 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #include @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include #include #include "error.h" @@ -16,9 +19,11 @@ static const char *logfile = strdup("/tmp/kek.log"); +static sockaddr_in syslog_ip_addr = { }; +static bool is_file = true; log_level_t log_level_file = warning; log_level_t log_level_screen = warning; -FILE *lfh = nullptr; +FILE *lfh = nullptr; static int lf_uid = -1; static int lf_gid = -1; static bool l_timestamp = true; @@ -30,29 +35,58 @@ int gettid() } #endif -void setlog(const char *lf, const log_level_t ll_file, const log_level_t ll_screen, const bool timestamp) +void setlogfile(const char *const lf, const log_level_t ll_file, const log_level_t ll_screen, const bool timestamp) { if (lfh) fclose(lfh); free((void *)logfile); + is_file = true; + logfile = lf ? strdup(lf) : nullptr; - log_level_file = ll_file; + log_level_file = ll_file; log_level_screen = ll_screen; - l_timestamp = timestamp; + l_timestamp = timestamp; atexit(closelog); } +void setloghost(const char *const host, const log_level_t ll) +{ + inet_aton(host, &syslog_ip_addr.sin_addr); + syslog_ip_addr.sin_port = htons(514); + + is_file = false; + + log_level_file = ll; + + l_timestamp = false; +} + +void setll(const log_level_t ll_file, const log_level_t ll_screen) +{ + log_level_file = ll_file; + log_level_screen = ll_screen; +} + void setloguid(const int uid, const int gid) { lf_uid = uid; lf_gid = gid; } +void send_syslog(const int ll, const std::string & what) +{ + std::string msg = format("<%d>%s", 16 * 8 + ll, what.c_str()); + + int s = socket(AF_INET, SOCK_DGRAM, 0); + (void)sendto(s, msg.c_str(), msg.size(), 0, reinterpret_cast(&syslog_ip_addr), sizeof syslog_ip_addr); + close(s); +} + void closelog() { if (lfh) { @@ -70,7 +104,6 @@ void dolog(const log_level_t ll, const char *fmt, ...) lfh = fopen(logfile, "a+"); if (!lfh) error_exit(true, "Cannot access log-file %s", logfile); - #if !defined(_WIN32) if (lf_uid != -1 && fchown(fileno(lfh), lf_uid, lf_gid) == -1) error_exit(true, "Cannot change logfile (%s) ownership", logfile); @@ -101,29 +134,33 @@ void dolog(const log_level_t ll, const char *fmt, ...) #endif char *ts_str = nullptr; - const char *const ll_names[] = { "debug ", "info ", "warning", "error " }; + const char *const ll_names[] = { "emerg ", "alert ", "crit ", "error ", "warning", "notice ", "info ", "debug ", "none " }; asprintf(&ts_str, "%04d-%02d-%02d %02d:%02d:%02d.%06d] %s ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, int(now % 1000000), ll_names[ll]); + if (ll <= log_level_file && is_file == false) + send_syslog(ll, str); #if !defined(ESP32) - if (ll >= log_level_file && lfh != nullptr) + if (ll <= log_level_file && lfh != nullptr) fprintf(lfh, "%s%s\n", ts_str, str); #endif - if (ll >= log_level_screen) + if (ll <= log_level_screen) printf("%s%s\r\n", ts_str, str); free(ts_str); } else { + if (ll <= log_level_file && is_file == false) + send_syslog(ll, str); #if !defined(ESP32) - if (ll >= log_level_file && lfh != nullptr) + if (ll <= log_level_file && lfh != nullptr) fprintf(lfh, "%s\n", str); #endif - if (ll >= log_level_screen) + if (ll <= log_level_screen) printf("%s\r\n", str); } diff --git a/log.h b/log.h index 1f4003e..c58e9f5 100644 --- a/log.h +++ b/log.h @@ -1,4 +1,4 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #pragma once @@ -8,10 +8,12 @@ #include "config.h" -typedef enum { debug, info, warning, ll_error, none } log_level_t; // TODO ll_ prefix +typedef enum { ll_emerg = 0, ll_alert, ll_critical, ll_error, warning, notice, info, debug, none } log_level_t; // TODO ll_ prefix log_level_t parse_ll(const std::string & str); -void setlog(const char *lf, const log_level_t ll_file, const log_level_t ll_screen, const bool l_timestamp); +void setlogfile(const char *const lf, const log_level_t ll_file, const log_level_t ll_screen, const bool l_timestamp); +void setloghost(const char *const host, const log_level_t ll); +void setll(const log_level_t ll_file, const log_level_t ll_screen); void setloguid(const int uid, const int gid); void closelog(); void dolog(const log_level_t ll, const char *fmt, ...); @@ -22,7 +24,8 @@ void dolog(const log_level_t ll, const char *fmt, ...); #define DOLOG(ll, always, fmt, ...) do { \ extern log_level_t log_level_file, log_level_screen; \ \ - if (always || ll >= log_level_file || ll >= log_level_screen) \ + [[unlikely]] \ + if (always || ll <= log_level_file || ll <= log_level_screen) \ dolog(ll, fmt, ##__VA_ARGS__); \ } while(0) #endif diff --git a/main.cpp b/main.cpp index 98198fa..56ca2fd 100644 --- a/main.cpp +++ b/main.cpp @@ -493,7 +493,7 @@ int main(int argc, char *argv[]) console *cnsl = nullptr; - setlog(logfile, ll_file, ll_screen, timestamp); + setlogfile(logfile, ll_file, ll_screen, timestamp); if (validate_json.empty() == false) return run_cpu_validation(validate_json); @@ -622,11 +622,11 @@ int main(int argc, char *argv[]) delete metrics_thread; } + delete lf; + delete cnsl; delete b; - delete lf; - return 0; } diff --git a/rl02.cpp b/rl02.cpp index 14aa89a..a11a03e 100644 --- a/rl02.cpp +++ b/rl02.cpp @@ -15,9 +15,9 @@ static const char * const regnames[] = { "control status", - "bus address ", - "disk address ", - "multipurpose " + "bus address", + "disk address", + "multipurpose" }; static const char * const commands[] = { @@ -89,7 +89,7 @@ uint16_t rl02::readWord(const uint16_t addr) value = registers[reg]; } - DOLOG(debug, false, "RL02 read \"%s\"/%o: %06o", regnames[reg], addr, value); + DOLOG(debug, false, "RL02: read \"%s\"/%o: %06o", regnames[reg], addr, value); return value; } @@ -112,7 +112,7 @@ void rl02::writeByte(const uint16_t addr, const uint8_t v) uint32_t rl02::get_bus_address() const { - return registers[(RL02_BAR - RL02_BASE) / 2] | (uint32_t((registers[(RL02_CSR - RL02_BASE) / 2] >> 4) & 3) << 16); + return (registers[(RL02_BAR - RL02_BASE) / 2] | (uint32_t((registers[(RL02_CSR - RL02_BASE) / 2] >> 4) & 3) << 16)) & ~1; } void rl02::update_bus_address(const uint32_t a) @@ -137,7 +137,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) { const int reg = (addr - RL02_BASE) / 2; - DOLOG(debug, false, "RL02 write \"%s\"/%06o: %06o", regnames[reg], addr, v); + DOLOG(debug, false, "RL02: write \"%s\"/%06o: %06o", regnames[reg], addr, v); registers[reg] = v; @@ -146,16 +146,24 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) const bool do_exec = !(v & 128); - DOLOG(debug, false, "RL02 set command %d, exec: %d (%s)", command, do_exec, commands[command]); - int device = (v >> 8) & 3; + DOLOG(debug, false, "RL02: device %d, set command %d, exec: %d (%s)", device, command, do_exec, commands[command]); + bool do_int = false; *disk_read_acitivity = true; - if (command == 2) { // get status - registers[(RL02_MPR - RL02_BASE) / 2] = 0; + if (size_t(device) >= fhs.size()) { + DOLOG(info, false, "RL02: PDP11/70 is accessing a not-attached virtual disk %d", device); + + registers[(RL02_CSR - RL02_BASE) / 2] |= (1 << 10) | (1 << 15); + + do_int = true; + } + else if (command == 2) { // get status + mpr[0] = 5 /* lock on */ | (1 << 3) /* brush home */ | (1 << 4) /* heads over disk */ | (head << 6) | (1 << 7) /* RL02 */; + mpr[1] = mpr[0]; } else if (command == 3) { // seek uint16_t temp = registers[(RL02_DAR - RL02_BASE) / 2]; @@ -169,10 +177,10 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) else if (new_track >= rl02_track_count) new_track = rl02_track_count - 1; - DOLOG(debug, false, "RL02: seek from cylinder %d to %d (distance: %d, DAR: %06o)", track, new_track, cylinder_count, temp); + DOLOG(debug, false, "RL02: device %d, seek from cylinder %d to %d (distance: %d, DAR: %06o)", device, track, new_track, cylinder_count, temp); track = new_track; - update_dar(); +// update_dar(); do_int = true; } @@ -181,7 +189,53 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) mpr[1] = 0; // zero mpr[2] = 0; // TODO: CRC - DOLOG(debug, false, "RL02 read header [cylinder: %d, head: %d, sector: %d] %06o", track, head, sector, mpr[0]); + DOLOG(debug, false, "RL02: device %d, read header [cylinder: %d, head: %d, sector: %d] %06o", device, track, head, sector, mpr[0]); + + do_int = true; + } + else if (command == 5) { // write data + uint32_t memory_address = get_bus_address(); + + uint32_t count = (65536l - registers[(RL02_MPR - RL02_BASE) / 2]) * 2; + if (count == 65536) + count = 0; + + uint16_t temp = registers[(RL02_DAR - RL02_BASE) / 2]; + + sector = temp & 63; + head = (temp >> 6) & 1; + track = temp >> 7; + + uint32_t temp_disk_offset = calc_offset(); + + DOLOG(debug, false, "RL02: device %d, write %d bytes (dec) to %d (dec) from %06o (oct) [cylinder: %d, head: %d, sector: %d]", device, count, temp_disk_offset, memory_address, track, head, sector); + + while(count > 0) { + uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count); + + if (!fhs.at(device)->write(temp_disk_offset, cur, xfer_buffer)) { + DOLOG(ll_error, true, "RL02: write error, device %d, disk offset %u, read size %u, cylinder %d, head %d, sector %d", device, temp_disk_offset, cur, track, head, sector); + break; + } + + mpr[0] += count / 2; + + temp_disk_offset += cur; + + count -= cur; + + sector++; + if (sector >= rl02_sectors_per_track) { + sector = 0; + + head++; + if (head >= 2) { + head = 0; + + track++; + } + } + } do_int = true; } @@ -200,7 +254,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) uint32_t temp_disk_offset = calc_offset(); - DOLOG(debug, false, "RL02 read %d bytes (dec) from %d (dec) to %06o (oct) [cylinder: %d, head: %d, sector: %d]", count, temp_disk_offset, memory_address, track, head, sector); + DOLOG(debug, false, "RL02: device %d, read %d bytes (dec) from %d (dec) to %06o (oct) [cylinder: %d, head: %d, sector: %d]", device, count, temp_disk_offset, memory_address, track, head, sector); // update_dar(); @@ -208,7 +262,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count); if (!fhs.at(device)->read(temp_disk_offset, cur, xfer_buffer)) { - DOLOG(ll_error, true, "RL02 read error, device %d, disk offset %u, read size %u, cylinder %d, head %d, sector %d", device, temp_disk_offset, cur, track, head, sector); + DOLOG(ll_error, true, "RL02: read error, device %d, disk offset %u, read size %u, cylinder %d, head %d, sector %d", device, temp_disk_offset, cur, track, head, sector); break; } @@ -218,6 +272,8 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) b->writeUnibusByte(memory_address++, xfer_buffer[i++]); // update_bus_address(memory_address); + + mpr[0]++; } temp_disk_offset += cur; @@ -247,9 +303,9 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) if (do_int) { if (registers[(RL02_CSR - RL02_BASE) / 2] & 64) { // interrupt enable? - DOLOG(debug, false, "RL02 triggering interrupt"); + DOLOG(debug, false, "RL02: triggering interrupt"); - b->getCpu()->queue_interrupt(4, 0160); + b->getCpu()->queue_interrupt(5, 0160); } }