diff --git a/ESP32/data/.place_holder b/ESP32/data/.place_holder new file mode 100644 index 0000000..e69de29 diff --git a/ESP32/main.ino b/ESP32/main.ino index 908f680..ded87a3 100644 --- a/ESP32/main.ino +++ b/ESP32/main.ino @@ -1,8 +1,10 @@ // (C) 2018-2023 by Folkert van Heusden // Released under Apache License v2.0 #include +#include #include #include +#include #include #include #include @@ -27,6 +29,12 @@ #include "utils.h" +constexpr const char CFG_FILE[] = "/net-disk.json"; + +#define MAX_CFG_SIZE 1024 +StaticJsonDocument json_doc; + + bus *b = nullptr; cpu *c = nullptr; tty *tty_ = nullptr; @@ -60,6 +68,83 @@ void console_thread_wrapper_io(void *const c) cnsl->operator()(); } +typedef enum { DT_RK05, DT_RL02 } disk_type_t; + +std::optional, std::vector > > load_disk_configuration(console *const c) +{ + File dataFile = LittleFS.open(CFG_FILE, "r"); + + if (!dataFile) + return { }; + + size_t size = dataFile.size(); + + char buffer[MAX_CFG_SIZE]; + + if (size > sizeof buffer) { // this should not happen + dataFile.close(); + + return { }; + } + + dataFile.read(reinterpret_cast(buffer), size); + buffer[(sizeof buffer) - 1] = 0x00; + + dataFile.close(); + + auto error = deserializeJson(json_doc, buffer); + + if (error) // this should not happen + return { }; + + String nbd_host = json_doc["NBD-host"]; + int nbd_port = json_doc["NBD-port"]; + + String disk_type_temp = json_doc["disk-type"]; + + disk_type_t disk_type = DT_RK05; + + if (disk_type_temp == "rl02") + disk_type = DT_RL02; + + disk_backend *d = new disk_backend_nbd(nbd_host.c_str(), nbd_port); + + if (d->begin() == false) { + c->put_string_lf("Cannot initialize NBD client from configuration file"); + delete d; + return { }; + } + + c->put_string_lf(format("Connection to NBD server at %s:%d success", nbd_host.c_str(), nbd_port)); + + if (disk_type == DT_RK05) + return { { { d }, { } } }; + + if (disk_type == DT_RL02) + return { { { }, { d } } }; + + return { }; +} + +bool save_disk_configuration(const std::string & nbd_host, const int nbd_port, const disk_type_t dt) +{ + json_doc["NBD-host"] = nbd_host; + json_doc["NBD-port"] = nbd_port; + + json_doc["disk-type"] = dt == DT_RK05 ? "rk05" : "rl02"; + + File dataFile = LittleFS.open(CFG_FILE, "w"); + + if (!dataFile) + return false; + + serializeJson(json_doc, dataFile); + + dataFile.close(); + + return true; +} + typedef enum { BE_NETWORK, BE_SD } disk_backend_t; std::optional select_disk_backend(console *const c) { @@ -81,8 +166,6 @@ std::optional select_disk_backend(console *const c) return BE_SD; } -typedef enum { DT_RK05, DT_RL02 } disk_type_t; - std::optional select_disk_type(console *const c) { c->put_string("1. RK05, 2. RL02, 9. abort"); @@ -130,6 +213,11 @@ std::optional, std::vector return { }; } + if (save_disk_configuration(hostname, atoi(port_str.c_str()), disk_type.value())) + 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 }, { } } }; @@ -197,6 +285,21 @@ std::optional, std::vector } } +void set_disk_configuration(std::pair, std::vector > & disk_files) +{ + if (disk_files.first.empty() == false) + b->add_rk05(new rk05(disk_files.first, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); + + if (disk_files.second.empty() == false) + b->add_rl02(new rl02(disk_files.second, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); + + // TODO: allow bootloader to be selected + if (disk_files.first.empty() == false) + setBootLoader(b, BL_RK05); + else + setBootLoader(b, BL_RL02); +} + void configure_disk(console *const c) { for(;;) { @@ -217,17 +320,7 @@ void configure_disk(console *const c) if (files.has_value() == false) break; - if (files.value().first.empty() == false) - b->add_rk05(new rk05(files.value().first, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); - - if (files.value().second.empty() == false) - b->add_rl02(new rl02(files.value().second, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); - - // TODO: allow bootloader to be selected - if (files.value().first.empty() == false) - setBootLoader(b, BL_RK05); - else - setBootLoader(b, BL_RL02); + set_disk_configuration(files.value()); break; } @@ -266,15 +359,14 @@ void configure_network(console *const c) return; } - set_hostname(); - if (parts.size() == 1) WiFi.begin(parts.at(0).c_str()); else WiFi.begin(parts.at(0).c_str(), parts.at(1).c_str()); } -void wait_network(console *const c) { +void wait_network(console *const c) +{ constexpr const int timeout = 10 * 3; int i = 0; @@ -291,18 +383,20 @@ void wait_network(console *const c) { c->put_string_lf("Time out connecting"); } -void check_network(console *const c) { +void check_network(console *const c) +{ wait_network(c); c->put_string_lf(""); c->put_string_lf(format("Local IP address: %s", WiFi.localIP().toString().c_str())); } -void start_network(console *const c) { - WiFi.mode(WIFI_STA); - +void start_network(console *const c) +{ set_hostname(); + WiFi.mode(WIFI_STA); + WiFi.begin(); wait_network(c); @@ -311,11 +405,26 @@ void start_network(console *const c) { c->put_string_lf(format("Local IP address: %s", WiFi.localIP().toString().c_str())); } -void set_tty_serial_speed(const int bps) { +void set_tty_serial_speed(const int bps) +{ Serial_RS232.begin(bps); } -void setup() { +void recall_configuration(console *const c) +{ + c->put_string_lf("Starting network..."); + start_network(cnsl); + + auto disk_configuration = load_disk_configuration(c); + + if (disk_configuration.has_value()) { + c->put_string_lf("Starting disk..."); + set_disk_configuration(disk_configuration.value()); + } +} + +void setup() +{ Serial.begin(115200); Serial.println(F("This PDP-11 emulator is called \"kek\" (reason for that is forgotten) and was written by Folkert van Heusden.")); @@ -328,6 +437,9 @@ void setup() { Serial.print(F("CPU clock frequency (MHz): ")); Serial.println(getCpuFrequencyMhz()); + if (!LittleFS.begin(true)) + Serial.println(F("LittleFS.begin() failed")); + Serial.print(F("Free RAM before init (decimal bytes): ")); Serial.println(ESP.getFreeHeap()); @@ -380,7 +492,8 @@ void setup() { cnsl->start_thread(); } -void loop() { +void loop() +{ debugger(cnsl, b, &stop_event, false); c->reset(); diff --git a/ESP32/platformio.ini b/ESP32/platformio.ini index e7d8b97..e880d9f 100644 --- a/ESP32/platformio.ini +++ b/ESP32/platformio.ini @@ -10,8 +10,10 @@ board = wemos_d1_mini32 framework = arduino monitor_speed = 115200 upload_speed = 1000000 +board_build.filesystem = littlefs lib_deps = greiman/SdFat@^2.1.2 adafruit/Adafruit NeoPixel + bblanchon/ArduinoJson@^6.19.4 build_flags = -std=gnu++17 -Ofast -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99 build_unflags = -std=gnu++11 -Os diff --git a/debugger.cpp b/debugger.cpp index c439a58..daffa85 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -19,6 +19,8 @@ void check_network(console *const c); void start_network(console *const c); void set_tty_serial_speed(const int bps); + +void recall_configuration(console *const c); #endif // returns size of instruction (in bytes) @@ -162,339 +164,353 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto bool single_step = false; while(*stop_event != EVENT_TERMINATE) { - std::string cmd = cnsl->read_line(format("%d", stop_event->load())); - auto parts = split(cmd, " "); - auto kv = split(parts, "="); + try { + std::string cmd = cnsl->read_line(format("%d", stop_event->load())); + auto parts = split(cmd, " "); + auto kv = split(parts, "="); - if (parts.empty()) - continue; + if (parts.empty()) + continue; - if (cmd == "go") { - single_step = false; + if (cmd == "go") { + single_step = false; - *stop_event = EVENT_NONE; - } - else if (parts[0] == "single" || parts[0] == "s") { - single_step = true; - - if (parts.size() == 2) - n_single_step = atoi(parts[1].c_str()); - else - n_single_step = 1; - - *stop_event = EVENT_NONE; - } - else if ((parts[0] == "sbp" || parts[0] == "cbp") && parts.size() == 2){ - uint16_t pc = std::stoi(parts[1].c_str(), nullptr, 8); - - if (parts[0] == "sbp") { - c->set_breakpoint(pc); - - cnsl->put_string_lf(format("Set breakpoint at %06o", pc)); + *stop_event = EVENT_NONE; } - else { - c->remove_breakpoint(pc); + else if (parts[0] == "single" || parts[0] == "s") { + single_step = true; - cnsl->put_string_lf(format("Clear breakpoint at %06o", pc)); + if (parts.size() == 2) + n_single_step = atoi(parts[1].c_str()); + else + n_single_step = 1; + + *stop_event = EVENT_NONE; } + else if ((parts[0] == "sbp" || parts[0] == "cbp") && parts.size() == 2){ + uint16_t pc = std::stoi(parts[1].c_str(), nullptr, 8); - continue; - } - else if (cmd == "lbp") { - auto bps = c->list_breakpoints(); + if (parts[0] == "sbp") { + c->set_breakpoint(pc); - cnsl->put_string_lf("Breakpoints:"); + cnsl->put_string_lf(format("Set breakpoint at %06o", pc)); + } + else { + c->remove_breakpoint(pc); - for(auto a : bps) { - cnsl->put_string(format(" %06o> ", a)); - - disassemble(c, cnsl, a, true); - } - - continue; - } - else if (parts[0] == "disassemble" || parts[0] == "d") { - int pc = kv.find("pc") != kv.end() ? std::stoi(kv.find("pc")->second, nullptr, 8) : c->getPC(); - int n = kv.find("n") != kv.end() ? std::stoi(kv.find("n") ->second, nullptr, 10) : 1; - - cnsl->put_string_lf(format("Disassemble %d instructions starting at %o", n, pc)); - - bool show_registers = kv.find("pc") == kv.end(); - - for(int i=0; isetPC(new_pc); - - cnsl->put_string_lf(format("Set PC to %06o", new_pc)); - } - else { - cnsl->put_string_lf("setpc requires an (octal address as) parameter"); - } - - continue; - } - else if (parts[0] == "toggle") { - auto s_it = kv.find("s"); - auto t_it = kv.find("t"); - - if (s_it == kv.end() || t_it == kv.end()) - cnsl->put_string_lf(format("toggle: parameter missing? current switches states: 0o%06o", c->getBus()->get_console_switches())); - else { - int s = std::stoi(s_it->second, nullptr, 8); - int t = std::stoi(t_it->second, nullptr, 8); - - c->getBus()->set_console_switch(s, t); - - cnsl->put_string_lf(format("Set switch %d to %d", s, t)); - } - - continue; - } - else if (parts[0] == "setmem") { - auto a_it = kv.find("a"); - auto v_it = kv.find("v"); - - if (a_it == kv.end() || v_it == kv.end()) - cnsl->put_string_lf("setmem: parameter missing?"); - else { - uint16_t a = std::stoi(a_it->second, nullptr, 8); - uint8_t v = std::stoi(v_it->second, nullptr, 8); - - c->getBus()->writeByte(a, v); - - cnsl->put_string_lf(format("Set %06o to %03o", a, v)); - } - - continue; - } - else if (parts[0] == "trace" || parts[0] == "t") { - tracing = !tracing; - - cnsl->put_string_lf(format("Tracing set to %s", tracing ? "ON" : "OFF")); - - continue; - } - else if (parts[0] == "mmudump") { - mmu_dump(cnsl, b); - - continue; - } - else if (parts[0] == "strace") { - if (parts.size() != 2) { - trace_start_addr = -1; - - cnsl->put_string_lf("Tracing start address reset"); - } - else { - trace_start_addr = std::stoi(parts[1], nullptr, 8); - - cnsl->put_string_lf(format("Tracing start address set to %06o", trace_start_addr)); - } - - continue; - } - else if (parts[0] == "examine" || parts[0] == "e") { - if (parts.size() < 3) - cnsl->put_string_lf("parameter missing"); - else { - int addr = std::stoi(parts[2], nullptr, 8); - int val = -1; - - int n = parts.size() == 4 ? atoi(parts[3].c_str()) : 1; - bool word = parts[1] == "w"; - - if (parts[1] != "w" && parts[1] != "b") { - cnsl->put_string_lf("expected b or w"); - - continue; + cnsl->put_string_lf(format("Clear breakpoint at %06o", pc)); } - std::string out; + continue; + } + else if (cmd == "lbp") { + auto bps = c->list_breakpoints(); + + cnsl->put_string_lf("Breakpoints:"); + + for(auto a : bps) { + cnsl->put_string(format(" %06o> ", a)); + + disassemble(c, cnsl, a, true); + } + + continue; + } + else if (parts[0] == "disassemble" || parts[0] == "d") { + int pc = kv.find("pc") != kv.end() ? std::stoi(kv.find("pc")->second, nullptr, 8) : c->getPC(); + int n = kv.find("n") != kv.end() ? std::stoi(kv.find("n") ->second, nullptr, 10) : 1; + + cnsl->put_string_lf(format("Disassemble %d instructions starting at %o", n, pc)); + + bool show_registers = kv.find("pc") == kv.end(); for(int i=0; iread(addr + i, wm_byte, rm_cur, true); - else if (word) - val = b->read(addr + i, wm_word, rm_cur, true); + pc += disassemble(c, cnsl, pc, !show_registers); - if (val == -1) { - cnsl->put_string_lf(format("Can't read from %06o\n", addr + i)); + show_registers = false; + } + + continue; + } + else if (parts[0] == "setpc") { + if (parts.size() == 2) { + uint16_t new_pc = std::stoi(parts.at(1), nullptr, 8); + c->setPC(new_pc); + + cnsl->put_string_lf(format("Set PC to %06o", new_pc)); + } + else { + cnsl->put_string_lf("setpc requires an (octal address as) parameter"); + } + + continue; + } + else if (parts[0] == "toggle") { + auto s_it = kv.find("s"); + auto t_it = kv.find("t"); + + if (s_it == kv.end() || t_it == kv.end()) + cnsl->put_string_lf(format("toggle: parameter missing? current switches states: 0o%06o", c->getBus()->get_console_switches())); + else { + int s = std::stoi(s_it->second, nullptr, 8); + int t = std::stoi(t_it->second, nullptr, 8); + + c->getBus()->set_console_switch(s, t); + + cnsl->put_string_lf(format("Set switch %d to %d", s, t)); + } + + continue; + } + else if (parts[0] == "setmem") { + auto a_it = kv.find("a"); + auto v_it = kv.find("v"); + + if (a_it == kv.end() || v_it == kv.end()) + cnsl->put_string_lf("setmem: parameter missing?"); + else { + uint16_t a = std::stoi(a_it->second, nullptr, 8); + uint8_t v = std::stoi(v_it->second, nullptr, 8); + + c->getBus()->writeByte(a, v); + + cnsl->put_string_lf(format("Set %06o to %03o", a, v)); + } + + continue; + } + else if (parts[0] == "trace" || parts[0] == "t") { + tracing = !tracing; + + cnsl->put_string_lf(format("Tracing set to %s", tracing ? "ON" : "OFF")); + + continue; + } + else if (parts[0] == "mmudump") { + mmu_dump(cnsl, b); + + continue; + } + else if (parts[0] == "strace") { + if (parts.size() != 2) { + trace_start_addr = -1; + + cnsl->put_string_lf("Tracing start address reset"); + } + else { + trace_start_addr = std::stoi(parts[1], nullptr, 8); + + cnsl->put_string_lf(format("Tracing start address set to %06o", trace_start_addr)); + } + + continue; + } + else if (parts[0] == "examine" || parts[0] == "e") { + if (parts.size() < 3) + cnsl->put_string_lf("parameter missing"); + else { + int addr = std::stoi(parts[2], nullptr, 8); + int val = -1; + + int n = parts.size() == 4 ? atoi(parts[3].c_str()) : 1; + bool word = parts[1] == "w"; + + if (parts[1] != "w" && parts[1] != "b") { + cnsl->put_string_lf("expected b or w"); + + continue; + } + + std::string out; + + for(int i=0; iread(addr + i, wm_byte, rm_cur, true); + else if (word) + val = b->read(addr + i, wm_word, rm_cur, true); + + if (val == -1) { + cnsl->put_string_lf(format("Can't read from %06o\n", addr + i)); + break; + } + + if (n == 1) + cnsl->put_string_lf(format("value at %06o, octal: %o, hex: %x, dec: %d\n", addr + i, val, val, val)); + + if (n > 1) { + if (i > 0) + out += " "; + + if (word) + out += format("%06o", val); + else + out += format("%03o", val); + } + } + + if (n > 1) + cnsl->put_string_lf(out); + } + + continue; + } + else if (cmd == "reset" || cmd == "r") { +#if defined(ESP32) + ESP.restart(); +#else + *stop_event = EVENT_NONE; + + c->reset(); +#endif + continue; + } +#if defined(ESP32) + else if (cmd == "cfgdisk") { + configure_disk(cnsl); + + continue; + } + else if (cmd == "cfgnet") { + configure_network(cnsl); + + continue; + } + else if (cmd == "chknet") { + check_network(cnsl); + + continue; + } + else if (cmd == "startnet") { + start_network(cnsl); + + continue; + } + else if (parts.at(0) == "serspd") { + if (parts.size() == 2) { + int speed = std::stoi(parts.at(1), nullptr, 10); + set_tty_serial_speed(speed); + + cnsl->put_string_lf(format("Set baudrate to %d", speed)); + } + else { + cnsl->put_string_lf("serspd requires an (decimal) parameter"); + } + + continue; + } +#endif + else if (cmd == "cls") { + const char cls[] = { 27, '[', '2', 'J', 12, 0 }; + + cnsl->put_string_lf(cls); + + continue; + } + else if (cmd == "turbo") { + turbo = !turbo; + + cnsl->put_string_lf(format("Turbo set to %s", turbo ? "ON" : "OFF")); + + continue; + } + else if (cmd == "init") { + recall_configuration(cnsl); + + continue; + } + else if (cmd == "quit" || cmd == "q") { +#if defined(ESP32) + ESP.restart(); +#endif + break; + } + else if (cmd == "help" || cmd == "h" || cmd == "?") { + cnsl->put_string_lf("disassemble/d - show current instruction (pc=/n=)"); + cnsl->put_string_lf("go - run until trap or ^e"); +#if !defined(ESP32) + cnsl->put_string_lf("quit/q - stop emulator"); +#endif + cnsl->put_string_lf("examine/e - show memory address ( [])"); + cnsl->put_string_lf("reset/r - reset cpu/bus/etc"); + cnsl->put_string_lf("single/s - run 1 instruction (implicit 'disassemble' command)"); + cnsl->put_string_lf("sbp/cbp/lbp - set/clear/list breakpoint(s)"); + cnsl->put_string_lf("trace/t - toggle tracing"); + cnsl->put_string_lf("turbo - toggle turbo mode (cannot be interrupted)"); + cnsl->put_string_lf("strace - start tracing from address - invoke without address to disable"); + cnsl->put_string_lf("mmudump - dump MMU settings (PARs/PDRs)"); + cnsl->put_string_lf("setpc - set PC to value"); + cnsl->put_string_lf("setmem - set memory (a=) to value (v=), both in octal, one byte"); + cnsl->put_string_lf("toggle - set switch (s=, 0...15 (decimal)) of the front panel to state (t=, 0 or 1)"); + cnsl->put_string_lf("cls - clear screen"); +#if defined(ESP32) + cnsl->put_string_lf("cfgnet - configure network (e.g. WiFi)"); + cnsl->put_string_lf("startnet - start network"); + cnsl->put_string_lf("chknet - check network status"); + cnsl->put_string_lf("cfgdisk - configure disk"); + cnsl->put_string_lf("serspd - set serial speed in bps (8N1 are default)"); + cnsl->put_string_lf("init - reload (disk-)configuration from flash"); +#endif + + continue; + } + else { + cnsl->put_string_lf("?"); + continue; + } + + c->emulation_start(); + + *cnsl->get_running_flag() = true; + + if (turbo) { + while(*stop_event == EVENT_NONE) { + c->step_a(); + c->step_b(); + } + } + else { + while(*stop_event == EVENT_NONE) { + if (!single_step) + DOLOG(debug, false, "---"); + + c->step_a(); + + if (trace_start_addr != -1 && c->getPC() == trace_start_addr) + tracing = true; + + if (tracing || single_step) + disassemble(c, single_step ? cnsl : nullptr, c->getPC(), false); + + if (c->check_breakpoint() && !single_step) { + cnsl->put_string_lf("Breakpoint"); break; } - if (n == 1) - cnsl->put_string_lf(format("value at %06o, octal: %o, hex: %x, dec: %d\n", addr + i, val, val, val)); + c->step_b(); - if (n > 1) { - if (i > 0) - out += " "; - - if (word) - out += format("%06o", val); - else - out += format("%03o", val); - } + if (single_step && --n_single_step == 0) + break; } - - if (n > 1) - cnsl->put_string_lf(out); } - continue; - } - else if (cmd == "reset" || cmd == "r") { -#if defined(ESP32) - ESP.restart(); -#else - *stop_event = EVENT_NONE; + *cnsl->get_running_flag() = false; - c->reset(); -#endif - continue; - } -#if defined(ESP32) - else if (cmd == "cfgdisk") { - configure_disk(cnsl); - - continue; - } - else if (cmd == "cfgnet") { - configure_network(cnsl); - - continue; - } - else if (cmd == "chknet") { - check_network(cnsl); - - continue; - } - else if (cmd == "startnet") { - start_network(cnsl); - - continue; - } - else if (parts.at(0) == "serspd") { - if (parts.size() == 2) { - int speed = std::stoi(parts.at(1), nullptr, 10); - set_tty_serial_speed(speed); - - cnsl->put_string_lf(format("Set baudrate to %d", speed)); - } - else { - cnsl->put_string_lf("serspd requires an (decimal) parameter"); + if (!single_step) { + auto speed = c->get_mips_rel_speed(); + cnsl->debug("MIPS: %.2f, relative speed: %.2f%%, instructions executed: %lu", std::get<0>(speed), std::get<1>(speed), std::get<2>(speed)); } - continue; - } -#endif - else if (cmd == "cls") { - const char cls[] = { 12, 0 }; + if (*stop_event == EVENT_INTERRUPT) { + single_step = true; - cnsl->put_string_lf(cls); - - continue; - } - else if (cmd == "turbo") { - turbo = !turbo; - - cnsl->put_string_lf(format("Turbo set to %s", turbo ? "ON" : "OFF")); - - continue; - } - else if (cmd == "quit" || cmd == "q") { -#if defined(ESP32) - ESP.restart(); -#endif - break; - } - else if (cmd == "help" || cmd == "h" || cmd == "?") { - cnsl->put_string_lf("disassemble/d - show current instruction (pc=/n=)"); - cnsl->put_string_lf("go - run until trap or ^e"); -#if !defined(ESP32) - cnsl->put_string_lf("quit/q - stop emulator"); -#endif - cnsl->put_string_lf("examine/e - show memory address ( [])"); - cnsl->put_string_lf("reset/r - reset cpu/bus/etc"); - cnsl->put_string_lf("single/s - run 1 instruction (implicit 'disassemble' command)"); - cnsl->put_string_lf("sbp/cbp/lbp - set/clear/list breakpoint(s)"); - cnsl->put_string_lf("trace/t - toggle tracing"); - cnsl->put_string_lf("turbo - toggle turbo mode (cannot be interrupted)"); - cnsl->put_string_lf("strace - start tracing from address - invoke without address to disable"); - cnsl->put_string_lf("mmudump - dump MMU settings (PARs/PDRs)"); - cnsl->put_string_lf("setpc - set PC to value"); - cnsl->put_string_lf("setmem - set memory (a=) to value (v=), both in octal, one byte"); - cnsl->put_string_lf("toggle - set switch (s=, 0...15 (decimal)) of the front panel to state (t=, 0 or 1)"); - cnsl->put_string_lf("cls - clear screen"); -#if defined(ESP32) - cnsl->put_string_lf("cfgnet - configure network (e.g. WiFi)"); - cnsl->put_string_lf("startnet - start network"); - cnsl->put_string_lf("chknet - check network status"); - cnsl->put_string_lf("cfgdisk - configure disk"); - cnsl->put_string_lf("serspd - set serial speed in bps (8N1 are default)"); -#endif - - continue; - } - else { - cnsl->put_string_lf("?"); - continue; - } - - c->emulation_start(); - - *cnsl->get_running_flag() = true; - - if (turbo) { - while(*stop_event == EVENT_NONE) { - c->step_a(); - c->step_b(); + *stop_event = EVENT_NONE; } } - else { - while(*stop_event == EVENT_NONE) { - if (!single_step) - DOLOG(debug, false, "---"); - - c->step_a(); - - if (trace_start_addr != -1 && c->getPC() == trace_start_addr) - tracing = true; - - if (tracing || single_step) - disassemble(c, single_step ? cnsl : nullptr, c->getPC(), false); - - if (c->check_breakpoint() && !single_step) { - cnsl->put_string_lf("Breakpoint"); - break; - } - - c->step_b(); - - if (single_step && --n_single_step == 0) - break; - } + catch(const std::exception & e) { + cnsl->put_string_lf(format("Exception caught: %s", e.what())); } - - *cnsl->get_running_flag() = false; - - if (!single_step) { - auto speed = c->get_mips_rel_speed(); - cnsl->debug("MIPS: %.2f, relative speed: %.2f%%, instructions executed: %lu", std::get<0>(speed), std::get<1>(speed), std::get<2>(speed)); - } - - if (*stop_event == EVENT_INTERRUPT) { - single_step = true; - - *stop_event = EVENT_NONE; + catch(...) { + cnsl->put_string_lf("Unspecified exception caught"); } } }