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; }