diff --git a/bus.cpp b/bus.cpp index 59aafdb..14a7cb7 100644 --- a/bus.cpp +++ b/bus.cpp @@ -130,6 +130,13 @@ bus *bus::deserialize(const json_t *const j, console *const cnsl, std::atomic_ui } #endif +void bus::show_state(console *const cnsl) const +{ + cnsl->put_string_lf(format("Microprogram break register: %06o", microprogram_break_register)); + cnsl->put_string_lf(format("Console switches: %06o", console_switches)); + cnsl->put_string_lf(format("Console LEDs: %06o", console_leds)); +} + void bus::set_memory_size(const int n_pages) { uint32_t n_bytes = n_pages * 8192l; diff --git a/bus.h b/bus.h index f489c8f..e9b3050 100644 --- a/bus.h +++ b/bus.h @@ -9,6 +9,7 @@ #include #include "gen.h" +#include "device.h" #include "dc11.h" #include "mmu.h" #include "rk05.h" @@ -56,7 +57,7 @@ typedef struct { bool is_psw; } write_rc_t; -class bus +class bus: public device { private: cpu *c { nullptr }; @@ -86,6 +87,8 @@ public: void reset(); void init(); // invoked by 'RESET' command + void show_state(console *const cnsl) const override; + void set_console_switches(const uint16_t new_state) { console_switches = new_state; } void set_console_switch(const int bit, const bool state) { console_switches &= ~(1 << bit); console_switches |= state << bit; } uint16_t get_console_switches() { return console_switches; } @@ -115,16 +118,18 @@ public: tm_11 *getTM11() { return tm11; } uint16_t read(const uint16_t a, const word_mode_t word_mode, const rm_selection_t mode_selection, const bool peek_only=false, const d_i_space_t s = i_space); - uint16_t read_byte(const uint16_t a) { return read(a, wm_byte, rm_cur); } - uint16_t read_word(const uint16_t a, const d_i_space_t s = i_space); + uint8_t read_byte(const uint16_t a) override { return read(a, wm_byte, rm_cur); } + uint16_t read_word(const uint16_t a, const d_i_space_t s); + uint16_t read_word(const uint16_t a) override { return read_word(a, i_space); } uint16_t peekWord(const uint16_t a); uint8_t readUnibusByte(const uint32_t a); uint16_t readPhysical(const uint32_t a); write_rc_t write(const uint16_t a, const word_mode_t word_mode, uint16_t value, const rm_selection_t mode_selection, const d_i_space_t s = i_space); void writeUnibusByte(const uint32_t a, const uint8_t value); - void write_byte(const uint16_t a, const uint8_t value) { write(a, wm_byte, value, rm_cur); } - void write_word(const uint16_t a, const uint16_t value, const d_i_space_t s = i_space); + void write_byte(const uint16_t a, const uint8_t value) override { write(a, wm_byte, value, rm_cur); } + void write_word(const uint16_t a, const uint16_t value, const d_i_space_t s); + void write_word(const uint16_t a, const uint16_t value) override { write_word(a, value, i_space); } void writePhysical(const uint32_t a, const uint16_t value); bool is_psw(const uint16_t addr, const int run_mode, const d_i_space_t space) const; diff --git a/console.cpp b/console.cpp index be5ac2c..581eef2 100644 --- a/console.cpp +++ b/console.cpp @@ -1,6 +1,7 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license +#include #include #include #include diff --git a/console.h b/console.h index 88e1b3c..a22b569 100644 --- a/console.h +++ b/console.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 @@ -6,16 +6,17 @@ #include #include #include +#include #include #include -#include "bus.h" - #if defined(_WIN32) #include "win32.h" #endif +class bus; + class console { private: diff --git a/console_ncurses.cpp b/console_ncurses.cpp index 6f2cee6..8f7fceb 100644 --- a/console_ncurses.cpp +++ b/console_ncurses.cpp @@ -1,4 +1,4 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #include @@ -6,6 +6,7 @@ #include #include +#include "bus.h" #include "console_ncurses.h" #include "cpu.h" #include "error.h" diff --git a/dc11.cpp b/dc11.cpp index f2e5047..5caebda 100644 --- a/dc11.cpp +++ b/dc11.cpp @@ -115,6 +115,28 @@ dc11::~dc11() #endif } +void dc11::show_state(console *const cnsl) const +{ + for(int i=0; i<4; i++) { + cnsl->put_string_lf(format("* LINE %d", i + 1)); + + if (i == serial_line) { + cnsl->put_string_lf(format(" Serial thread running: %s", serial_thread_running ? "true": "false" )); + cnsl->put_string_lf(format(" Serial enabled: %s", serial_enabled ? "true": "false" )); + } + else { + if (pfds[dc11_n_lines + i].fd != INVALID_SOCKET) + cnsl->put_string_lf(" Connected to: " + get_endpoint_name(pfds[dc11_n_lines + i].fd)); + } + + std::unique_lock lck(input_lock[i]); + cnsl->put_string_lf(format(" Characters in buffer: %zu", recv_buffers[i].size())); + + cnsl->put_string_lf(format(" RX interrupt enabled: %s", is_rx_interrupt_enabled(i) ? "true": "false" )); + cnsl->put_string_lf(format(" TX interrupt enabled: %s", is_tx_interrupt_enabled(i) ? "true": "false" )); + } +} + void dc11::trigger_interrupt(const int line_nr, const bool is_tx) { TRACE("DC11: interrupt for line %d, %s", line_nr, is_tx ? "TX" : "RX"); @@ -423,12 +445,12 @@ void dc11::reset() { } -bool dc11::is_rx_interrupt_enabled(const int line_nr) +bool dc11::is_rx_interrupt_enabled(const int line_nr) const { return !!(registers[line_nr * 4 + 0] & 64); } -bool dc11::is_tx_interrupt_enabled(const int line_nr) +bool dc11::is_tx_interrupt_enabled(const int line_nr) const { return !!(registers[line_nr * 4 + 2] & 64); } diff --git a/dc11.h b/dc11.h index e15bd9e..fc23436 100644 --- a/dc11.h +++ b/dc11.h @@ -48,7 +48,7 @@ private: pollfd *pfds { nullptr }; #endif std::vector recv_buffers[dc11_n_lines]; - std::mutex input_lock[dc11_n_lines]; + mutable std::mutex input_lock[dc11_n_lines]; std::atomic_bool serial_thread_running { false }; bool serial_enabled { false }; #if IS_POSIX @@ -57,8 +57,8 @@ private: #endif void trigger_interrupt(const int line_nr, const bool is_tx); - bool is_rx_interrupt_enabled(const int line_nr); - bool is_tx_interrupt_enabled(const int line_nr); + bool is_rx_interrupt_enabled(const int line_nr) const; + bool is_tx_interrupt_enabled(const int line_nr) const; public: dc11(const int base_port, bus *const b); @@ -70,6 +70,9 @@ public: #endif void reset(); + + void show_state(console *const cnsl) const override; + #if defined(ESP32) void set_serial(const int bitrate, const int rx, const int tx); void serial_handler(); diff --git a/debugger.cpp b/debugger.cpp index 90992c0..9f0c7dc 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -436,77 +436,6 @@ std::map split(const std::vector & kv_arr return out; } -void dump_par_pdr(console *const cnsl, bus *const b, const uint16_t pdrs, const uint16_t pars, const std::string & name, const int state, const std::optional & selection) -{ - if (state == 0 || state == 2) - cnsl->put_string_lf(name); - else - cnsl->put_string_lf(format("%s DISABLED", name.c_str())); - - cnsl->put_string_lf(" PAR PDR LEN"); - - for(int i=0; i<8; i++) { - if (selection.has_value() && i != selection.value()) - continue; - uint16_t par_value = b->read(pars + i * 2, wm_word, rm_cur, true); - uint16_t pdr_value = b->read(pdrs + i * 2, wm_word, rm_cur, true); - - uint16_t pdr_len = (((pdr_value >> 8) & 127) + 1) * 64; - - cnsl->put_string_lf(format("%d] %06o %08o %06o %04o D%d A%d", i, par_value, par_value * 64, pdr_value, pdr_len, !!(pdr_value & 8), pdr_value & 7)); - } -} - -void dump_memory_contents(console *const cnsl, bus *const b, const uint16_t read_addr) -{ - cnsl->put_string_lf(format("\tMOV #%06o,R0", read_addr)); - cnsl->put_string_lf(format("\tMOV #%06o,(R0)", b->read(read_addr, wm_word, rm_cur, true))); -} - -void dump_range_as_instructions(console *const cnsl, bus *const b, const uint16_t base) -{ - for(int i=0; i<8; i++) - dump_memory_contents(cnsl, b, base + i * 2); -} - -void mmu_dump(console *const cnsl, bus *const b, const bool verbose) -{ - uint16_t mmr0 = b->getMMU()->getMMR0(); - uint16_t mmr1 = b->getMMU()->getMMR1(); - uint16_t mmr2 = b->getMMU()->getMMR2(); - uint16_t mmr3 = b->getMMU()->getMMR3(); - - cnsl->put_string_lf(mmr0 & 1 ? "MMU enabled" : "MMU NOT enabled"); - - cnsl->put_string_lf(format("MMR0: %06o", mmr0)); - cnsl->put_string_lf(format("MMR1: %06o", mmr1)); - cnsl->put_string_lf(format("MMR2: %06o", mmr2)); - cnsl->put_string_lf(format("MMR3: %06o", mmr3)); - - dump_par_pdr(cnsl, b, ADDR_PDR_SV_START, ADDR_PAR_SV_START, "supervisor i-space", 0, { }); - dump_par_pdr(cnsl, b, ADDR_PDR_SV_START + 020, ADDR_PAR_SV_START + 020, "supervisor d-space", 1 + (!!(mmr3 & 2)), { }); - - dump_par_pdr(cnsl, b, ADDR_PDR_K_START, ADDR_PAR_K_START, "kernel i-space", 0, { }); - dump_par_pdr(cnsl, b, ADDR_PDR_K_START + 020, ADDR_PAR_K_START + 020, "kernel d-space", 1 + (!!(mmr3 & 4)), { }); - - dump_par_pdr(cnsl, b, ADDR_PDR_U_START, ADDR_PAR_U_START, "user i-space", 0, { }); - dump_par_pdr(cnsl, b, ADDR_PDR_U_START + 020, ADDR_PAR_U_START + 020, "user d-space", 1 + (!!(mmr3 & 1)), { }); - - if (verbose) { - dump_range_as_instructions(cnsl, b, ADDR_PDR_SV_START); // sv i - dump_range_as_instructions(cnsl, b, ADDR_PDR_SV_START + 020); // sv d - dump_range_as_instructions(cnsl, b, ADDR_PDR_K_START); // k i - dump_range_as_instructions(cnsl, b, ADDR_PDR_K_START + 020); // k d - dump_range_as_instructions(cnsl, b, ADDR_PDR_U_START); // u i - dump_range_as_instructions(cnsl, b, ADDR_PDR_U_START + 020); // u d - - dump_memory_contents(cnsl, b, ADDR_MMR0); - dump_memory_contents(cnsl, b, ADDR_MMR1); - dump_memory_contents(cnsl, b, ADDR_MMR2); - dump_memory_contents(cnsl, b, ADDR_MMR3); - } -} - const char *trap_action_to_str(const trap_action_t ta) { if (ta == T_PROCEED) @@ -534,16 +463,16 @@ void mmu_resolve(console *const cnsl, bus *const b, const uint16_t va) uint16_t mmr3 = b->getMMU()->getMMR3(); if (run_mode == 0) { - dump_par_pdr(cnsl, b, ADDR_PDR_K_START, ADDR_PAR_K_START, "kernel i-space", 0, data.apf); - dump_par_pdr(cnsl, b, ADDR_PDR_K_START + 020, ADDR_PAR_K_START + 020, "kernel d-space", 1 + (!!(mmr3 & 4)), data.apf); + b->getMMU()->dump_par_pdr(cnsl, 1, false, "supervisor i-space", 0, data.apf); + b->getMMU()->dump_par_pdr(cnsl, 1, true, "supervisor d-space", 1 + (!!(mmr3 & 4)), data.apf); } else if (run_mode == 1) { - dump_par_pdr(cnsl, b, ADDR_PDR_SV_START, ADDR_PAR_SV_START, "supervisor i-space", 0, data.apf); - dump_par_pdr(cnsl, b, ADDR_PDR_SV_START + 020, ADDR_PAR_SV_START + 020, "supervisor d-space", 1 + (!!(mmr3 & 4)), data.apf); + b->getMMU()->dump_par_pdr(cnsl, 0, false, "kernel i-space", 0, data.apf); + b->getMMU()->dump_par_pdr(cnsl, 0, true, "kernel d-space", 1 + (!!(mmr3 & 4)), data.apf); } else if (run_mode == 3) { - dump_par_pdr(cnsl, b, ADDR_PDR_U_START, ADDR_PAR_U_START, "user i-space", 0, data.apf); - dump_par_pdr(cnsl, b, ADDR_PDR_U_START + 020, ADDR_PAR_U_START + 020, "user d-space", 1 + (!!(mmr3 & 4)), data.apf); + b->getMMU()->dump_par_pdr(cnsl, 3, false, "user i-space", 0, data.apf); + b->getMMU()->dump_par_pdr(cnsl, 3, true, "user d-space", 1 + (!!(mmr3 & 4)), data.apf); } for(int i=0; i<2; i++) { @@ -790,8 +719,19 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto continue; } - else if (parts[0] == "mmudump") { - mmu_dump(cnsl, b, parts.size() == 2 && parts[1] == "-v"); + else if (parts[0] == "state") { + if (parts[1] == "rl02") + b->getRL02()->show_state(cnsl); + else if (parts[1] == "mmu") + b->getMMU() ->show_state(cnsl); + else if (parts[1] == "rk05") + b->getRK05()->show_state(cnsl); + else if (parts[1] == "dc11") + b->getDC11()->show_state(cnsl); + else if (parts[1] == "tm11") + b->getTM11()->show_state(cnsl); + else + cnsl->put_string_lf(format("Device \"%s\" is not known", parts[1].c_str())); continue; } @@ -1072,7 +1012,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto "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)", + "state x - dump state of a device: rl02, rk05, mmu, tm11 or dc11", "mmures x - resolve a virtual address", "qi - show queued interrupts", "setpc x - set PC to value", diff --git a/device.h b/device.h index ebaa506..6bf8fae 100644 --- a/device.h +++ b/device.h @@ -1,5 +1,6 @@ #pragma once +#include "console.h" class device { @@ -12,6 +13,8 @@ public: virtual void reset() = 0; + virtual void show_state(console *const cnsl) const = 0; + virtual uint8_t read_byte(const uint16_t addr) = 0; virtual uint16_t read_word(const uint16_t addr) = 0; diff --git a/loaders.cpp b/loaders.cpp index 3be2575..cb354bf 100644 --- a/loaders.cpp +++ b/loaders.cpp @@ -138,8 +138,8 @@ void set_boot_loader(bus *const b, const bootloader_t which) bl = rl02_code; } - for(int i=0; iwrite_word(offset + i * 2, bl[i]); + for(uint16_t i=0; iwrite_word(uint16_t(offset + i * 2), bl[i]); c->setRegister(7, start); } diff --git a/mmu.cpp b/mmu.cpp index 55c427a..b943722 100644 --- a/mmu.cpp +++ b/mmu.cpp @@ -30,6 +30,46 @@ void mmu::reset() CPUERR = MMR0 = MMR1 = MMR2 = MMR3 = PIR = CSR = 0; } +void mmu::dump_par_pdr(console *const cnsl, const int run_mode, const bool d, const std::string & name, const int state, const std::optional & selection) const +{ + if (state == 0 || state == 2) + cnsl->put_string_lf(name); + else + cnsl->put_string_lf(format("%s DISABLED", name.c_str())); + + cnsl->put_string_lf(" PAR PDR LEN"); + + for(int i=0; i<8; i++) { + if (selection.has_value() && i != selection.value()) + continue; + uint16_t par_value = pages[run_mode][d][i].par; + uint16_t pdr_value = pages[run_mode][d][i].pdr; + + uint16_t pdr_len = (((pdr_value >> 8) & 127) + 1) * 64; + + cnsl->put_string_lf(format("%d] %06o %08o %06o %04o D%d A%d", i, par_value, par_value * 64, pdr_value, pdr_len, !!(pdr_value & 8), pdr_value & 7)); + } +} + +void mmu::show_state(console *const cnsl) const +{ + cnsl->put_string_lf(MMR0 & 1 ? "MMU enabled" : "MMU NOT enabled"); + + cnsl->put_string_lf(format("MMR0: %06o", MMR0)); + cnsl->put_string_lf(format("MMR1: %06o", MMR1)); + cnsl->put_string_lf(format("MMR2: %06o", MMR2)); + cnsl->put_string_lf(format("MMR3: %06o", MMR3)); + + dump_par_pdr(cnsl, 1, false, "supervisor i-space", 0, { }); + dump_par_pdr(cnsl, 1, true, "supervisor d-space", 1 + (!!(MMR3 & 2)), { }); + + dump_par_pdr(cnsl, 0, false, "kernel i-space", 0, { }); + dump_par_pdr(cnsl, 0, true, "kernel d-space", 1 + (!!(MMR3 & 2)), { }); + + dump_par_pdr(cnsl, 3, false, "user i-space", 0, { }); + dump_par_pdr(cnsl, 3, true, "user d-space", 1 + (!!(MMR3 & 2)), { }); +} + uint16_t mmu::read_pdr(const uint32_t a, const int run_mode) { int page = (a >> 1) & 7; diff --git a/mmu.h b/mmu.h index 27074cf..8c64d51 100644 --- a/mmu.h +++ b/mmu.h @@ -77,6 +77,9 @@ public: void reset() override; + void dump_par_pdr(console *const cnsl, const int run_mode, const bool d, const std::string & name, const int state, const std::optional & selection) const; + void show_state(console *const cnsl) const override; + bool is_enabled() const { return MMR0 & 1; } bool is_locked() const { return !!(MMR0 & 0160000); } diff --git a/rk05.cpp b/rk05.cpp index 1cd9e22..44f127b 100644 --- a/rk05.cpp +++ b/rk05.cpp @@ -46,6 +46,17 @@ void rk05::reset() memset(registers, 0x00, sizeof registers); } +void rk05::show_state(console *const cnsl) const +{ + cnsl->put_string_lf(format("DS : %06o", registers[0])); + cnsl->put_string_lf(format("ERROR : %06o", registers[1])); + cnsl->put_string_lf(format("CS : %06o", registers[2])); + cnsl->put_string_lf(format("WC : %06o", registers[3])); + cnsl->put_string_lf(format("BA : %06o", registers[4])); + cnsl->put_string_lf(format("DA : %06o", registers[5])); + cnsl->put_string_lf(format("DATABUF: %06o", registers[6])); +} + uint8_t rk05::read_byte(const uint16_t addr) { uint16_t v = read_word(addr & ~1); diff --git a/rk05.h b/rk05.h index 86ed1d5..9d17a93 100644 --- a/rk05.h +++ b/rk05.h @@ -46,6 +46,8 @@ public: void begin() override; void reset() override; + void show_state(console *const cnsl) const override; + #if IS_POSIX json_t *serialize() const; static rk05 *deserialize(const json_t *const j, bus *const b); diff --git a/rl02.cpp b/rl02.cpp index 25139e9..237e743 100644 --- a/rl02.cpp +++ b/rl02.cpp @@ -60,6 +60,18 @@ void rl02::reset() sector = 0; } +void rl02::show_state(console *const cnsl) const +{ + cnsl->put_string_lf(format("CSR: %06o", registers[0])); + cnsl->put_string_lf(format("BAR: %06o", registers[1])); + cnsl->put_string_lf(format("DAR: %06o", registers[2])); + cnsl->put_string_lf(format("MPR: %06o / %06o / %06o", mpr[0], mpr[1], mpr[2])); + + cnsl->put_string_lf(format("track : %d", track )); + cnsl->put_string_lf(format("head : %d", head )); + cnsl->put_string_lf(format("sector: %d", sector)); +} + #if IS_POSIX json_t *rl02::serialize() const { diff --git a/rl02.h b/rl02.h index 0ea1d92..78ee4e9 100644 --- a/rl02.h +++ b/rl02.h @@ -53,6 +53,8 @@ public: void begin() override; void reset() override; + void show_state(console *const cnsl) const override; + #if IS_POSIX json_t *serialize() const; static rl02 *deserialize(const json_t *const j, bus *const b); diff --git a/tm-11.cpp b/tm-11.cpp index 20eba66..2d99157 100644 --- a/tm-11.cpp +++ b/tm-11.cpp @@ -43,6 +43,18 @@ void tm_11::load(const std::string & file) reset(); } +void tm_11::show_state(console *const cnsl) const +{ + cnsl->put_string_lf(format("MTS : %06o", registers[0])); + cnsl->put_string_lf(format("MTC : %06o", registers[1])); + cnsl->put_string_lf(format("MTBRC : %06o", registers[2])); + cnsl->put_string_lf(format("MTCMA : %06o", registers[3])); + cnsl->put_string_lf(format("MTD : %06o", registers[4])); + cnsl->put_string_lf(format("MTRD : %06o", registers[5])); + cnsl->put_string_lf(format("offset: %d", offset )); + cnsl->put_string_lf(format("tape file: %s", tape_file.c_str())); +} + void tm_11::reset() { memset(registers, 0x00, sizeof registers ); diff --git a/tm-11.h b/tm-11.h index fd9f4a0..1d58244 100644 --- a/tm-11.h +++ b/tm-11.h @@ -41,6 +41,8 @@ public: void reset() override; + void show_state(console *const cnsl) const override; + uint8_t read_byte(const uint16_t addr) override; uint16_t read_word(const uint16_t addr) override; diff --git a/utils.cpp b/utils.cpp index faec346..a9e71da 100644 --- a/utils.cpp +++ b/utils.cpp @@ -11,6 +11,7 @@ #include #include #else +#include #include #include #include @@ -257,3 +258,18 @@ void set_nodelay(const int fd) #endif DOLOG(warning, true, "Cannot disable nagle algorithm"); } + +std::string get_endpoint_name(const int fd) +{ + char host[64] { "?" }; + char serv[32] { "?" }; + sockaddr_in6 addr { 0 }; + socklen_t addr_len = sizeof addr; + + if (getpeername(fd, reinterpret_cast(&addr), &addr_len) == -1) + return format("FAILED TO FIND NAME OF %d: %s", fd, strerror(errno)); + + getnameinfo(reinterpret_cast(&addr), addr_len, host, sizeof(host), serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV); + + return std::string(host) + "." + std::string(serv); +} diff --git a/utils.h b/utils.h index b5590f2..8fd97a0 100644 --- a/utils.h +++ b/utils.h @@ -1,4 +1,4 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #include @@ -27,3 +27,4 @@ ssize_t READ(int fd, char *whereto, size_t len); void update_word(uint16_t *const w, const bool msb, const uint8_t v); void set_nodelay(const int fd); +std::string get_endpoint_name(const int fd);