From 1e34084b99787e4b266e26d63ac4b4ad01895736 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 13:44:30 +0200 Subject: [PATCH 01/19] IS_POSIX define --- debugger.cpp | 16 ++++++++-------- gen.h | 3 +++ utils.cpp | 6 ++++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/debugger.cpp b/debugger.cpp index d78df6b..7c50e2c 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -2,7 +2,8 @@ // Released under MIT license #include -#ifdef linux +#include "gen.h" +#if IS_POSIX #include #include #include @@ -18,13 +19,12 @@ #include "console.h" #include "cpu.h" #include "disk_backend.h" -#ifdef linux +#if IS_POSIX #include "disk_backend_file.h" #else #include "disk_backend_esp32.h" #endif #include "disk_backend_nbd.h" -#include "gen.h" #include "loaders.h" #include "log.h" #include "tty.h" @@ -67,7 +67,7 @@ typedef enum { BE_NETWORK, BE_SD } disk_backend_t; #if !defined(BUILD_FOR_RP2040) std::optional, std::vector, std::string> > load_disk_configuration(console *const c) { -#ifdef linux +#if IS_POSIX json_error_t error; json_t *json = json_load_file("." NET_DISK_CFG_FILE, JSON_REJECT_DUPLICATES, &error); if (!json) { @@ -147,7 +147,7 @@ std::optional, std::vector & tape_file, const disk_type_t dt, console *const cnsl) { -#ifdef linux +#if IS_POSIX json_t *json = json_object(); json_object_set(json, "NBD-host", json_string(nbd_host.c_str())); @@ -297,7 +297,7 @@ std::optional, std::vector, std::vector, std::string> > select_disk_files(console *const c) { -#ifdef linux +#if IS_POSIX c->put_string_lf("Files in current directory: "); #else c->debug("MISO: %d", int(MISO)); @@ -377,7 +377,7 @@ std::optional, std::vector, std::vector #include "rp2040.h" @@ -165,7 +167,7 @@ void set_thread_name(std::string name) std::string get_thread_name() { -#ifdef linux +#if IS_POSIX char buffer[16 + 1] { }; pthread_getname_np(pthread_self(), buffer, sizeof buffer); From 655df33c3c4aa829864eb584a4003a31d07fcbf2 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 13:45:49 +0200 Subject: [PATCH 02/19] version --- ESP32/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ESP32/platformio.ini b/ESP32/platformio.ini index 3d868e6..948ef3a 100644 --- a/ESP32/platformio.ini +++ b/ESP32/platformio.ini @@ -1,4 +1,4 @@ -# (C) 2018-2023 by Folkert van Heusden +# (C) 2018-2024 by Folkert van Heusden # Released under MIT license [platformio] From ef166a98e9c079308381ea2d9cda3ba6442e7ebf Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 14:00:34 +0200 Subject: [PATCH 03/19] (de-)serialize for memory-object --- memory.cpp | 28 ++++++++++++++++++++++++++++ memory.h | 12 ++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/memory.cpp b/memory.cpp index e58851c..9761814 100644 --- a/memory.cpp +++ b/memory.cpp @@ -27,3 +27,31 @@ void memory::reset() { memset(m, 0x00, size); } + +#if IS_POSIX +json_t *memory::serialize() +{ + json_t *j = json_object(); + + json_object_set(j, "size", json_integer(size)); + + json_t *ja = json_array(); + for(size_t i=0; iwriteByte(i, json_integer_value(json_array_get(ja, i))); + + return m; +} +#endif diff --git a/memory.h b/memory.h index 5942078..4120cd4 100644 --- a/memory.h +++ b/memory.h @@ -1,11 +1,15 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #pragma once - +#include "gen.h" #include +#if IS_POSIX +#include +#endif #include + class memory { private: @@ -17,6 +21,10 @@ public: ~memory(); void reset(); +#if IS_POSIX + json_t *serialize(); + static memory *deserialize(const json_t *const j); +#endif uint16_t readByte(const uint32_t a) const { return m[a]; } void writeByte(const uint32_t a, const uint16_t v) { assert(a < size); m[a] = v; } From cdccde195625582c501e120291651ff3065bbbb8 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 14:34:10 +0200 Subject: [PATCH 04/19] moved all kw11-l to seperate class --- bus.cpp | 74 +++++--------------------------------- bus.h | 45 ++++++++++------------- kw11-l.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++++++++----- kw11-l.h | 23 +++++++++--- main.cpp | 10 +++--- 5 files changed, 142 insertions(+), 112 deletions(-) diff --git a/bus.cpp b/bus.cpp index 8198ae3..5aa06a4 100644 --- a/bus.cpp +++ b/bus.cpp @@ -8,6 +8,7 @@ #include "bus.h" #include "gen.h" #include "cpu.h" +#include "kw11-l.h" #include "log.h" #include "memory.h" #include "mmu.h" @@ -26,15 +27,14 @@ bus::bus() mmu_ = new mmu(); - reset(); + kw11_l_ = new kw11_l(this); -#if defined(BUILD_FOR_RP2040) - xSemaphoreGive(lf_csr_lock); // initialize -#endif + reset(); } bus::~bus() { + delete kw11_l_; delete c; delete tm11; delete rk05_; @@ -220,22 +220,8 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm return temp; } - if (a == ADDR_LFC) { // line frequency clock and status register -#if defined(BUILD_FOR_RP2040) - xSemaphoreTake(lf_csr_lock, portMAX_DELAY); -#else - std::unique_lock lck(lf_csr_lock); -#endif - - uint16_t temp = lf_csr; - if (!peek_only) DOLOG(debug, false, "READ-I/O line frequency clock: %o", temp); - -#if defined(BUILD_FOR_RP2040) - xSemaphoreGive(lf_csr_lock); -#endif - - return temp; - } + if (a == ADDR_LFC) // line frequency clock and status register + return kw11_l_->readWord(a); if (a == ADDR_LP11CSR) { // printer, CSR register, LP11 uint16_t temp = 0x80; @@ -847,20 +833,8 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 return { false }; } - if (a == ADDR_LFC) { // line frequency clock and status register -#if defined(BUILD_FOR_RP2040) - xSemaphoreTake(lf_csr_lock, portMAX_DELAY); -#else - std::unique_lock lck(lf_csr_lock); -#endif - - DOLOG(debug, false, "WRITE-I/O set line frequency clock/status register: %06o", value); - lf_csr = value; -#if defined(BUILD_FOR_RP2040) - xSemaphoreGive(lf_csr_lock); -#endif - return { false }; - } + if (a == ADDR_LFC) // line frequency clock and status register + kw11_l_->writeWord(a, value); if (tm11 && a >= TM_11_BASE && a < TM_11_END) { DOLOG(debug, false, "WRITE-I/O TM11 register %d: %06o", (a - TM_11_BASE) / 2, value); @@ -1023,35 +997,3 @@ void bus::writeUnibusByte(const uint32_t a, const uint8_t v) DOLOG(debug, false, "writeUnibusByte[%08o]=%03o", a, v); m->writeByte(a, v); } - -void bus::set_lf_crs_b7() -{ -#if defined(BUILD_FOR_RP2040) - xSemaphoreTake(lf_csr_lock, portMAX_DELAY); -#else - std::unique_lock lck(lf_csr_lock); -#endif - - lf_csr |= 128; - -#if defined(BUILD_FOR_RP2040) - xSemaphoreGive(lf_csr_lock); -#endif -} - -uint8_t bus::get_lf_crs() -{ -#if defined(BUILD_FOR_RP2040) - xSemaphoreTake(lf_csr_lock, portMAX_DELAY); -#else - std::unique_lock lck(lf_csr_lock); -#endif - - uint8_t rc = lf_csr; - -#if defined(BUILD_FOR_RP2040) - xSemaphoreGive(lf_csr_lock); -#endif - - return rc; -} diff --git a/bus.h b/bus.h index e61243a..d9cb2bd 100644 --- a/bus.h +++ b/bus.h @@ -54,6 +54,7 @@ #define ADDR_SYSTEM_ID 0177764 class cpu; +class kw11_l; class memory; class tty; @@ -75,23 +76,17 @@ typedef struct { class bus { private: - cpu *c { nullptr }; - tm_11 *tm11 { nullptr }; - rk05 *rk05_ { nullptr }; - rl02 *rl02_ { nullptr }; - tty *tty_ { nullptr }; + cpu *c { nullptr }; + tm_11 *tm11 { nullptr }; + rk05 *rk05_ { nullptr }; + rl02 *rl02_ { nullptr }; + tty *tty_ { nullptr }; + kw11_l *kw11_l_ { nullptr }; - mmu *mmu_ { nullptr }; + mmu *mmu_ { nullptr }; int n_pages { DEFAULT_N_PAGES }; - memory *m { nullptr }; - -#if defined(BUILD_FOR_RP2040) - SemaphoreHandle_t lf_csr_lock { xSemaphoreCreateBinary() }; -#else - std::mutex lf_csr_lock; -#endif - uint16_t lf_csr { 0 }; + memory *m { nullptr }; uint16_t microprogram_break_register { 0 }; @@ -116,23 +111,19 @@ public: uint16_t get_console_leds() { return console_leds; } - void add_cpu (cpu *const c); - void add_tm11(tm_11 *const tm11); - void add_rk05(rk05 *const rk05_); - void add_rl02(rl02 *const rl02_); - void add_tty (tty *const tty_); + void add_cpu (cpu *const c ); + void add_tm11(tm_11 *const tm11 ); + void add_rk05(rk05 *const rk05_); + void add_rl02(rl02 *const rl02_); + void add_tty (tty *const tty_ ); - cpu *getCpu() { return c; } - - tty *getTty() { return tty_; } - - mmu *getMMU() { return mmu_; } + cpu *getCpu() { return c; } + kw11_l *getKW11_L() { return kw11_l_; } + tty *getTty() { return tty_; } + mmu *getMMU() { return mmu_; } void init(); // invoked by 'RESET' command - void set_lf_crs_b7(); - uint8_t get_lf_crs(); - 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 readByte(const uint16_t a) { return read(a, wm_byte, rm_cur); } uint16_t readWord(const uint16_t a, const d_i_space_t s = i_space); diff --git a/kw11-l.cpp b/kw11-l.cpp index 9081eb3..1661ed0 100644 --- a/kw11-l.cpp +++ b/kw11-l.cpp @@ -25,13 +25,8 @@ void thread_wrapper_kw11(void *p) } #endif -kw11_l::kw11_l(bus *const b, console *const cnsl) : b(b), cnsl(cnsl) +kw11_l::kw11_l(bus *const b): b(b) { -#if defined(ESP32) || defined(BUILD_FOR_RP2040) - xTaskCreate(&thread_wrapper_kw11, "kw11-l", 2048, this, 1, nullptr); -#else - th = new std::thread(std::ref(*this)); -#endif } kw11_l::~kw11_l() @@ -40,11 +35,25 @@ kw11_l::~kw11_l() #if !defined(ESP32) && !defined(BUILD_FOR_RP2040) th->join(); - delete th; #endif } +void kw11_l::begin(console *const cnsl) +{ + this->cnsl = cnsl; + +#if defined(ESP32) || defined(BUILD_FOR_RP2040) + xTaskCreate(&thread_wrapper_kw11, "kw11-l", 2048, this, 1, nullptr); + +#if defined(BUILD_FOR_RP2040) + xSemaphoreGive(lf_csr_lock); // initialize +#endif +#else + th = new std::thread(std::ref(*this)); +#endif +} + void kw11_l::operator()() { set_thread_name("kek:kw-11l"); @@ -53,9 +62,10 @@ void kw11_l::operator()() while(!stop_flag) { if (*cnsl->get_running_flag()) { - b->set_lf_crs_b7(); + DOLOG(debug, true, "KW11-L tick"); + set_lf_crs_b7(); - if (b->get_lf_crs() & 64) + if (get_lf_crs() & 64) b->getCpu()->queue_interrupt(6, 0100); // TODO: dependant on cpu cycles processed @@ -68,3 +78,77 @@ void kw11_l::operator()() DOLOG(debug, true, "KW11-L thread terminating"); } + +uint16_t kw11_l::readWord(const uint16_t a) +{ + if (a != ADDR_LFC) { + DOLOG(debug, true, "KW11-L readWord not for us (%06o)", a); + return 0; + } + +#if defined(BUILD_FOR_RP2040) + xSemaphoreTake(lf_csr_lock, portMAX_DELAY); +#else + std::unique_lock lck(lf_csr_lock); +#endif + + uint16_t temp = lf_csr; + +#if defined(BUILD_FOR_RP2040) + xSemaphoreGive(lf_csr_lock); +#endif + + return temp; +} + +void kw11_l::writeWord(const uint16_t a, const uint16_t value) +{ + if (a != ADDR_LFC) { + DOLOG(debug, true, "KW11-L writeWord not for us (%06o to %06o)", value, a); + return; + } + +#if defined(BUILD_FOR_RP2040) + xSemaphoreTake(lf_csr_lock, portMAX_DELAY); +#else + std::unique_lock lck(lf_csr_lock); +#endif + + DOLOG(debug, false, "WRITE-I/O set line frequency clock/status register: %06o", value); + lf_csr = value; +#if defined(BUILD_FOR_RP2040) + xSemaphoreGive(lf_csr_lock); +#endif +} + +void kw11_l::set_lf_crs_b7() +{ +#if defined(BUILD_FOR_RP2040) + xSemaphoreTake(lf_csr_lock, portMAX_DELAY); +#else + std::unique_lock lck(lf_csr_lock); +#endif + + lf_csr |= 128; + +#if defined(BUILD_FOR_RP2040) + xSemaphoreGive(lf_csr_lock); +#endif +} + +uint8_t kw11_l::get_lf_crs() +{ +#if defined(BUILD_FOR_RP2040) + xSemaphoreTake(lf_csr_lock, portMAX_DELAY); +#else + std::unique_lock lck(lf_csr_lock); +#endif + + uint8_t rc = lf_csr; + +#if defined(BUILD_FOR_RP2040) + xSemaphoreGive(lf_csr_lock); +#endif + + return rc; +} diff --git a/kw11-l.h b/kw11-l.h index 416f1f7..eb423a3 100644 --- a/kw11-l.h +++ b/kw11-l.h @@ -1,26 +1,39 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #include #include #include "bus.h" +#include "console.h" class kw11_l { private: bus *const b { nullptr }; - console *const cnsl { nullptr }; + console *cnsl { nullptr }; -#if !defined(BUILD_FOR_RP2040) +#if defined(BUILD_FOR_RP2040) + SemaphoreHandle_t lf_csr_lock { xSemaphoreCreateBinary() }; +#else std::thread * th { nullptr }; + std::mutex lf_csr_lock; #endif + uint16_t lf_csr { 0 }; + std::atomic_bool stop_flag { false }; + uint8_t get_lf_crs(); + void set_lf_crs_b7(); + public: - kw11_l(bus *const b, console *const cnsl); + kw11_l(bus *const b); virtual ~kw11_l(); - void operator()(); + void begin(console *const cnsl); + void operator()(); + + uint16_t readWord (const uint16_t a); + void writeWord(const uint16_t a, const uint16_t v); }; diff --git a/main.cpp b/main.cpp index 71fa638..e36e4e9 100644 --- a/main.cpp +++ b/main.cpp @@ -584,14 +584,14 @@ int main(int argc, char *argv[]) if (test.empty() == false) load_p11_x11(b, test); - kw11_l *lf = new kw11_l(b, cnsl); - std::thread *metrics_thread = nullptr; if (metrics) metrics_thread = new std::thread(get_metrics, c); cnsl->start_thread(); + b->getKW11_L()->begin(cnsl); + if (is_bic) run_bic(cnsl, b, &event, tracing, bic_start.value()); else if (run_debugger || (bootloader == BL_NONE && test.empty() && tape.empty())) @@ -624,11 +624,11 @@ int main(int argc, char *argv[]) delete metrics_thread; } - delete lf; - - delete cnsl; + cnsl->stop_thread(); delete b; + delete cnsl; + return 0; } From 3879721b2822f27b34be905afb9b11d9567587b2 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 14:39:03 +0200 Subject: [PATCH 05/19] KW11-L fixes --- bus.cpp | 5 ++++- kw11-l.cpp | 8 +++++--- kw11-l.h | 12 ++++++------ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/bus.cpp b/bus.cpp index 5aa06a4..b19807c 100644 --- a/bus.cpp +++ b/bus.cpp @@ -833,9 +833,12 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 return { false }; } - if (a == ADDR_LFC) // line frequency clock and status register + if (a == ADDR_LFC) { // line frequency clock and status register kw11_l_->writeWord(a, value); + return { false }; + } + if (tm11 && a >= TM_11_BASE && a < TM_11_END) { DOLOG(debug, false, "WRITE-I/O TM11 register %d: %06o", (a - TM_11_BASE) / 2, value); word_mode == wm_byte ? tm11->writeByte(a, value) : tm11->writeWord(a, value); diff --git a/kw11-l.cpp b/kw11-l.cpp index 1661ed0..449bfb2 100644 --- a/kw11-l.cpp +++ b/kw11-l.cpp @@ -34,8 +34,11 @@ kw11_l::~kw11_l() stop_flag = true; #if !defined(ESP32) && !defined(BUILD_FOR_RP2040) - th->join(); - delete th; + if (th) { + th->join(); + + delete th; + } #endif } @@ -62,7 +65,6 @@ void kw11_l::operator()() while(!stop_flag) { if (*cnsl->get_running_flag()) { - DOLOG(debug, true, "KW11-L tick"); set_lf_crs_b7(); if (get_lf_crs() & 64) diff --git a/kw11-l.h b/kw11-l.h index eb423a3..666ac40 100644 --- a/kw11-l.h +++ b/kw11-l.h @@ -11,18 +11,18 @@ class kw11_l { private: - bus *const b { nullptr }; - console *cnsl { nullptr }; + bus *const b { nullptr }; + console *cnsl { nullptr }; #if defined(BUILD_FOR_RP2040) SemaphoreHandle_t lf_csr_lock { xSemaphoreCreateBinary() }; #else - std::thread * th { nullptr }; - std::mutex lf_csr_lock; + std::thread *th { nullptr }; + std::mutex lf_csr_lock; #endif - uint16_t lf_csr { 0 }; + uint16_t lf_csr { 0 }; - std::atomic_bool stop_flag { false }; + std::atomic_bool stop_flag { false }; uint8_t get_lf_crs(); void set_lf_crs_b7(); From ebb7bb3fd02e8f7e7b1146defa784bc5908b7fd3 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 14:48:23 +0200 Subject: [PATCH 06/19] shuffle bus.h --- bus.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bus.h b/bus.h index d9cb2bd..1065d03 100644 --- a/bus.h +++ b/bus.h @@ -98,19 +98,19 @@ public: ~bus(); void reset(); + void init(); // invoked by 'RESET' command 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; } void set_debug_mode() { console_switches |= 128; } + uint16_t get_console_leds() { return console_leds; } int get_memory_size() const { return n_pages; } void set_memory_size(const int n_pages); void mmudebug(const uint16_t a); - uint16_t get_console_leds() { return console_leds; } - void add_cpu (cpu *const c ); void add_tm11(tm_11 *const tm11 ); void add_rk05(rk05 *const rk05_); @@ -122,8 +122,6 @@ public: tty *getTty() { return tty_; } mmu *getMMU() { return mmu_; } - void init(); // invoked by 'RESET' command - 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 readByte(const uint16_t a) { return read(a, wm_byte, rm_cur); } uint16_t readWord(const uint16_t a, const d_i_space_t s = i_space); From 6ab59835e75634c12618f87f92fb6b4d52c7e10d Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 15:45:02 +0200 Subject: [PATCH 07/19] start of bus::(de-)serialize --- bus.cpp | 41 +++++++++++++++++++++++++++++++++-------- bus.h | 25 ++++++++++++------------- gen.h | 12 ++++++++++++ main.cpp | 2 ++ memory.h | 6 ++---- 5 files changed, 61 insertions(+), 25 deletions(-) diff --git a/bus.cpp b/bus.cpp index b19807c..2513f81 100644 --- a/bus.cpp +++ b/bus.cpp @@ -23,8 +23,6 @@ bus::bus() { - m = new memory(n_pages * 8192l); - mmu_ = new mmu(); kw11_l_ = new kw11_l(this); @@ -44,6 +42,27 @@ bus::~bus() delete m; } +#if IS_POSIX +json_t *bus::serialize() +{ + json_t *j_out = json_object(); + + json_object_set(j_out, "memory", m->serialize()); + + return j_out; +} + +bus *bus::deserialize(const json_t *const j) +{ + bus *b = new bus(); + + memory *m = memory::deserialize(json_object_get(j, "memory")); + b->add_ram(m); + + return b; +} +#endif + void bus::set_memory_size(const int n_pages) { this->n_pages = n_pages; @@ -58,10 +77,10 @@ void bus::set_memory_size(const int n_pages) void bus::reset() { - m->reset(); - - mmu_->reset(); - + if (m) + m->reset(); + if (mmu_) + mmu_->reset(); if (c) c->reset(); if (tm11) @@ -74,16 +93,22 @@ void bus::reset() tty_->reset(); } +void bus::add_ram(memory *const m) +{ + delete this->m; + this->m = m; +} + void bus::add_cpu(cpu *const c) { delete this->c; - this->c = c; + this->c = c; } void bus::add_tm11(tm_11 *const tm11) { delete this->tm11; - this->tm11 = tm11; + this->tm11= tm11; } void bus::add_rk05(rk05 *const rk05_) diff --git a/bus.h b/bus.h index 1065d03..8001c4e 100644 --- a/bus.h +++ b/bus.h @@ -18,14 +18,6 @@ #include "rp2040.h" #endif -#if defined(ESP32) || defined(BUILD_FOR_RP2040) -// ESP32 goes in a crash-loop when allocating 128kB -// see also https://github.com/espressif/esp-idf/issues/1934 -#define DEFAULT_N_PAGES 12 -#else -#define DEFAULT_N_PAGES 31 -#endif - #define ADDR_MMR0 0177572 #define ADDR_MMR1 0177574 #define ADDR_MMR2 0177576 @@ -97,6 +89,11 @@ public: bus(); ~bus(); +#if IS_POSIX + json_t *serialize(); + static bus *deserialize(const json_t *const j); +#endif + void reset(); void init(); // invoked by 'RESET' command @@ -111,12 +108,14 @@ public: void mmudebug(const uint16_t a); - void add_cpu (cpu *const c ); - void add_tm11(tm_11 *const tm11 ); - void add_rk05(rk05 *const rk05_); - void add_rl02(rl02 *const rl02_); - void add_tty (tty *const tty_ ); + void add_ram (memory *const m ); + void add_cpu (cpu *const c ); + void add_tm11(tm_11 *const tm11 ); + void add_rk05(rk05 *const rk05_); + void add_rl02(rl02 *const rl02_); + void add_tty (tty *const tty_ ); + memory *getRAM() { return m; } cpu *getCpu() { return c; } kw11_l *getKW11_L() { return kw11_l_; } tty *getTty() { return tty_; } diff --git a/gen.h b/gen.h index 644fc34..46c1f04 100644 --- a/gen.h +++ b/gen.h @@ -15,3 +15,15 @@ typedef enum { rm_prev, rm_cur } rm_selection_t; #define IS_POSIX (defined(linux) || defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))) #define IS_UP (!(IS_POSIX)) /* is microprocessor */ + +#if IS_POSIX +#include +#endif + +#if defined(ESP32) || defined(BUILD_FOR_RP2040) +// ESP32 goes in a crash-loop when allocating 128kB +// see also https://github.com/espressif/esp-idf/issues/1934 +#define DEFAULT_N_PAGES 12 +#else +#define DEFAULT_N_PAGES 31 +#endif diff --git a/main.cpp b/main.cpp index e36e4e9..9dd570c 100644 --- a/main.cpp +++ b/main.cpp @@ -504,6 +504,8 @@ int main(int argc, char *argv[]) if (set_ram_size.has_value()) b->set_memory_size(set_ram_size.value()); + else + b->set_memory_size(DEFAULT_N_PAGES * 8192l); b->set_console_switches(console_switches); diff --git a/memory.h b/memory.h index 4120cd4..265b805 100644 --- a/memory.h +++ b/memory.h @@ -2,13 +2,11 @@ // Released under MIT license #pragma once -#include "gen.h" #include -#if IS_POSIX -#include -#endif #include +#include "gen.h" + class memory { From 10193fbf59b6b4f669eb4b3348deecfbf0579180 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 16:10:09 +0200 Subject: [PATCH 08/19] more serialize code --- bus.cpp | 44 ++++++++++++++++++++++++++++++++++++++++---- bus.h | 16 +++++++++------- kw11-l.cpp | 27 +++++++++++++++++++++++++++ kw11-l.h | 8 ++++++++ tty.cpp | 37 ++++++++++++++++++++++++++++++++++++- tty.h | 8 +++++++- 6 files changed, 127 insertions(+), 13 deletions(-) diff --git a/bus.cpp b/bus.cpp index 2513f81..d9a6e56 100644 --- a/bus.cpp +++ b/bus.cpp @@ -47,17 +47,45 @@ json_t *bus::serialize() { json_t *j_out = json_object(); - json_object_set(j_out, "memory", m->serialize()); + if (m) + json_object_set(j_out, "memory", m->serialize()); + + if (kw11_l_) + json_object_set(j_out, "kw11-l", kw11_l_->serialize()); + + if (tty_) + json_object_set(j_out, "tty", tty_->serialize()); + + // TODO: mmu, cpu, rl02, rk05, tm11 return j_out; } -bus *bus::deserialize(const json_t *const j) +bus *bus::deserialize(const json_t *const j, console *const cnsl) { bus *b = new bus(); - memory *m = memory::deserialize(json_object_get(j, "memory")); - b->add_ram(m); + json_t *temp = nullptr; + + temp = json_object_get(j, "memory"); + if (temp) { + memory *m = memory::deserialize(temp); + b->add_ram(m); + } + + temp = json_object_get(j, "kw11-l"); + if (temp) { + kw11_l *kw11_l_ = kw11_l::deserialize(temp, b, cnsl); + b->add_KW11_L(kw11_l_); + } + + temp = json_object_get(j, "tty"); + if (temp) { + tty *tty_ = tty::deserialize(temp, b, cnsl); + b->add_tty(tty_); + } + + // TODO: mmu, cpu, rl02, rk05, tm11 return b; } @@ -91,6 +119,14 @@ void bus::reset() rl02_->reset(); if (tty_) tty_->reset(); + if (kw11_l_) + kw11_l_->reset(); +} + +void bus::add_KW11_L(kw11_l *const kw11_l_) +{ + delete this->kw11_l_; + this->kw11_l_ = kw11_l_; } void bus::add_ram(memory *const m) diff --git a/bus.h b/bus.h index 8001c4e..af1ed6b 100644 --- a/bus.h +++ b/bus.h @@ -45,6 +45,7 @@ #define ADDR_CCR 0177746 #define ADDR_SYSTEM_ID 0177764 +class console; class cpu; class kw11_l; class memory; @@ -91,7 +92,7 @@ public: #if IS_POSIX json_t *serialize(); - static bus *deserialize(const json_t *const j); + static bus *deserialize(const json_t *const j, console *const cnsl); #endif void reset(); @@ -108,12 +109,13 @@ public: void mmudebug(const uint16_t a); - void add_ram (memory *const m ); - void add_cpu (cpu *const c ); - void add_tm11(tm_11 *const tm11 ); - void add_rk05(rk05 *const rk05_); - void add_rl02(rl02 *const rl02_); - void add_tty (tty *const tty_ ); + void add_ram (memory *const m ); + void add_cpu (cpu *const c ); + void add_tm11 (tm_11 *const tm11 ); + void add_rk05 (rk05 *const rk05_ ); + void add_rl02 (rl02 *const rl02_ ); + void add_tty (tty *const tty_ ); + void add_KW11_L(kw11_l *const kw11_l_); memory *getRAM() { return m; } cpu *getCpu() { return c; } diff --git a/kw11-l.cpp b/kw11-l.cpp index 449bfb2..350afc3 100644 --- a/kw11-l.cpp +++ b/kw11-l.cpp @@ -57,6 +57,11 @@ void kw11_l::begin(console *const cnsl) #endif } +void kw11_l::reset() +{ + lf_csr = 0; +} + void kw11_l::operator()() { set_thread_name("kek:kw-11l"); @@ -154,3 +159,25 @@ uint8_t kw11_l::get_lf_crs() return rc; } + +#if IS_POSIX +json_t *kw11_l::serialize() +{ + json_t *j = json_object(); + + json_object_set(j, "CSR", json_integer(lf_csr)); + + return j; +} + +kw11_l *kw11_l::deserialize(const json_t *const j, bus *const b, console *const cnsl) +{ + uint16_t CSR = json_integer_value(json_object_get(j, "CSR")); + + kw11_l *out = new kw11_l(b); + out->lf_csr = CSR; + out->begin(cnsl); + + return out; +} +#endif diff --git a/kw11-l.h b/kw11-l.h index 666ac40..32c6bed 100644 --- a/kw11-l.h +++ b/kw11-l.h @@ -6,6 +6,7 @@ #include "bus.h" #include "console.h" +#include "gen.h" class kw11_l @@ -31,6 +32,13 @@ public: kw11_l(bus *const b); virtual ~kw11_l(); + void reset(); + +#if IS_POSIX + json_t *serialize(); + static kw11_l *deserialize(const json_t *const j, bus *const b, console *const cnsl); +#endif + void begin(console *const cnsl); void operator()(); diff --git a/tty.cpp b/tty.cpp index 312cba6..57494a1 100644 --- a/tty.cpp +++ b/tty.cpp @@ -1,4 +1,4 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #include @@ -193,3 +193,38 @@ void tty::writeWord(const uint16_t addr, uint16_t v) DOLOG(debug, false, "set register %o to %o", addr, v); registers[(addr - PDP11TTY_BASE) / 2] = v; } + +#if IS_POSIX +json_t *tty::serialize() +{ + json_t *j = json_object(); + + json_t *ja_reg = json_array(); + for(size_t i=0; i<4; i++) + json_array_append(ja_reg, json_integer(registers[i])); + json_object_set(j, "registers", ja_reg); + + json_t *ja_buf = json_array(); + for(auto & c: chars) + json_array_append(ja_buf, json_integer(c)); + json_object_set(j, "input-buffer", ja_buf); + + return j; +} + +tty *tty::deserialize(const json_t *const j, bus *const b, console *const cnsl) +{ + tty *out = new tty(cnsl, b); + + json_t *ja_reg = json_object_get(j, "registers"); + for(size_t i=0; i<4; i++) + out->registers[i] = json_integer_value(json_array_get(ja_reg, i)); + + json_t *ja_buf = json_object_get(j, "input-buffer"); + size_t buf_size = json_array_size(ja_buf); + for(size_t i=0; ichars.push_back(json_integer_value(json_array_get(ja_buf, i))); + + return out; +} +#endif diff --git a/tty.h b/tty.h index b14c96e..6702889 100644 --- a/tty.h +++ b/tty.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 @@ -13,6 +13,7 @@ #include "bus.h" #include "console.h" +#include "gen.h" #define PDP11TTY_TKS 0177560 // reader status @@ -50,6 +51,11 @@ public: tty(console *const c, bus *const b); virtual ~tty(); +#if IS_POSIX + json_t *serialize(); + static tty *deserialize(const json_t *const j, bus *const b, console *const cnsl); +#endif + void reset(); uint8_t readByte(const uint16_t addr); From 6c7529971d10287f0468e80093980d65a7fe6c92 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 17:00:04 +0200 Subject: [PATCH 09/19] mmu ser/deser --- bus.cpp | 17 ++++++++++++- bus.h | 1 + mmu.cpp | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mmu.h | 10 ++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/bus.cpp b/bus.cpp index d9a6e56..c69d1dd 100644 --- a/bus.cpp +++ b/bus.cpp @@ -56,7 +56,10 @@ json_t *bus::serialize() if (tty_) json_object_set(j_out, "tty", tty_->serialize()); - // TODO: mmu, cpu, rl02, rk05, tm11 + if (mmu_) + json_object_set(j_out, "mmu", mmu_->serialize()); + + // TODO: cpu, rl02, rk05, tm11 return j_out; } @@ -85,6 +88,12 @@ bus *bus::deserialize(const json_t *const j, console *const cnsl) b->add_tty(tty_); } + temp = json_object_get(j, "mmu"); + if (temp) { + mmu *mmu_ = mmu::deserialize(temp); + b->add_mmu(mmu_); + } + // TODO: mmu, cpu, rl02, rk05, tm11 return b; @@ -135,6 +144,12 @@ void bus::add_ram(memory *const m) this->m = m; } +void bus::add_mmu(mmu *const mmu_) +{ + delete this->mmu_; + this->mmu_ = mmu_; +} + void bus::add_cpu(cpu *const c) { delete this->c; diff --git a/bus.h b/bus.h index af1ed6b..d1312ba 100644 --- a/bus.h +++ b/bus.h @@ -111,6 +111,7 @@ public: void add_ram (memory *const m ); void add_cpu (cpu *const c ); + void add_mmu (mmu *const mmu_ ); void add_tm11 (tm_11 *const tm11 ); void add_rk05 (rk05 *const rk05_ ); void add_rl02 (rl02 *const rl02_ ); diff --git a/mmu.cpp b/mmu.cpp index b0083ab..f3eaa7e 100644 --- a/mmu.cpp +++ b/mmu.cpp @@ -220,3 +220,80 @@ void mmu::writeByte(const uint16_t a, const uint8_t value) else if (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END) write_par(a, 3, value, wm_byte); } + +#if IS_POSIX +void mmu::add_par_pdr(json_t *const target, const int run_mode, const bool is_d, const std::string & name) +{ + json_t *j = json_object(); + + json_t *ja_par = json_array(); + for(int i=0; i<8; i++) + json_array_append(ja_par, json_integer(pages[run_mode][is_d][i].par)); + json_object_set(j, "par", ja_par); + + json_t *ja_pdr = json_array(); + for(int i=0; i<8; i++) + json_array_append(ja_pdr, json_integer(pages[run_mode][is_d][i].pdr)); + json_object_set(j, "pdr", ja_pdr); + + json_object_set(target, name.c_str(), j); +} + +json_t *mmu::serialize() +{ + json_t *j = json_object(); + + for(int run_mode=0; run_mode<4; run_mode++) { + if (run_mode == 2) + continue; + + for(int is_d=0; is_d<2; is_d++) + add_par_pdr(j, run_mode, is_d, format("runmode_%d_d_%d", run_mode, is_d)); + } + + json_object_set(j, "MMR0", json_integer(MMR0)); + json_object_set(j, "MMR1", json_integer(MMR1)); + json_object_set(j, "MMR2", json_integer(MMR2)); + json_object_set(j, "MMR3", json_integer(MMR3)); + json_object_set(j, "CPUERR", json_integer(CPUERR)); + json_object_set(j, "PIR", json_integer(PIR)); + json_object_set(j, "CSR", json_integer(CSR)); + + return j; +} + +void mmu::set_par_pdr(const json_t *const j_in, const int run_mode, const bool is_d, const std::string & name) +{ + json_t *j = json_object_get(j_in, name.c_str()); + + json_t *j_par = json_object_get(j, "par"); + for(int i=0; i<8; i++) + pages[run_mode][is_d][i].par = json_integer_value(json_array_get(j_par, i)); + json_t *j_pdr = json_object_get(j, "pdr"); + for(int i=0; i<8; i++) + pages[run_mode][is_d][i].pdr = json_integer_value(json_array_get(j_pdr, i)); +} + +mmu *mmu::deserialize(const json_t *const j) +{ + mmu *m = new mmu(); + + for(int run_mode=0; run_mode<4; run_mode++) { + if (run_mode == 2) + continue; + + for(int is_d=0; is_d<2; is_d++) + m->set_par_pdr(j, run_mode, is_d, format("runmode_%d_d_%d", run_mode, is_d)); + } + + m->MMR0 = json_integer_value(json_object_get(j, "MMR0")); + m->MMR1 = json_integer_value(json_object_get(j, "MMR1")); + m->MMR2 = json_integer_value(json_object_get(j, "MMR2")); + m->MMR3 = json_integer_value(json_object_get(j, "MMR3")); + m->CPUERR = json_integer_value(json_object_get(j, "CPUERR")); + m->PIR = json_integer_value(json_object_get(j, "PIR")); + m->CSR = json_integer_value(json_object_get(j, "CSR")); + + return m; +} +#endif diff --git a/mmu.h b/mmu.h index 22ed44e..3a80c0b 100644 --- a/mmu.h +++ b/mmu.h @@ -1,8 +1,10 @@ #pragma once #include +#include #include "device.h" +#include "gen.h" #define ADDR_PDR_SV_START 0172200 #define ADDR_PDR_SV_END 0172240 @@ -39,10 +41,18 @@ private: uint16_t PIR { 0 }; uint16_t CSR { 0 }; + void add_par_pdr(json_t *const target, const int run_mode, const bool is_d, const std::string & name); + void set_par_pdr(const json_t *const j_in, const int run_mode, const bool is_d, const std::string & name); + public: mmu(); virtual ~mmu(); +#if IS_POSIX + json_t *serialize(); + static mmu *deserialize(const json_t *const j); +#endif + void reset() override; bool is_enabled() const { return MMR0 & 1; } From e0bbef778de7bf0f2453d863f418e2666a4bb9e2 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 19:07:24 +0200 Subject: [PATCH 10/19] serialize --- bus.cpp | 17 ++++++++++---- bus.h | 4 ++-- cpu.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ cpu.h | 6 +++++ debugger.cpp | 27 ++++++++++++++++++++++ memory.cpp | 4 ++-- memory.h | 2 +- mmu.cpp | 4 ++-- mmu.h | 4 ++-- 9 files changed, 118 insertions(+), 13 deletions(-) diff --git a/bus.cpp b/bus.cpp index c69d1dd..3af1f5f 100644 --- a/bus.cpp +++ b/bus.cpp @@ -43,7 +43,7 @@ bus::~bus() } #if IS_POSIX -json_t *bus::serialize() +json_t *bus::serialize() const { json_t *j_out = json_object(); @@ -59,12 +59,15 @@ json_t *bus::serialize() if (mmu_) json_object_set(j_out, "mmu", mmu_->serialize()); - // TODO: cpu, rl02, rk05, tm11 + if (c) + json_object_set(j_out, "cpu", c->serialize()); + + // TODO: rl02, rk05, tm11 return j_out; } -bus *bus::deserialize(const json_t *const j, console *const cnsl) +bus *bus::deserialize(const json_t *const j, console *const cnsl, std::atomic_uint32_t *const event) { bus *b = new bus(); @@ -94,7 +97,13 @@ bus *bus::deserialize(const json_t *const j, console *const cnsl) b->add_mmu(mmu_); } - // TODO: mmu, cpu, rl02, rk05, tm11 + temp = json_object_get(j, "cpu"); + if (temp) { + cpu *cpu_ = cpu::deserialize(temp, b, event); + b->add_cpu(cpu_); + } + + // TODO: rl02, rk05, tm11 return b; } diff --git a/bus.h b/bus.h index d1312ba..b0ae4c8 100644 --- a/bus.h +++ b/bus.h @@ -91,8 +91,8 @@ public: ~bus(); #if IS_POSIX - json_t *serialize(); - static bus *deserialize(const json_t *const j, console *const cnsl); + json_t *serialize() const; + static bus *deserialize(const json_t *const j, console *const cnsl, std::atomic_uint32_t *const event); #endif void reset(); diff --git a/cpu.cpp b/cpu.cpp index d5e9582..8f55edd 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -2395,3 +2395,66 @@ void cpu::step() DOLOG(debug, false, "bus-trap during execution of command (%d)", exception_nr); } } + +#if IS_POSIX +json_t *cpu::serialize() +{ + json_t *j = json_object(); + + for(int set=0; set<2; set++) { + for(int regnr=0; regnr<6; regnr++) + json_object_set(j, format("register-%d-%d", set, regnr).c_str(), json_integer(regs0_5[set][regnr])); + } + + for(int spnr=0; spnr<4; spnr++) + json_object_set(j, format("sp-%d", spnr).c_str(), json_integer(sp[spnr])); + + json_object_set(j, "pc", json_integer(pc)); + json_object_set(j, "instruction_start", json_integer(instruction_start)); + json_object_set(j, "psw", json_integer(psw)); + json_object_set(j, "fpsr", json_integer(fpsr)); + json_object_set(j, "stackLimitRegister", json_integer(stackLimitRegister)); + json_object_set(j, "processing_trap_depth", json_integer(processing_trap_depth)); + json_object_set(j, "instruction_count", json_integer(instruction_count)); + json_object_set(j, "running_since", json_integer(running_since)); + json_object_set(j, "wait_time", json_integer(wait_time)); + json_object_set(j, "it_is_a_trap", json_boolean(it_is_a_trap)); + json_object_set(j, "debug_mode", json_boolean(debug_mode)); + if (trap_delay.has_value()) + json_object_set(j, "trap_delay", json_integer(trap_delay.value())); + + return j; +} + +cpu *cpu::deserialize(const json_t *const j, bus *const b, std::atomic_uint32_t *const event) +{ + cpu *c = new cpu(b, event); + + for(int set=0; set<2; set++) { + for(int regnr=0; regnr<6; regnr++) + c->regs0_5[set][regnr] = json_integer_value(json_object_get(j, format("register-%d-%d", set, regnr).c_str())); + } + + for(int spnr=0; spnr<4; spnr++) + c->sp[spnr] = json_integer_value(json_object_get(j, format("sp-%d", spnr).c_str())); + + c->pc = json_integer_value(json_object_get(j, "pc")); + c->instruction_start = json_integer_value(json_object_get(j, "instruction_start")); + c->psw = json_integer_value(json_object_get(j, "psw")); + c->fpsr = json_integer_value(json_object_get(j, "fpsr")); + c->stackLimitRegister = json_integer_value(json_object_get(j, "stackLimitRegister")); + c->processing_trap_depth = json_integer_value(json_object_get(j, "processing_trap_depth")); + c->instruction_count = json_integer_value(json_object_get(j, "instruction_count")); + c->running_since = get_us(); + c->wait_time = 0; + c->it_is_a_trap = json_boolean_value(json_object_get(j, "it_is_a_trap")); + c->debug_mode = json_boolean_value(json_object_get(j, "debug_mode")); + json_t *temp = json_object_get(j, "trap_delay"); + if (temp) + c->trap_delay = json_integer_value(temp); + else + c->trap_delay.reset(); + + return c; +} +#endif diff --git a/cpu.h b/cpu.h index c968ca2..e5aeab4 100644 --- a/cpu.h +++ b/cpu.h @@ -14,6 +14,7 @@ #include "breakpoint.h" #include "bus.h" +#include "gen.h" constexpr const int initial_trap_delay = 8; @@ -111,6 +112,11 @@ public: explicit cpu(bus *const b, std::atomic_uint32_t *const event); ~cpu(); +#if IS_POSIX + json_t *serialize(); + static cpu *deserialize(const json_t *const j, bus *const b, std::atomic_uint32_t *const event); +#endif + std::optional check_breakpoint(); int set_breakpoint(breakpoint *const bp); bool remove_breakpoint(const int bp_id); diff --git a/debugger.cpp b/debugger.cpp index 7c50e2c..378f75c 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -722,6 +722,25 @@ void show_queued_interrupts(console *const cnsl, cpu *const c) } } +void serialize_state(console *const cnsl, const bus *const b, const std::string & filename) +{ + json_t *j = b->serialize(); + + bool ok = false; + + FILE *fh = fopen(filename.c_str(), "w"); + if (fh) { + if (json_dumpf(j, fh, 0) == 0) + ok = true; + + fclose(fh); + } + + json_decref(j); + + cnsl->put_string_lf(format("Serialize to %s: %s", filename.c_str(), ok ? "OK" : "failed")); +} + void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const bool tracing_in) { int32_t trace_start_addr = -1; @@ -1069,6 +1088,10 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto continue; } + else if (parts[0] == "ser" && parts.size() == 2) { + serialize_state(cnsl, b, parts.at(1)); + continue; + } else if (parts[0] == "setsl" && parts.size() == 3) { setloghost(parts.at(1).c_str(), parse_ll(parts[2])); @@ -1130,6 +1153,10 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto "stats - show run statistics", "ramsize - set ram size (page count (8 kB))", "bl - set bootload (rl02 or rk05)", +#if IS_POSIX + "ser - serialize state to a file", + "dser - deserialize state from a file", +#endif #if defined(ESP32) "cfgnet - configure network (e.g. WiFi)", "startnet - start network", diff --git a/memory.cpp b/memory.cpp index 9761814..ed6b3f5 100644 --- a/memory.cpp +++ b/memory.cpp @@ -29,7 +29,7 @@ void memory::reset() } #if IS_POSIX -json_t *memory::serialize() +json_t *memory::serialize() const { json_t *j = json_object(); @@ -50,7 +50,7 @@ memory *memory::deserialize(const json_t *const j) json_t *ja = json_object_get(j, "contents"); for(size_t i=0; iwriteByte(i, json_integer_value(json_array_get(ja, i))); + m->m[i] = json_integer_value(json_array_get(ja, i)); return m; } diff --git a/memory.h b/memory.h index 265b805..1a5dcbc 100644 --- a/memory.h +++ b/memory.h @@ -20,7 +20,7 @@ public: void reset(); #if IS_POSIX - json_t *serialize(); + json_t *serialize() const; static memory *deserialize(const json_t *const j); #endif diff --git a/mmu.cpp b/mmu.cpp index f3eaa7e..5e42949 100644 --- a/mmu.cpp +++ b/mmu.cpp @@ -222,7 +222,7 @@ void mmu::writeByte(const uint16_t a, const uint8_t value) } #if IS_POSIX -void mmu::add_par_pdr(json_t *const target, const int run_mode, const bool is_d, const std::string & name) +void mmu::add_par_pdr(json_t *const target, const int run_mode, const bool is_d, const std::string & name) const { json_t *j = json_object(); @@ -239,7 +239,7 @@ void mmu::add_par_pdr(json_t *const target, const int run_mode, const bool is_d, json_object_set(target, name.c_str(), j); } -json_t *mmu::serialize() +json_t *mmu::serialize() const { json_t *j = json_object(); diff --git a/mmu.h b/mmu.h index 3a80c0b..e78a5da 100644 --- a/mmu.h +++ b/mmu.h @@ -41,7 +41,7 @@ private: uint16_t PIR { 0 }; uint16_t CSR { 0 }; - void add_par_pdr(json_t *const target, const int run_mode, const bool is_d, const std::string & name); + void add_par_pdr(json_t *const target, const int run_mode, const bool is_d, const std::string & name) const; void set_par_pdr(const json_t *const j_in, const int run_mode, const bool is_d, const std::string & name); public: @@ -49,7 +49,7 @@ public: virtual ~mmu(); #if IS_POSIX - json_t *serialize(); + json_t *serialize() const; static mmu *deserialize(const json_t *const j); #endif From 859577479f0d9ee35fef1d29d21be4f7b785ac5f Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 19:21:31 +0200 Subject: [PATCH 11/19] deserialize --- main.cpp | 114 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 43 deletions(-) diff --git a/main.cpp b/main.cpp index 9dd570c..f92a5f8 100644 --- a/main.cpp +++ b/main.cpp @@ -298,6 +298,7 @@ void get_metrics(cpu *const c) void help() { printf("-h this help\n"); + printf("-D x deserialize state from file\n"); printf("-T t.bin load file as a binary tape file (like simh \"load\" command), also for .BIC files\n"); printf("-B run tape file as a unit test (for .BIC files)\n"); printf("-R d.rk load file as a RK05 disk device\n"); @@ -372,14 +373,20 @@ int main(int argc, char *argv[]) bool metrics = false; + std::string deserialize; + int opt = -1; - while((opt = getopt(argc, argv, "hMT:Br:R:p:ndtL:bl:s:Q:N:J:XS:")) != -1) + while((opt = getopt(argc, argv, "hD:MT:Br:R:p:ndtL:bl:s:Q:N:J:XS:")) != -1) { switch(opt) { case 'h': help(); return 1; + case 'D': + deserialize = optarg; + break; + case 'M': metrics = true; break; @@ -500,17 +507,65 @@ int main(int argc, char *argv[]) if (validate_json.empty() == false) return run_cpu_validation(validate_json); - bus *b = new bus(); + bus *b = nullptr; - if (set_ram_size.has_value()) - b->set_memory_size(set_ram_size.value()); - else - b->set_memory_size(DEFAULT_N_PAGES * 8192l); + if (deserialize.empty()) { + b = new bus(); - b->set_console_switches(console_switches); + if (set_ram_size.has_value()) + b->set_memory_size(set_ram_size.value()); + else + b->set_memory_size(DEFAULT_N_PAGES * 8192l); - cpu *c = new cpu(b, &event); - b->add_cpu(c); + b->set_console_switches(console_switches); + + cpu *c = new cpu(b, &event); + b->add_cpu(c); + + if (rk05_files.empty() == false) { + if (enable_bootloader == false) + DOLOG(warning, true, "Note: loading RK05 with no (RK05-) bootloader selected"); + else + bootloader = BL_RK05; + + b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); + } + + if (rl02_files.empty() == false) { + if (enable_bootloader == false) + DOLOG(warning, true, "Note: loading RL02 with no (RL02-) bootloader selected"); + else + bootloader = BL_RL02; + + b->add_rl02(new rl02(rl02_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); + } + + if (enable_bootloader) + setBootLoader(b, bootloader); + + tty *tty_ = new tty(cnsl, b); + + b->add_tty(tty_); + } + else { + FILE *fh = fopen(deserialize.c_str(), "r"); + if (!fh) + error_exit(true, "Failed to open %s", deserialize.c_str()); + + json_error_t je { }; + json_t *j = json_loadf(fh, 0, &je); + + fclose(fh); + + if (!j) + error_exit(true, "State file %s is corrupt: %s", deserialize.c_str(), je.text); + + b = bus::deserialize(j, cnsl, &event); + + json_decref(j); + } + + running = cnsl->get_running_flag(); std::atomic_bool interrupt_emulation { false }; @@ -522,11 +577,11 @@ int main(int argc, char *argv[]) if (bic_start.has_value() == false) return 1; // fail - c->setRegister(7, bic_start.value()); + b->getCpu()->setRegister(7, bic_start.value()); } if (sa_set) - c->setRegister(7, start_addr); + b->getCpu()->setRegister(7, start_addr); #if !defined(_WIN32) if (withUI) @@ -541,34 +596,7 @@ int main(int argc, char *argv[]) cnsl = new console_posix(&event, b); } - if (rk05_files.empty() == false) { - if (enable_bootloader == false) - DOLOG(warning, true, "Note: loading RK05 with no (RK05-) bootloader selected"); - else - bootloader = BL_RK05; - - b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); - } - - if (rl02_files.empty() == false) { - if (enable_bootloader == false) - DOLOG(warning, true, "Note: loading RL02 with no (RL02-) bootloader selected"); - else - bootloader = BL_RL02; - - b->add_rl02(new rl02(rl02_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); - } - - if (enable_bootloader) - setBootLoader(b, bootloader); - - running = cnsl->get_running_flag(); - - tty *tty_ = new tty(cnsl, b); - - b->add_tty(tty_); - - DOLOG(info, true, "Start running at %06o", c->getRegister(7)); + DOLOG(info, true, "Start running at %06o", b->getCpu()->getRegister(7)); #if !defined(_WIN32) struct sigaction sa { }; @@ -588,7 +616,7 @@ int main(int argc, char *argv[]) std::thread *metrics_thread = nullptr; if (metrics) - metrics_thread = new std::thread(get_metrics, c); + metrics_thread = new std::thread(get_metrics, b->getCpu()); cnsl->start_thread(); @@ -599,13 +627,13 @@ int main(int argc, char *argv[]) else if (run_debugger || (bootloader == BL_NONE && test.empty() && tape.empty())) debugger(cnsl, b, &event, tracing); else { - c->emulation_start(); // for statistics + b->getCpu()->emulation_start(); // for statistics for(;;) { *running = true; while(event == EVENT_NONE) - c->step(); + b->getCpu()->step(); *running = false; @@ -615,7 +643,7 @@ int main(int argc, char *argv[]) break; } - auto stats = c->get_mips_rel_speed({ }, { }); + auto stats = b->getCpu()->get_mips_rel_speed({ }, { }); cnsl->put_string_lf(format("MIPS: %.2f, relative speed: %.2f%%, instructions executed: %" PRIu64 " in %.2f seconds", std::get<0>(stats), std::get<1>(stats), std::get<2>(stats), std::get<3>(stats) / 1000000.)); } From 4eb557cbc5fc6e85d50f163b4837eef0a9fa27da Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 20:04:27 +0200 Subject: [PATCH 12/19] RL02 serialization --- bus.cpp | 13 ++++++-- disk_backend.cpp | 22 +++++++++++++- disk_backend.h | 9 +++++- disk_backend_file.cpp | 20 +++++++++++++ disk_backend_file.h | 7 ++++- disk_backend_nbd.cpp | 21 +++++++++++++ disk_backend_nbd.h | 6 ++++ rl02.cpp | 70 ++++++++++++++++++++++++++++++++++++++----- rl02.h | 12 ++++++-- 9 files changed, 165 insertions(+), 15 deletions(-) diff --git a/bus.cpp b/bus.cpp index 3af1f5f..5d73884 100644 --- a/bus.cpp +++ b/bus.cpp @@ -62,7 +62,10 @@ json_t *bus::serialize() const if (c) json_object_set(j_out, "cpu", c->serialize()); - // TODO: rl02, rk05, tm11 + if (rl02_) + json_object_set(j_out, "rl02", rl02_->serialize()); + + // TODO: rk05, tm11 return j_out; } @@ -103,7 +106,13 @@ bus *bus::deserialize(const json_t *const j, console *const cnsl, std::atomic_ui b->add_cpu(cpu_); } - // TODO: rl02, rk05, tm11 + temp = json_object_get(j, "rl02"); + if (temp) { + rl02 *rl02_ = rl02::deserialize(temp, b); + b->add_rl02(rl02_); + } + + // TODO: rk05, tm11 return b; } diff --git a/disk_backend.cpp b/disk_backend.cpp index 54dfc37..1b4de50 100644 --- a/disk_backend.cpp +++ b/disk_backend.cpp @@ -1,7 +1,10 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #include "disk_backend.h" +#include "disk_backend_file.h" +#include "disk_backend_nbd.h" + disk_backend::disk_backend() { @@ -10,3 +13,20 @@ disk_backend::disk_backend() disk_backend::~disk_backend() { } + +#if IS_POSIX +disk_backend *disk_backend::deserialize(const json_t *const j) +{ + std::string type = json_string_value(json_object_get(j, "disk-backend-type")); + + if (type == "file") + return disk_backend_file::deserialize(j); + + if (type == "nbd") + return disk_backend_nbd::deserialize(j); + + // should not be reached + + return nullptr; +} +#endif diff --git a/disk_backend.h b/disk_backend.h index e8754c8..141c2d8 100644 --- a/disk_backend.h +++ b/disk_backend.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,6 +6,8 @@ #include #include +#include "gen.h" + class disk_backend { @@ -13,6 +15,11 @@ public: disk_backend(); virtual ~disk_backend(); +#if IS_POSIX + virtual json_t *serialize() const = 0; + static disk_backend *deserialize(const json_t *const j); +#endif + virtual bool begin() = 0; virtual bool read(const off_t offset, const size_t n, uint8_t *const target) = 0; diff --git a/disk_backend_file.cpp b/disk_backend_file.cpp index 328075a..127faa3 100644 --- a/disk_backend_file.cpp +++ b/disk_backend_file.cpp @@ -19,6 +19,26 @@ disk_backend_file::~disk_backend_file() close(fd); } +#if IS_POSIX +json_t *disk_backend_file::serialize() const +{ + json_t *j = json_object(); + + json_object_set(j, "disk-backend-type", json_string("file")); + + // TODO store checksum of backend + json_object_set(j, "filename", json_string(filename.c_str())); + + return j; +} + +disk_backend_file *disk_backend_file::deserialize(const json_t *const j) +{ + // TODO verify checksum of backend + return new disk_backend_file(json_string_value(json_object_get(j, "filename"))); +} +#endif + bool disk_backend_file::begin() { fd = open(filename.c_str(), O_RDWR); diff --git a/disk_backend_file.h b/disk_backend_file.h index 652c81d..d02ef0d 100644 --- a/disk_backend_file.h +++ b/disk_backend_file.h @@ -1,4 +1,4 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #include @@ -17,6 +17,11 @@ public: disk_backend_file(const std::string & filename); virtual ~disk_backend_file(); +#if IS_POSIX + json_t *serialize() const override; + static disk_backend_file *deserialize(const json_t *const j); +#endif + bool begin() override; bool read(const off_t offset, const size_t n, uint8_t *const target) override; diff --git a/disk_backend_nbd.cpp b/disk_backend_nbd.cpp index 7e3c7fd..6f85c00 100644 --- a/disk_backend_nbd.cpp +++ b/disk_backend_nbd.cpp @@ -47,6 +47,27 @@ disk_backend_nbd::~disk_backend_nbd() close(fd); } +#if IS_POSIX +json_t *disk_backend_nbd::serialize() const +{ + json_t *j = json_object(); + + json_object_set(j, "disk-backend-type", json_string("nbd")); + + // TODO store checksum of backend + json_object_set(j, "host", json_string(host.c_str())); + json_object_set(j, "port", json_integer(port)); + + return j; +} + +disk_backend_nbd *disk_backend_nbd::deserialize(const json_t *const j) +{ + // TODO verify checksum of backend + return new disk_backend_nbd(json_string_value(json_object_get(j, "host")), json_integer_value(json_object_get(j, "port"))); +} +#endif + bool disk_backend_nbd::begin() { if (!connect(false)) { diff --git a/disk_backend_nbd.h b/disk_backend_nbd.h index 70f65aa..b6679a8 100644 --- a/disk_backend_nbd.h +++ b/disk_backend_nbd.h @@ -5,6 +5,7 @@ #include #include "disk_backend.h" +#include "gen.h" class disk_backend_nbd : public disk_backend @@ -20,6 +21,11 @@ public: disk_backend_nbd(const std::string & host, const unsigned port); virtual ~disk_backend_nbd(); +#if IS_POSIX + json_t *serialize() const override; + static disk_backend_nbd *deserialize(const json_t *const j); +#endif + bool begin() override; bool read(const off_t offset, const size_t n, uint8_t *const target) override; diff --git a/rl02.cpp b/rl02.cpp index f34a562..25b57af 100644 --- a/rl02.cpp +++ b/rl02.cpp @@ -31,10 +31,10 @@ static const char * const commands[] = { "read data w/o header check" }; -rl02::rl02(const std::vector & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity) : +rl02::rl02(const std::vector & files, bus *const b, std::atomic_bool *const disk_read_activity, std::atomic_bool *const disk_write_activity) : b(b), - disk_read_acitivity(disk_read_acitivity), - disk_write_acitivity(disk_write_acitivity) + disk_read_activity (disk_read_activity), + disk_write_activity(disk_write_activity) { fhs = files; @@ -58,6 +58,54 @@ void rl02::reset() sector = 0; } +#if IS_POSIX +json_t *rl02::serialize() const +{ + json_t *j = json_object(); + + json_t *j_backends = json_array(); + for(auto & dbe: fhs) + json_array_append(j_backends, dbe->serialize()); + + json_object_set(j, "backends", j_backends); + + for(int regnr=0; regnr<4; regnr++) + json_object_set(j, format("register-%d", regnr).c_str(), json_integer(registers[regnr])); + + for(int mprnr=0; mprnr<3; mprnr++) + json_object_set(j, format("mpr-%d", mprnr).c_str(), json_integer(mpr[mprnr])); + + json_object_set(j, "track", json_integer(track)); + json_object_set(j, "head", json_integer(head)); + json_object_set(j, "sector", json_integer(sector)); + + return j; +} + +rl02 *rl02::deserialize(const json_t *const j, bus *const b) +{ + std::vector backends; + + json_t *j_backends = json_object_get(j, "backends"); + for(size_t i=0; iregisters[regnr] = json_integer_value(json_object_get(j, format("register-%d", regnr).c_str())); + + for(int mprnr=0; mprnr<3; mprnr++) + r->mpr[mprnr] = json_integer_value(json_object_get(j, format("mpr-%d", mprnr).c_str())); + + r->track = json_integer_value(json_object_get(j, "track" )); + r->head = json_integer_value(json_object_get(j, "head" )); + r->sector = json_integer_value(json_object_get(j, "sector")); + + return r; +} +#endif + uint8_t rl02::readByte(const uint16_t addr) { uint16_t v = readWord(addr & ~1); @@ -152,8 +200,6 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) bool do_int = false; - *disk_read_acitivity = true; - if (size_t(device) >= fhs.size()) { DOLOG(info, false, "RL02: PDP11/70 is accessing a not-attached virtual disk %d", device); @@ -194,6 +240,9 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) do_int = true; } else if (command == 5) { // write data + if (disk_write_activity) + *disk_write_activity = true; + uint32_t memory_address = get_bus_address(); uint32_t count = (65536l - registers[(RL02_MPR - RL02_BASE) / 2]) * 2; @@ -247,8 +296,14 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) } do_int = true; + + if (disk_write_activity) + *disk_write_activity = false; } else if (command == 6 || command == 7) { // read data / read data without header check + if (disk_read_activity) + *disk_read_activity = true; + uint32_t memory_address = get_bus_address(); uint32_t count = (65536l - registers[(RL02_MPR - RL02_BASE) / 2]) * 2; @@ -305,6 +360,9 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) } do_int = true; + + if (disk_read_activity) + *disk_read_activity = false; } else { DOLOG(warning, false, "RL02: command %d not implemented", command); @@ -317,7 +375,5 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) b->getCpu()->queue_interrupt(5, 0160); } } - - *disk_read_acitivity = false; } } diff --git a/rl02.h b/rl02.h index 64bc4d6..4a9858e 100644 --- a/rl02.h +++ b/rl02.h @@ -11,6 +11,7 @@ #include "device.h" #include "disk_backend.h" +#include "gen.h" #define RL02_CSR 0174400 // control status register @@ -38,8 +39,8 @@ private: uint16_t mpr[3]; std::vector fhs; - std::atomic_bool *const disk_read_acitivity { nullptr }; - std::atomic_bool *const disk_write_acitivity { nullptr }; + std::atomic_bool *const disk_read_activity { nullptr }; + std::atomic_bool *const disk_write_activity { nullptr }; uint32_t get_bus_address() const; void update_bus_address(const uint32_t a); @@ -47,11 +48,16 @@ private: uint32_t calc_offset() const; public: - rl02(const std::vector & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity); + rl02(const std::vector & files, bus *const b, std::atomic_bool *const disk_read_activity, std::atomic_bool *const disk_write_activity); virtual ~rl02(); void reset() override; +#if IS_POSIX + json_t *serialize() const; + static rl02 *deserialize(const json_t *const j, bus *const b); +#endif + uint8_t readByte(const uint16_t addr) override; uint16_t readWord(const uint16_t addr) override; From e020ff525fe4142e07bbe6614e4992bf2b294385 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 20:05:31 +0200 Subject: [PATCH 13/19] only compile state-serialization on posix --- debugger.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debugger.cpp b/debugger.cpp index 378f75c..2df2051 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -722,6 +722,7 @@ void show_queued_interrupts(console *const cnsl, cpu *const c) } } +#if IS_POSIX void serialize_state(console *const cnsl, const bus *const b, const std::string & filename) { json_t *j = b->serialize(); @@ -740,6 +741,7 @@ void serialize_state(console *const cnsl, const bus *const b, const std::string cnsl->put_string_lf(format("Serialize to %s: %s", filename.c_str(), ok ? "OK" : "failed")); } +#endif void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const bool tracing_in) { @@ -1088,10 +1090,12 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto continue; } +#if IS_POSIX else if (parts[0] == "ser" && parts.size() == 2) { serialize_state(cnsl, b, parts.at(1)); continue; } +#endif else if (parts[0] == "setsl" && parts.size() == 3) { setloghost(parts.at(1).c_str(), parse_ll(parts[2])); From 5ded69d437dae31b4cfb3460042145b00cee1546 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 20:07:00 +0200 Subject: [PATCH 14/19] readable state --- debugger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debugger.cpp b/debugger.cpp index 2df2051..30da333 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -731,7 +731,7 @@ void serialize_state(console *const cnsl, const bus *const b, const std::string FILE *fh = fopen(filename.c_str(), "w"); if (fh) { - if (json_dumpf(j, fh, 0) == 0) + if (json_dumpf(j, fh, JSON_INDENT(4)) == 0) ok = true; fclose(fh); From 0a2f508e616bc0440dd70cf5088828bd6de71c15 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 20:30:43 +0200 Subject: [PATCH 15/19] several fixes for serialization --- console.cpp | 5 +++-- console.h | 6 ++++-- console_ncurses.cpp | 3 +-- console_ncurses.h | 2 +- console_posix.cpp | 3 +-- console_posix.h | 2 +- disk_backend.cpp | 1 + main.cpp | 36 +++++++++++++++++++----------------- rl02.cpp | 2 +- 9 files changed, 32 insertions(+), 28 deletions(-) diff --git a/console.cpp b/console.cpp index 47beb3d..f656aed 100644 --- a/console.cpp +++ b/console.cpp @@ -25,9 +25,8 @@ void thread_wrapper_console(void *p) } #endif -console::console(std::atomic_uint32_t *const stop_event, bus *const b, const int t_width, const int t_height) : +console::console(std::atomic_uint32_t *const stop_event, const int t_width, const int t_height) : stop_event(stop_event), - b(b), t_width(t_width), t_height(t_height) { @@ -49,6 +48,8 @@ console::~console() void console::start_thread() { + assert(b); + stop_thread_flag = false; #if defined(BUILD_FOR_RP2040) diff --git a/console.h b/console.h index 5680350..5cb932f 100644 --- a/console.h +++ b/console.h @@ -31,7 +31,7 @@ private: protected: std::atomic_uint32_t *const stop_event { nullptr }; - bus *const b { nullptr }; + bus *b { nullptr }; #if !defined(BUILD_FOR_RP2040) std::thread *th { nullptr }; #endif @@ -57,9 +57,11 @@ protected: virtual void put_char_ll(const char c) = 0; public: - console(std::atomic_uint32_t *const stop_event, bus *const b, const int t_width = 80, const int t_height = 25); + console(std::atomic_uint32_t *const stop_event, const int t_width = 80, const int t_height = 25); virtual ~console(); + void set_bus(bus *const b) { this->b = b; } + void start_thread(); void stop_thread(); diff --git a/console_ncurses.cpp b/console_ncurses.cpp index 025a2ce..df2e736 100644 --- a/console_ncurses.cpp +++ b/console_ncurses.cpp @@ -13,8 +13,7 @@ #include "utils.h" -console_ncurses::console_ncurses(std::atomic_uint32_t *const stop_event, bus *const b) : - console(stop_event, b) +console_ncurses::console_ncurses(std::atomic_uint32_t *const stop_event): console(stop_event) { init_ncurses(true); diff --git a/console_ncurses.h b/console_ncurses.h index 30eb9ae..99ca686 100644 --- a/console_ncurses.h +++ b/console_ncurses.h @@ -29,7 +29,7 @@ protected: void put_char_ll(const char c) override; public: - console_ncurses(std::atomic_uint32_t *const stop_event, bus *const b); + console_ncurses(std::atomic_uint32_t *const stop_event); virtual ~console_ncurses(); void put_string_lf(const std::string & what) override; diff --git a/console_posix.cpp b/console_posix.cpp index 5d9b9ee..02f7a13 100644 --- a/console_posix.cpp +++ b/console_posix.cpp @@ -16,8 +16,7 @@ #include "error.h" -console_posix::console_posix(std::atomic_uint32_t *const stop_event, bus *const b) : - console(stop_event, b) +console_posix::console_posix(std::atomic_uint32_t *const stop_event): console(stop_event) { #if !defined(_WIN32) if (tcgetattr(STDIN_FILENO, &org_tty_opts) == -1) diff --git a/console_posix.h b/console_posix.h index 661c3d7..aabf323 100644 --- a/console_posix.h +++ b/console_posix.h @@ -21,7 +21,7 @@ protected: void put_char_ll(const char c) override; public: - console_posix(std::atomic_uint32_t *const stop_event, bus *const b); + console_posix(std::atomic_uint32_t *const stop_event); virtual ~console_posix(); void resize_terminal() override; diff --git a/disk_backend.cpp b/disk_backend.cpp index 1b4de50..b1cb17d 100644 --- a/disk_backend.cpp +++ b/disk_backend.cpp @@ -26,6 +26,7 @@ disk_backend *disk_backend::deserialize(const json_t *const j) return disk_backend_nbd::deserialize(j); // should not be reached + assert(false); return nullptr; } diff --git a/main.cpp b/main.cpp index f92a5f8..c9505e4 100644 --- a/main.cpp +++ b/main.cpp @@ -507,6 +507,17 @@ int main(int argc, char *argv[]) if (validate_json.empty() == false) return run_cpu_validation(validate_json); + DOLOG(info, true, "This PDP-11 emulator is called \"kek\" (reason for that is forgotten) and was written by Folkert van Heusden."); + + DOLOG(info, true, "Built on: " __DATE__ " " __TIME__); + +#if !defined(_WIN32) + if (withUI) + cnsl = new console_ncurses(&event); + else +#endif + cnsl = new console_posix(&event); + bus *b = nullptr; if (deserialize.empty()) { @@ -542,10 +553,6 @@ int main(int argc, char *argv[]) if (enable_bootloader) setBootLoader(b, bootloader); - - tty *tty_ = new tty(cnsl, b); - - b->add_tty(tty_); } else { FILE *fh = fopen(deserialize.c_str(), "r"); @@ -565,6 +572,14 @@ int main(int argc, char *argv[]) json_decref(j); } + if (b->getTty() == nullptr) { + tty *tty_ = new tty(cnsl, b); + + b->add_tty(tty_); + } + + cnsl->set_bus(b); + running = cnsl->get_running_flag(); std::atomic_bool interrupt_emulation { false }; @@ -583,19 +598,6 @@ int main(int argc, char *argv[]) if (sa_set) b->getCpu()->setRegister(7, start_addr); -#if !defined(_WIN32) - if (withUI) - cnsl = new console_ncurses(&event, b); - else -#endif - { - DOLOG(info, true, "This PDP-11 emulator is called \"kek\" (reason for that is forgotten) and was written by Folkert van Heusden."); - - DOLOG(info, true, "Built on: " __DATE__ " " __TIME__); - - cnsl = new console_posix(&event, b); - } - DOLOG(info, true, "Start running at %06o", b->getCpu()->getRegister(7)); #if !defined(_WIN32) diff --git a/rl02.cpp b/rl02.cpp index 25b57af..0256c86 100644 --- a/rl02.cpp +++ b/rl02.cpp @@ -33,7 +33,7 @@ static const char * const commands[] = { rl02::rl02(const std::vector & files, bus *const b, std::atomic_bool *const disk_read_activity, std::atomic_bool *const disk_write_activity) : b(b), - disk_read_activity (disk_read_activity), + disk_read_activity (disk_read_activity ), disk_write_activity(disk_write_activity) { fhs = files; From 7c0133dc8d13164df597e73ebe1d1a4f707cc194 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 22:18:17 +0200 Subject: [PATCH 16/19] queued interrupts were not stored --- cpu.cpp | 24 ++++++++++++++++++++++++ cpu.h | 2 +- disk_backend.cpp | 18 ++++++++++++------ main.cpp | 3 +++ 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/cpu.cpp b/cpu.cpp index 8f55edd..3a024b6 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -2423,6 +2423,18 @@ json_t *cpu::serialize() if (trap_delay.has_value()) json_object_set(j, "trap_delay", json_integer(trap_delay.value())); + json_t *j_queued_interrupts = json_object(); + for(auto & il: queued_interrupts) { + json_t *ja_qi_level = json_array(); + for(auto & v: il.second) + json_array_append(ja_qi_level, json_integer(v)); + + json_object_set(j_queued_interrupts, format("%d", il.first).c_str(), ja_qi_level); + } + json_object_set(j, "queued_interrupts", j_queued_interrupts); + + json_object_set(j, "any_queued_interrupts", json_boolean(any_queued_interrupts)); + return j; } @@ -2454,6 +2466,18 @@ cpu *cpu::deserialize(const json_t *const j, bus *const b, std::atomic_uint32_t c->trap_delay = json_integer_value(temp); else c->trap_delay.reset(); + c->any_queued_interrupts = json_boolean_value(json_object_get(j, "any_queued_interrupts")); + + c->init_interrupt_queue(); + json_t *j_queued_interrupts = json_object_get(j, "queued_interrupts"); + for(int level=0; level<8; level++) { + auto it = c->queued_interrupts.find(level); + + json_t *ja_qi_level = json_object_get(j_queued_interrupts, format("%d", level).c_str()); + + for(size_t i=0; isecond.insert(json_integer_value(json_array_get(ja_qi_level, i))); + } return c; } diff --git a/cpu.h b/cpu.h index e5aeab4..98d2430 100644 --- a/cpu.h +++ b/cpu.h @@ -62,6 +62,7 @@ private: // level, vector std::map > queued_interrupts; + std::atomic_bool any_queued_interrupts { false }; #if defined(BUILD_FOR_RP2040) SemaphoreHandle_t qi_lock { xSemaphoreCreateBinary() }; QueueHandle_t qi_q { xQueueCreate(16, 1) }; @@ -69,7 +70,6 @@ private: std::mutex qi_lock; std::condition_variable qi_cv; #endif - std::atomic_bool any_queued_interrupts { false }; std::map breakpoints; int bp_nr { 0 }; diff --git a/disk_backend.cpp b/disk_backend.cpp index b1cb17d..971be4a 100644 --- a/disk_backend.cpp +++ b/disk_backend.cpp @@ -1,6 +1,8 @@ // (C) 2018-2024 by Folkert van Heusden // Released under MIT license +#include + #include "disk_backend.h" #include "disk_backend_file.h" #include "disk_backend_nbd.h" @@ -17,17 +19,21 @@ disk_backend::~disk_backend() #if IS_POSIX disk_backend *disk_backend::deserialize(const json_t *const j) { - std::string type = json_string_value(json_object_get(j, "disk-backend-type")); + std::string type = json_string_value(json_object_get(j, "disk-backend-type")); + + disk_backend *d = nullptr; if (type == "file") - return disk_backend_file::deserialize(j); + d = disk_backend_file::deserialize(j); - if (type == "nbd") - return disk_backend_nbd::deserialize(j); + else if (type == "nbd") + d = disk_backend_nbd::deserialize(j); // should not be reached - assert(false); + assert(d); - return nullptr; + d->begin(); + + return d; } #endif diff --git a/main.cpp b/main.cpp index c9505e4..d25804c 100644 --- a/main.cpp +++ b/main.cpp @@ -570,6 +570,9 @@ int main(int argc, char *argv[]) b = bus::deserialize(j, cnsl, &event); json_decref(j); + + DOLOG(warning, true, "DO NOT FORGET TO DELETE AND NOT TO RE-USE THE STATE FILE (\"%s\")! (unless updated)", deserialize.c_str()); + myusleep(251000); } if (b->getTty() == nullptr) { From 1da19f0241e6c099469ed88e8b7525b2ba902fe4 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Thu, 25 Apr 2024 23:59:21 +0200 Subject: [PATCH 17/19] mixed commit: disk overlay for snapshots/state-dumps, compile fixes for ESP32 --- ESP32/console_esp32.cpp | 6 +-- ESP32/console_esp32.h | 4 +- ESP32/console_shabadge.cpp | 4 +- ESP32/console_shabadge.h | 2 +- ESP32/disk_backend_esp32.cpp | 6 +-- ESP32/disk_backend_esp32.h | 8 ++-- ESP32/main.ino | 9 ++-- ESP32/mmu.cpp | 1 + ESP32/mmu.h | 1 + debugger.cpp | 6 +-- disk_backend.cpp | 81 +++++++++++++++++++++++++++++++++++- disk_backend.h | 26 ++++++++++-- disk_backend_file.cpp | 48 +++++++++++++++------ disk_backend_file.h | 8 ++-- disk_backend_nbd.cpp | 45 ++++++++++++++++---- disk_backend_nbd.h | 11 +++-- gen.h | 7 +++- main.cpp | 52 ++++++++++------------- mmu.h | 2 + rk05.cpp | 4 +- rl02.cpp | 4 +- 21 files changed, 244 insertions(+), 91 deletions(-) create mode 120000 ESP32/mmu.cpp create mode 120000 ESP32/mmu.h diff --git a/ESP32/console_esp32.cpp b/ESP32/console_esp32.cpp index 690a1b6..d4efeb0 100644 --- a/ESP32/console_esp32.cpp +++ b/ESP32/console_esp32.cpp @@ -1,4 +1,4 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #include @@ -13,8 +13,8 @@ #define NEOPIXELS_PIN 25 -console_esp32::console_esp32(std::atomic_uint32_t *const stop_event, bus *const b, std::vector & io_ports, const int t_width, const int t_height) : - console(stop_event, b, t_width, t_height), +console_esp32::console_esp32(std::atomic_uint32_t *const stop_event, std::vector & io_ports, const int t_width, const int t_height) : + console(stop_event, t_width, t_height), io_ports(io_ports) { } diff --git a/ESP32/console_esp32.h b/ESP32/console_esp32.h index fd3aa30..b83aded 100644 --- a/ESP32/console_esp32.h +++ b/ESP32/console_esp32.h @@ -1,4 +1,4 @@ -// (C) 2018-2023 by Folkert van Heusden +// (C) 2018-2024 by Folkert van Heusden // Released under MIT license #include @@ -18,7 +18,7 @@ protected: void put_char_ll(const char c) override; public: - console_esp32(std::atomic_uint32_t *const stop_event, bus *const b, std::vector & io_ports, const int t_width, const int t_height); + console_esp32(std::atomic_uint32_t *const stop_event, std::vector & io_ports, const int t_width, const int t_height); virtual ~console_esp32(); void put_string_lf(const std::string & what) override; diff --git a/ESP32/console_shabadge.cpp b/ESP32/console_shabadge.cpp index 8720724..b8cdf77 100644 --- a/ESP32/console_shabadge.cpp +++ b/ESP32/console_shabadge.cpp @@ -15,8 +15,8 @@ #define COLORED 0 #define UNCOLORED 1 -console_shabadge::console_shabadge(std::atomic_uint32_t *const stop_event, bus *const b, std::vector & io_ports) : - console_esp32(stop_event, b, io_ports, 296 / 8, 128 / 8) +console_shabadge::console_shabadge(std::atomic_uint32_t *const stop_event, std::vector & io_ports) : + console_esp32(stop_event, io_ports, 296 / 8, 128 / 8) { if (epd.Init() != 0) Serial.println("Init of DEPG0290B01 failed"); diff --git a/ESP32/console_shabadge.h b/ESP32/console_shabadge.h index 8a77cb2..bf09419 100644 --- a/ESP32/console_shabadge.h +++ b/ESP32/console_shabadge.h @@ -22,7 +22,7 @@ private: void put_char_ll(const char c) override; public: - console_shabadge(std::atomic_uint32_t *const stop_event, bus *const b, std::vector & io_ports); + console_shabadge(std::atomic_uint32_t *const stop_event, std::vector & io_ports); virtual ~console_shabadge(); void panel_update_thread() override; diff --git a/ESP32/disk_backend_esp32.cpp b/ESP32/disk_backend_esp32.cpp index fdc33c5..9f42509 100644 --- a/ESP32/disk_backend_esp32.cpp +++ b/ESP32/disk_backend_esp32.cpp @@ -29,7 +29,7 @@ void disk_backend_esp32::emit_error() DOLOG(ll_error, true, "SdFat error: %d/%d", sd.sdErrorCode(), sd.sdErrorData()); } -bool disk_backend_esp32::begin() +bool disk_backend_esp32::begin(const bool dummy) { if (!fh->open(filename.c_str(), O_RDWR)) { DOLOG(ll_error, true, "rk05: cannot open \"%s\"", filename.c_str()); @@ -41,7 +41,7 @@ bool disk_backend_esp32::begin() return true; } -bool disk_backend_esp32::read(const off_t offset, const size_t n, uint8_t *const target) +bool disk_backend_esp32::read(const off_t offset, const size_t n, uint8_t *const target, const size_t sector_size) { DOLOG(debug, false, "disk_backend_esp32::read: read %zu bytes from offset %zu", n, offset); @@ -77,7 +77,7 @@ bool disk_backend_esp32::read(const off_t offset, const size_t n, uint8_t *const return true; } -bool disk_backend_esp32::write(const off_t offset, const size_t n, const uint8_t *const from) +bool disk_backend_esp32::write(const off_t offset, const size_t n, const uint8_t *const from, const size_t sector_size) { DOLOG(debug, false, "disk_backend_esp32::write: write %zu bytes to offset %zu", n, offset); diff --git a/ESP32/disk_backend_esp32.h b/ESP32/disk_backend_esp32.h index c24ae51..b0f048a 100644 --- a/ESP32/disk_backend_esp32.h +++ b/ESP32/disk_backend_esp32.h @@ -23,9 +23,11 @@ public: disk_backend_esp32(const std::string & filename); virtual ~disk_backend_esp32(); - bool begin() override; + std::string get_identifier() const { return filename; } - bool read(const off_t offset, const size_t n, uint8_t *const target) override; + bool begin(const bool dummy) override; - bool write(const off_t offset, const size_t n, const uint8_t *const from) override; + bool read(const off_t offset, const size_t n, uint8_t *const target, const size_t sector_size) override; + + bool write(const off_t offset, const size_t n, const uint8_t *const from, const size_t sector_size) override; }; diff --git a/ESP32/main.ino b/ESP32/main.ino index 3407eef..c5fe75c 100644 --- a/ESP32/main.ino +++ b/ESP32/main.ino @@ -38,7 +38,6 @@ #include "esp32.h" #endif #include "gen.h" -#include "kw11-l.h" #include "loaders.h" #include "memory.h" #include "tty.h" @@ -286,13 +285,11 @@ void setup() { std::vector serial_ports { &Serial_RS232, &Serial }; #if defined(SHA2017) - cnsl = new console_shabadge(&stop_event, b, serial_ports); + cnsl = new console_shabadge(&stop_event, serial_ports); #elif defined(ESP32) || defined(BUILD_FOR_RP2040) - cnsl = new console_esp32(&stop_event, b, serial_ports, 80, 25); + cnsl = new console_esp32(&stop_event, serial_ports, 80, 25); #endif - - Serial.println(F("Start line-frequency interrupt")); - kw11_l *lf = new kw11_l(b, cnsl); + cnsl->set_bus(b); running = cnsl->get_running_flag(); diff --git a/ESP32/mmu.cpp b/ESP32/mmu.cpp new file mode 120000 index 0000000..b83d63b --- /dev/null +++ b/ESP32/mmu.cpp @@ -0,0 +1 @@ +../mmu.cpp \ No newline at end of file diff --git a/ESP32/mmu.h b/ESP32/mmu.h new file mode 120000 index 0000000..cc56dfb --- /dev/null +++ b/ESP32/mmu.h @@ -0,0 +1 @@ +../mmu.h \ No newline at end of file diff --git a/debugger.cpp b/debugger.cpp index 30da333..29de1b7 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -125,7 +125,7 @@ std::optional, std::vectorbegin() == false) { + if (d->begin(false) == false) { c->put_string_lf("Cannot initialize NBD client from configuration file"); delete d; return { }; @@ -273,7 +273,7 @@ std::optional, std::vectorbegin() == false) { + if (d->begin(false) == false) { c->put_string_lf("Cannot initialize NBD client"); delete d; return { }; @@ -397,7 +397,7 @@ std::optional, std::vectorbegin()) { + if (!temp->begin(false)) { c->put_string("Cannot use: "); c->put_string_lf(selected_file.c_str()); diff --git a/disk_backend.cpp b/disk_backend.cpp index 971be4a..488ee94 100644 --- a/disk_backend.cpp +++ b/disk_backend.cpp @@ -4,8 +4,10 @@ #include #include "disk_backend.h" +#if IS_POSIX #include "disk_backend_file.h" #include "disk_backend_nbd.h" +#endif disk_backend::disk_backend() @@ -17,6 +19,80 @@ disk_backend::~disk_backend() } #if IS_POSIX +void disk_backend::store_object_in_overlay(const off_t id, const std::vector & data) +{ + overlay.insert_or_assign(id, data); +} + +std::optional > disk_backend::get_object_from_overlay(const off_t id) +{ + auto it = overlay.find(id); + if (it != overlay.end()) + return it->second; + + return { }; +} + +std::optional > disk_backend::get_from_overlay(const off_t offset, const size_t sector_size) +{ + assert((offset % sector_size) == 0); + + if (use_overlay) + return get_object_from_overlay(offset / sector_size); + + return { }; +} + +bool disk_backend::store_mem_range_in_overlay(const off_t offset, const size_t n, const uint8_t *const from, const size_t sector_size) +{ + assert((offset % sector_size) == 0); + assert((n % sector_size) == 0); + + if (use_overlay) { + for(size_t o=0; o(from + o, from + o + sector_size)); + + return true; + } + + return false; +} + +json_t *disk_backend::serialize_overlay() const +{ + json_t *out = json_object(); + + for(auto & id: overlay) { + json_t *j_data = json_array(); + + for(size_t i=0; i data; + for(size_t i=0; ibegin(); + d->deserialize_overlay(j); + + // assume we want snapshots (again?) + d->begin(true); return d; } diff --git a/disk_backend.h b/disk_backend.h index 141c2d8..48fbb20 100644 --- a/disk_backend.h +++ b/disk_backend.h @@ -3,7 +3,11 @@ #pragma once +#include +#include #include +#include +#include #include #include "gen.h" @@ -11,6 +15,20 @@ class disk_backend { +protected: +#if IS_POSIX + bool use_overlay { false }; + std::map > overlay; + + void store_object_in_overlay(const off_t id, const std::vector & data); + bool store_mem_range_in_overlay(const off_t offset, const size_t n, const uint8_t *const from, const size_t sector_size); + std::optional > get_object_from_overlay(const off_t id); + std::optional > get_from_overlay(const off_t offset, const size_t sector_size); + + json_t *serialize_overlay() const; + void deserialize_overlay(const json_t *const j); +#endif + public: disk_backend(); virtual ~disk_backend(); @@ -20,9 +38,11 @@ public: static disk_backend *deserialize(const json_t *const j); #endif - virtual bool begin() = 0; + virtual std::string get_identifier() const = 0; - virtual bool read(const off_t offset, const size_t n, uint8_t *const target) = 0; + virtual bool begin(const bool disk_snapshots) = 0; - virtual bool write(const off_t offset, const size_t n, const uint8_t *const from) = 0; + virtual bool read(const off_t offset, const size_t n, uint8_t *const target, const size_t sector_size) = 0; + + virtual bool write(const off_t offset, const size_t n, const uint8_t *const from, const size_t sector_size) = 0; }; diff --git a/disk_backend_file.cpp b/disk_backend_file.cpp index 127faa3..19ee4d2 100644 --- a/disk_backend_file.cpp +++ b/disk_backend_file.cpp @@ -1,11 +1,13 @@ // (C) 2018-2024 by Folkert van Heusden // Released under MIT license +#include #include #include #include #include "disk_backend_file.h" +#include "gen.h" #include "log.h" @@ -26,6 +28,8 @@ json_t *disk_backend_file::serialize() const json_object_set(j, "disk-backend-type", json_string("file")); + json_object_set(j, "overlay", serialize_overlay()); + // TODO store checksum of backend json_object_set(j, "filename", json_string(filename.c_str())); @@ -39,8 +43,10 @@ disk_backend_file *disk_backend_file::deserialize(const json_t *const j) } #endif -bool disk_backend_file::begin() +bool disk_backend_file::begin(const bool snapshots) { + use_overlay = snapshots; + fd = open(filename.c_str(), O_RDWR); if (fd == -1) { @@ -52,30 +58,48 @@ bool disk_backend_file::begin() return true; } -bool disk_backend_file::read(const off_t offset, const size_t n, uint8_t *const target) +bool disk_backend_file::read(const off_t offset_in, const size_t n, uint8_t *const target, const size_t sector_size) { - DOLOG(debug, false, "disk_backend_file::read: read %zu bytes from offset %zu", n, offset); + DOLOG(debug, false, "disk_backend_file::read: read %zu bytes from offset %zu", n, offset_in); + + assert((offset % sector_size) == 0); + assert((n % sector_size) == 0); + + for(off_t o=0; o #include #include #include @@ -54,6 +55,8 @@ json_t *disk_backend_nbd::serialize() const json_object_set(j, "disk-backend-type", json_string("nbd")); + json_object_set(j, "overlay", serialize_overlay()); + // TODO store checksum of backend json_object_set(j, "host", json_string(host.c_str())); json_object_set(j, "port", json_integer(port)); @@ -68,8 +71,12 @@ disk_backend_nbd *disk_backend_nbd::deserialize(const json_t *const j) } #endif -bool disk_backend_nbd::begin() +bool disk_backend_nbd::begin(const bool snapshots) { +#if IS_POSIX + use_overlay = snapshots; +#endif + if (!connect(false)) { DOLOG(ll_error, true, "disk_backend_nbd: cannot connect to NBD server"); return false; @@ -154,14 +161,27 @@ bool disk_backend_nbd::connect(const bool retry) return fd != -1; } -bool disk_backend_nbd::read(const off_t offset, const size_t n, uint8_t *const target) +bool disk_backend_nbd::read(const off_t offset_in, const size_t n, uint8_t *const target, const size_t sector_size) { - DOLOG(debug, false, "disk_backend_nbd::read: read %zu bytes from offset %zu", n, offset); + DOLOG(debug, false, "disk_backend_nbd::read: read %zu bytes from offset %zu", n, offset_in); if (n == 0) return true; - do { + size_t o = 0; + off_t offset = offset_in; + + while(offset < offset_in + off_t(n)) { +#if IS_POSIX + auto o_rc = get_from_overlay(offset, sector_size); + if (o_rc.has_value()) { + memcpy(&target[o], o_rc.value().data(), sector_size); + offset += sector_size; + o += sector_size; + continue; + } +#endif + if (fd == -1 && !connect(true)) { DOLOG(warning, true, "disk_backend_nbd::read: (re-)connect"); sleep(1); @@ -179,7 +199,7 @@ bool disk_backend_nbd::read(const off_t offset, const size_t n, uint8_t *const t nbd_request.magic = ntohl(0x25609513); nbd_request.type = 0; // READ nbd_request.offset = HTONLL(uint64_t(offset)); - nbd_request.length = htonl(n); + nbd_request.length = htonl(sector_size); if (WRITE(fd, reinterpret_cast(&nbd_request), sizeof nbd_request) != sizeof nbd_request) { DOLOG(warning, true, "disk_backend_nbd::read: problem sending request"); @@ -217,26 +237,33 @@ bool disk_backend_nbd::read(const off_t offset, const size_t n, uint8_t *const t return false; } - if (READ(fd, reinterpret_cast(target), n) != ssize_t(n)) { + if (READ(fd, reinterpret_cast(target), sector_size) != ssize_t(sector_size)) { DOLOG(warning, true, "disk_backend_nbd::read: problem receiving payload"); close(fd); fd = -1; sleep(1); continue; } + + offset += sector_size; + o += sector_size; } - while(fd == -1); return true; } -bool disk_backend_nbd::write(const off_t offset, const size_t n, const uint8_t *const from) +bool disk_backend_nbd::write(const off_t offset, const size_t n, const uint8_t *const from, const size_t sector_size) { DOLOG(debug, false, "disk_backend_nbd::write: write %zu bytes to offset %zu", n, offset); if (n == 0) return true; +#if IS_POSIX + if (store_mem_range_in_overlay(offset, n, from, sector_size)) + return true; +#endif + do { if (!connect(true)) { DOLOG(warning, true, "disk_backend_nbd::write: (re-)connect"); @@ -250,7 +277,7 @@ bool disk_backend_nbd::write(const off_t offset, const size_t n, const uint8_t * uint64_t handle; uint64_t offset; uint32_t length; - } nbd_request { 0 }; + } nbd_request { }; nbd_request.magic = ntohl(0x25609513); nbd_request.type = 1; // WRITE diff --git a/disk_backend_nbd.h b/disk_backend_nbd.h index b6679a8..fb369b9 100644 --- a/disk_backend_nbd.h +++ b/disk_backend_nbd.h @@ -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 "disk_backend.h" #include "gen.h" +#include "utils.h" class disk_backend_nbd : public disk_backend @@ -26,9 +27,11 @@ public: static disk_backend_nbd *deserialize(const json_t *const j); #endif - bool begin() override; + std::string get_identifier() const override { return format("%s:%d", host.c_str(), port); } - bool read(const off_t offset, const size_t n, uint8_t *const target) override; + bool begin(const bool snapshots) override; - bool write(const off_t offset, const size_t n, const uint8_t *const from) override; + bool read(const off_t offset, const size_t n, uint8_t *const target, const size_t sector_size) override; + + bool write(const off_t offset, const size_t n, const uint8_t *const from, const size_t sector_size) override; }; diff --git a/gen.h b/gen.h index 46c1f04..8629ac9 100644 --- a/gen.h +++ b/gen.h @@ -13,8 +13,11 @@ typedef enum { wm_word = 0, wm_byte = 1 } word_mode_t; typedef enum { rm_prev, rm_cur } rm_selection_t; -#define IS_POSIX (defined(linux) || defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))) -#define IS_UP (!(IS_POSIX)) /* is microprocessor */ +#if (defined(linux) || defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))) +#define IS_POSIX 1 +#else +#define IS_POSIX 0 +#endif #if IS_POSIX #include diff --git a/main.cpp b/main.cpp index d25804c..24de903 100644 --- a/main.cpp +++ b/main.cpp @@ -295,10 +295,19 @@ void get_metrics(cpu *const c) } } +void start_disk_devices(const std::vector & backends, const bool enable_snapshots) +{ + for(auto & backend: backends) { + if (backend->begin(enable_snapshots) == false) + error_exit(false, "Failed to initialize disk backend \"%s\"", backend->get_identifier().c_str()); + } +} + void help() { printf("-h this help\n"); printf("-D x deserialize state from file\n"); + printf("-P when serializing state to file (in the debugger), include an overlay: changes to disk-files are then non-persistent, they only exist in the state-dump\n"); printf("-T t.bin load file as a binary tape file (like simh \"load\" command), also for .BIC files\n"); printf("-B run tape file as a unit test (for .BIC files)\n"); printf("-R d.rk load file as a RK05 disk device\n"); @@ -318,27 +327,8 @@ void help() printf("-M log metrics\n"); } -#include "breakpoint_parser.h" int main(int argc, char *argv[]) { -#if 0 - { - bus *b = new bus(); - cpu *c = new cpu(b, &event); - b->add_cpu(c); - - std::pair > rc = parse_breakpoint(b, "(pc=0123 and (r0=01456 or r2=1) and memWV[0444]=0222)"); - printf("%p\n", rc.first); - - if (rc.second.has_value()) - printf("%s\n", rc.second.value().c_str()); - delete rc.first; - delete b; - } - - return 0; -#endif - //setlocale(LC_ALL, ""); std::vector rk05_files; @@ -365,7 +355,7 @@ int main(int argc, char *argv[]) std::string test; - disk_backend *temp_d = nullptr; + bool disk_snapshots = false; std::optional set_ram_size; @@ -376,7 +366,7 @@ int main(int argc, char *argv[]) std::string deserialize; int opt = -1; - while((opt = getopt(argc, argv, "hD:MT:Br:R:p:ndtL:bl:s:Q:N:J:XS:")) != -1) + while((opt = getopt(argc, argv, "hD:MT:Br:R:p:ndtL:bl:s:Q:N:J:XS:P")) != -1) { switch(opt) { case 'h': @@ -441,17 +431,11 @@ int main(int argc, char *argv[]) break; case 'R': - temp_d = new disk_backend_file(optarg); - if (!temp_d->begin()) - error_exit(false, "Cannot use file \"%s\" for RK05", optarg); - rk05_files.push_back(temp_d); + rk05_files.push_back(new disk_backend_file(optarg)); break; case 'r': - temp_d = new disk_backend_file(optarg); - if (!temp_d->begin()) - error_exit(false, "Cannot use file \"%s\" for RL02", optarg); - rl02_files.push_back(temp_d); + rl02_files.push_back(new disk_backend_file(optarg)); break; case 'N': { @@ -459,7 +443,7 @@ int main(int argc, char *argv[]) if (parts.size() != 3) error_exit(false, "-N: parameter missing"); - temp_d = new disk_backend_nbd(parts.at(0), atoi(parts.at(1).c_str())); + disk_backend *temp_d = new disk_backend_nbd(parts.at(0), atoi(parts.at(1).c_str())); if (parts.at(2) == "rk05") rk05_files.push_back(temp_d); @@ -494,6 +478,10 @@ int main(int argc, char *argv[]) set_ram_size = std::stoi(optarg); break; + case 'P': + disk_snapshots = true; + break; + default: fprintf(stderr, "-%c is not understood\n", opt); return 1; @@ -511,6 +499,10 @@ int main(int argc, char *argv[]) DOLOG(info, true, "Built on: " __DATE__ " " __TIME__); + start_disk_devices(rk05_files, disk_snapshots); + + start_disk_devices(rl02_files, disk_snapshots); + #if !defined(_WIN32) if (withUI) cnsl = new console_ncurses(&event); diff --git a/mmu.h b/mmu.h index e78a5da..4b2b4ad 100644 --- a/mmu.h +++ b/mmu.h @@ -41,8 +41,10 @@ private: uint16_t PIR { 0 }; uint16_t CSR { 0 }; +#if IS_POSIX void add_par_pdr(json_t *const target, const int run_mode, const bool is_d, const std::string & name) const; void set_par_pdr(const json_t *const j_in, const int run_mode, const bool is_d, const std::string & name); +#endif public: mmu(); diff --git a/rk05.cpp b/rk05.cpp index 8b1aaf8..34d0c37 100644 --- a/rk05.cpp +++ b/rk05.cpp @@ -156,7 +156,7 @@ void rk05::writeWord(const uint16_t addr, const uint16_t v) for(size_t i=0; ireadUnibusByte(work_memoff++); - if (!fhs.at(device)->write(work_diskoffb, cur, xfer_buffer)) + 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); work_diskoffb += cur; @@ -191,7 +191,7 @@ void rk05::writeWord(const uint16_t addr, const uint16_t v) while(temp > 0) { uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), temp); - if (!fhs.at(device)->read(temp_diskoffb, cur, xfer_buffer)) { + 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; } diff --git a/rl02.cpp b/rl02.cpp index 0256c86..339e93c 100644 --- a/rl02.cpp +++ b/rl02.cpp @@ -271,7 +271,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) mpr[0]++; } - if (!fhs.at(device)->write(temp_disk_offset, cur, xfer_buffer)) { + if (!fhs.at(device)->write(temp_disk_offset, cur, xfer_buffer, 256)) { 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; } @@ -325,7 +325,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) while(count > 0) { uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count); - if (!fhs.at(device)->read(temp_disk_offset, cur, xfer_buffer)) { + if (!fhs.at(device)->read(temp_disk_offset, cur, xfer_buffer, 256)) { 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; } From 8caad6ae37b853ef05b881cd2471b0ff886898a9 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Fri, 26 Apr 2024 15:01:27 +0200 Subject: [PATCH 18/19] disk configure menu --- ESP32/main.ino | 2 +- bus.h | 2 + debugger.cpp | 191 ++++++++++++++++++++++++------------------------- disk_device.h | 22 ++++++ loaders.cpp | 2 +- loaders.h | 2 +- main.cpp | 28 +++----- rk05.h | 5 +- rl02.cpp | 4 +- rl02.h | 9 ++- 10 files changed, 137 insertions(+), 130 deletions(-) create mode 100644 disk_device.h diff --git a/ESP32/main.ino b/ESP32/main.ino index c5fe75c..1609ba9 100644 --- a/ESP32/main.ino +++ b/ESP32/main.ino @@ -216,7 +216,7 @@ void setup() { while(!Serial) delay(100); - Serial.println(F("This PDP-11 emulator is called \"kek\" (reason for that is forgotten) and was written by Folkert van Heusden.")); + Serial.println(F("PDP11 emulator, by Folkert van Heusden")); Serial.print(F("GIT hash: ")); Serial.println(version_str); Serial.println(F("Build on: " __DATE__ " " __TIME__)); diff --git a/bus.h b/bus.h index b0ae4c8..1e8db64 100644 --- a/bus.h +++ b/bus.h @@ -123,6 +123,8 @@ public: kw11_l *getKW11_L() { return kw11_l_; } tty *getTty() { return tty_; } mmu *getMMU() { return mmu_; } + rk05 *getRK05() { return rk05_; } + rl02 *getRL02() { return rl02_; } 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 readByte(const uint16_t a) { return read(a, wm_byte, rm_cur); } diff --git a/debugger.cpp b/debugger.cpp index 29de1b7..c8fb8fd 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -38,7 +38,7 @@ #include "rp2040.h" #endif -void setBootLoader(bus *const b); +void set_boot_loader(bus *const b); void configure_disk(console *const c); @@ -196,61 +196,7 @@ bool save_disk_configuration(const std::string & nbd_host, const int nbd_port, c } #endif -std::optional select_disk_backend(console *const c) -{ -#if defined(BUILD_FOR_RP2040) - return BE_SD; -#elif linux - c->put_string("1. network (NBD), 2. local filesystem, 9. abort"); -#else - c->put_string("1. network (NBD), 2. local SD card, 9. abort"); -#endif - - int ch = -1; - while(ch == -1 && ch != '1' && ch != '2' && ch != '9') { - auto temp = c->wait_char(500); - - if (temp.has_value()) - ch = temp.value(); - } - - c->put_string_lf(format("%c", ch)); - - if (ch == '1') - return BE_NETWORK; - - if (ch == '2') - return BE_SD; - - return { }; -} - -std::optional select_disk_type(console *const c) -{ - c->put_string("1. RK05, 2. RL02, 3. tape/BIC, 9. abort"); - - int ch = -1; - while(ch == -1 && ch != '1' && ch != '2' && ch != '3' && ch != '9') { - auto temp = c->wait_char(500); - - if (temp.has_value()) - ch = temp.value(); - } - - c->put_string_lf(format("%c", ch)); - - if (ch == '1') - return DT_RK05; - - if (ch == '2') - return DT_RL02; - - if (ch == '3') - return DT_TAPE; - - return { }; -} - +#if 0 #if !defined(BUILD_FOR_RP2040) std::optional, std::vector, std::string> > select_nbd_server(console *const c) { @@ -293,9 +239,10 @@ std::optional, std::vector, std::vector, std::string> > select_disk_files(console *const c) +// disk image files +std::optional select_disk_file(console *const c) { #if IS_POSIX c->put_string_lf("Files in current directory: "); @@ -367,11 +314,6 @@ std::optional, std::vectorput_string("Opening file: "); c->put_string_lf(selected_file.c_str()); @@ -388,9 +330,6 @@ std::optional, std::vector, std::vectorput_string_lf("open failed"); } + + return { }; } -void set_disk_configuration(bus *const b, console *const cnsl, std::tuple, std::vector, std::string> & disk_files) +int wait_for_key(const std::string & title, console *const cnsl, const std::vector & allowed) { - if (std::get<0>(disk_files).empty() == false) - b->add_rk05(new rk05(std::get<0>(disk_files), b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); + cnsl->put_string_lf(title); - if (std::get<1>(disk_files).empty() == false) - b->add_rl02(new rl02(std::get<1>(disk_files), b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); + cnsl->put_string("> "); - if (std::get<2>(disk_files).empty() == false) { - auto addr = loadTape(b, std::get<2>(disk_files)); + int ch = -1; + while(ch == -1) { + auto temp = cnsl->wait_char(500); - if (addr.has_value()) - b->getCpu()->setPC(addr.value()); + if (temp.has_value()) { + for(auto & a: allowed) { + if (a == temp.value()) { + ch = temp.value(); + break; + } + } + } } - if (std::get<0>(disk_files).empty() == false) - setBootLoader(b, BL_RK05); - else if (std::get<1>(disk_files).empty() == false) - setBootLoader(b, BL_RL02); + cnsl->put_string_lf(format("%c", ch)); + + return ch; } void configure_disk(bus *const b, console *const cnsl) { + // TODO tape + int ch = wait_for_key("1. RK05, 2. RL02, 9. abort", cnsl, { '1', '2', '3', '9' }); + + bootloader_t bl = BL_NONE; + disk_device *dd = nullptr; + + if (ch == '1') { + dd = b->getRK05(); + bl = BL_RK05; + } + else if (ch == '2') { + dd = b->getRL02(); + bl = BL_RL02; + } + else if (ch == '9') { + return; + } + for(;;) { - cnsl->put_string_lf("Load disk"); + std::vector keys_allowed { '1', '2', '9' }; - auto backend = select_disk_backend(cnsl); + auto cartridge_slots = dd->access_disk_backends(); + int slot_key = 'A'; + for(auto & slot: *cartridge_slots) { + cnsl->put_string_lf(format(" %c. %s", slot_key, slot ? slot->get_identifier().c_str() : "-")); + keys_allowed.push_back(slot_key); + slot_key++; + } - if (backend.has_value() == false) + int ch = wait_for_key("Select cartridge to setup, 1. to add a cartridge, 2. to load a bootloader or 9. to exit", cnsl, keys_allowed); + if (ch == '9') break; - std::optional, std::vector, std::string> > files; + if (ch == '1') { + auto image_file = select_disk_file(cnsl); -#if !defined(BUILD_FOR_RP2040) - if (backend == BE_NETWORK) - files = select_nbd_server(cnsl); - else // if (backend == BE_SD) -#endif - files = select_disk_files(cnsl); + if (image_file.has_value()) { + cartridge_slots->push_back(image_file.value()); - if (files.has_value() == false) - break; + cnsl->put_string_lf("Cartridge loaded"); + } + } + else if (ch == '2') { + set_boot_loader(b, bl); - set_disk_configuration(b, cnsl, files.value()); + cnsl->put_string_lf("Bootloader loaded"); + } + else { + int slot = ch - 'A'; - break; + for(;;) { + int ch = wait_for_key("Select cartridge action: 1. load, 2. unload, 9. exit", cnsl, { '1', '2', '9' }); + if (ch == '9') + break; + + if (ch == '1') { + auto image_file = select_disk_file(cnsl); + + if (image_file.has_value()) { + delete cartridge_slots->at(slot); + cartridge_slots->at(slot) = image_file.value(); + + cnsl->put_string_lf("Cartridge loaded"); + } + } + else if (ch == '2') { + if (cartridge_slots->at(slot)) { + delete cartridge_slots->at(slot); + cartridge_slots->at(slot) = nullptr; + + cnsl->put_string_lf("Cartridge unloaded"); + } + } + } + } } } @@ -1026,7 +1019,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto continue; } else if (parts[0] == "bl" && parts.size() == 2) { - setBootLoader(b, parts.at(1) == "rk05" ? BL_RK05 : BL_RL02); + set_boot_loader(b, parts.at(1) == "rk05" ? BL_RK05 : BL_RL02); cnsl->put_string_lf("Bootloader set"); continue; diff --git a/disk_device.h b/disk_device.h new file mode 100644 index 0000000..266fe84 --- /dev/null +++ b/disk_device.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "device.h" +#include "disk_backend.h" + + +class disk_device: public device +{ +protected: + std::vector fhs; + +public: + disk_device() { + } + + virtual ~disk_device() { + } + + std::vector * access_disk_backends() { return &fhs; } +}; diff --git a/loaders.cpp b/loaders.cpp index a28ac4c..8f71e3d 100644 --- a/loaders.cpp +++ b/loaders.cpp @@ -28,7 +28,7 @@ void loadbin(bus *const b, uint16_t base, const char *const file) fclose(fh); } -void setBootLoader(bus *const b, const bootloader_t which) +void set_boot_loader(bus *const b, const bootloader_t which) { cpu *const c = b -> getCpu(); diff --git a/loaders.h b/loaders.h index 35235df..704535a 100644 --- a/loaders.h +++ b/loaders.h @@ -11,6 +11,6 @@ typedef enum { BL_NONE, BL_RK05, BL_RL02 } bootloader_t; void loadbin(bus *const b, uint16_t base, const char *const file); -void setBootLoader(bus *const b, const bootloader_t which); +void set_boot_loader(bus *const b, const bootloader_t which); std::optional loadTape(bus *const b, const std::string & file); void load_p11_x11(bus *const b, const std::string & file); diff --git a/main.cpp b/main.cpp index 24de903..56f7c72 100644 --- a/main.cpp +++ b/main.cpp @@ -495,7 +495,7 @@ int main(int argc, char *argv[]) if (validate_json.empty() == false) return run_cpu_validation(validate_json); - DOLOG(info, true, "This PDP-11 emulator is called \"kek\" (reason for that is forgotten) and was written by Folkert van Heusden."); + DOLOG(info, true, "PDP11 emulator, by Folkert van Heusden"); DOLOG(info, true, "Built on: " __DATE__ " " __TIME__); @@ -525,26 +525,18 @@ int main(int argc, char *argv[]) cpu *c = new cpu(b, &event); b->add_cpu(c); - if (rk05_files.empty() == false) { - if (enable_bootloader == false) - DOLOG(warning, true, "Note: loading RK05 with no (RK05-) bootloader selected"); - else - bootloader = BL_RK05; + if (rk05_files.empty() == false) + bootloader = BL_RK05; - b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); - } - - if (rl02_files.empty() == false) { - if (enable_bootloader == false) - DOLOG(warning, true, "Note: loading RL02 with no (RL02-) bootloader selected"); - else - bootloader = BL_RL02; - - b->add_rl02(new rl02(rl02_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); - } + if (rl02_files.empty() == false) + bootloader = BL_RL02; if (enable_bootloader) - setBootLoader(b, bootloader); + set_boot_loader(b, bootloader); + + b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); + + b->add_rl02(new rl02(rl02_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); } else { FILE *fh = fopen(deserialize.c_str(), "r"); diff --git a/rk05.h b/rk05.h index 7ba4682..5189011 100644 --- a/rk05.h +++ b/rk05.h @@ -9,7 +9,7 @@ #include #include -#include "device.h" +#include "disk_device.h" #include "disk_backend.h" @@ -25,12 +25,11 @@ class bus; -class rk05 : public device +class rk05: public disk_device { private: bus *const b { nullptr }; uint16_t registers [7] { 0 }; - std::vector fhs; uint8_t xfer_buffer[512] { 0 }; std::atomic_bool *const disk_read_acitivity { nullptr }; diff --git a/rl02.cpp b/rl02.cpp index 339e93c..a62067f 100644 --- a/rl02.cpp +++ b/rl02.cpp @@ -271,7 +271,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) mpr[0]++; } - if (!fhs.at(device)->write(temp_disk_offset, cur, xfer_buffer, 256)) { + if (fhs.at(device) == nullptr || fhs.at(device)->write(temp_disk_offset, cur, xfer_buffer, 256) == false) { 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; } @@ -325,7 +325,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v) while(count > 0) { uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count); - if (!fhs.at(device)->read(temp_disk_offset, cur, xfer_buffer, 256)) { + if (fhs.at(device) == nullptr || fhs.at(device)->read(temp_disk_offset, cur, xfer_buffer, 256) == false) { 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; } diff --git a/rl02.h b/rl02.h index 4a9858e..be8a96d 100644 --- a/rl02.h +++ b/rl02.h @@ -9,7 +9,7 @@ #include #include -#include "device.h" +#include "disk_device.h" #include "disk_backend.h" #include "gen.h" @@ -27,7 +27,7 @@ constexpr const int rl02_bytes_per_sector = 256; class bus; -class rl02 : public device +class rl02: public disk_device { private: bus *const b; @@ -37,10 +37,9 @@ private: uint8_t head { 0 }; uint8_t sector { 0 }; uint16_t mpr[3]; - std::vector fhs; - std::atomic_bool *const disk_read_activity { nullptr }; - std::atomic_bool *const disk_write_activity { nullptr }; + std::atomic_bool *const disk_read_activity { nullptr }; + std::atomic_bool *const disk_write_activity { nullptr }; uint32_t get_bus_address() const; void update_bus_address(const uint32_t a); From d86fd2690e9b31bd98cce54bd103ef79193a28a5 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Fri, 26 Apr 2024 15:08:39 +0200 Subject: [PATCH 19/19] select file or nbd --- debugger.cpp | 55 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/debugger.cpp b/debugger.cpp index c8fb8fd..4d696ec 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -196,50 +196,32 @@ bool save_disk_configuration(const std::string & nbd_host, const int nbd_port, c } #endif -#if 0 #if !defined(BUILD_FOR_RP2040) -std::optional, std::vector, std::string> > select_nbd_server(console *const c) +std::optional select_nbd_server(console *const cnsl) { - c->flush_input(); + cnsl->flush_input(); - std::string hostname = c->read_line("Enter hostname (or empty to abort): "); + std::string hostname = cnsl->read_line("Enter hostname (or empty to abort): "); if (hostname.empty()) return { }; - std::string port_str = c->read_line("Enter port number (or empty to abort): "); + std::string port_str = cnsl->read_line("Enter port number (or empty to abort): "); if (port_str.empty()) return { }; - auto disk_type = select_disk_type(c); - - if (disk_type.has_value() == false) - return { }; - disk_backend *d = new disk_backend_nbd(hostname, atoi(port_str.c_str())); if (d->begin(false) == false) { - c->put_string_lf("Cannot initialize NBD client"); + cnsl->put_string_lf("Cannot initialize NBD client"); delete d; return { }; } - if (save_disk_configuration(hostname, atoi(port_str.c_str()), { }, disk_type.value(), c)) - c->put_string_lf("NBD disk configuration saved"); - else - c->put_string_lf("NBD disk configuration NOT saved"); - - if (disk_type.value() == DT_RK05) - return { { { d }, { }, "" } }; - - if (disk_type.value() == DT_RL02) - return { { { }, { d }, "" } }; - - return { }; + return d; } #endif -#endif // disk image files std::optional select_disk_file(console *const c) @@ -379,6 +361,25 @@ int wait_for_key(const std::string & title, console *const cnsl, const std::vect return ch; } +std::optional select_disk_backend(console *const cnsl) +{ +#if defined(BUILD_FOR_RP2040) + return select_disk_file(cnsl); +#else + int ch = wait_for_key("1. local disk, 2. network disk (NBD), 9. abort", cnsl, { '1', '2', '9' }); + if (ch == '9') + return { }; + + if (ch == '1') + return select_disk_file(cnsl); + + if (ch == '2') + return select_nbd_server(cnsl); + + return { }; +#endif +} + void configure_disk(bus *const b, console *const cnsl) { // TODO tape @@ -415,7 +416,7 @@ void configure_disk(bus *const b, console *const cnsl) break; if (ch == '1') { - auto image_file = select_disk_file(cnsl); + auto image_file = select_disk_backend(cnsl); if (image_file.has_value()) { cartridge_slots->push_back(image_file.value()); @@ -437,7 +438,7 @@ void configure_disk(bus *const b, console *const cnsl) break; if (ch == '1') { - auto image_file = select_disk_file(cnsl); + auto image_file = select_disk_backend(cnsl); if (image_file.has_value()) { delete cartridge_slots->at(slot); @@ -1152,7 +1153,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto "bl - set bootload (rl02 or rk05)", #if IS_POSIX "ser - serialize state to a file", - "dser - deserialize state from a file", +// "dser - deserialize state from a file", #endif #if defined(ESP32) "cfgnet - configure network (e.g. WiFi)",