This commit is contained in:
parent
7e976f0a78
commit
517db4657a
3 changed files with 711 additions and 674 deletions
223
debugger.cpp
223
debugger.cpp
|
@ -1,6 +1,7 @@
|
||||||
// (C) 2018-2024 by Folkert van Heusden
|
// (C) 2018-2025 by Folkert van Heusden
|
||||||
// Released under MIT license
|
// Released under MIT license
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include "gen.h"
|
#include "gen.h"
|
||||||
#if IS_POSIX || defined(_WIN32)
|
#if IS_POSIX || defined(_WIN32)
|
||||||
|
@ -726,46 +727,38 @@ void set_kw11_l_interrupt_freq(console *const cnsl, bus *const b, const int freq
|
||||||
cnsl->put_string_lf("Frequency out of range");
|
cnsl->put_string_lf("Frequency out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event)
|
struct debugger_state {
|
||||||
{
|
int32_t trace_start_addr { -1 };
|
||||||
int32_t trace_start_addr = -1;
|
int n_single_step { 1 };
|
||||||
int n_single_step = 1;
|
bool turbo { false };
|
||||||
bool turbo = false;
|
bool marker { false };
|
||||||
bool marker = false;
|
|
||||||
std::optional<int> t_rl; // trace runlevel
|
std::optional<int> t_rl; // trace runlevel
|
||||||
|
bool single_step { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
bool debugger_do(debugger_state *const state, console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const std::string & cmd)
|
||||||
|
{
|
||||||
cpu *const c = b->getCpu();
|
cpu *const c = b->getCpu();
|
||||||
|
|
||||||
b->set_debug_mode();
|
|
||||||
|
|
||||||
bool single_step = false;
|
|
||||||
|
|
||||||
while(*stop_event != EVENT_TERMINATE) {
|
|
||||||
try {
|
|
||||||
if (marker)
|
|
||||||
cnsl->put_string_lf("---");
|
|
||||||
|
|
||||||
std::string cmd = cnsl->read_line(format("%d", stop_event->load()));
|
|
||||||
auto parts = split(cmd, " ");
|
auto parts = split(cmd, " ");
|
||||||
auto kv = split(parts, "=");
|
auto kv = split(parts, "=");
|
||||||
|
|
||||||
if (parts.empty())
|
if (parts.empty())
|
||||||
continue;
|
return true;
|
||||||
|
|
||||||
if (cmd == "go") {
|
if (cmd == "go") {
|
||||||
single_step = false;
|
state->single_step = false;
|
||||||
|
|
||||||
*stop_event = EVENT_NONE;
|
*stop_event = EVENT_NONE;
|
||||||
}
|
}
|
||||||
else if (cmd == "marker")
|
else if (cmd == "marker")
|
||||||
marker = !marker;
|
state->marker = !state->marker;
|
||||||
else if (parts[0] == "single" || parts[0] == "s" || parts[0] == "step") {
|
else if (parts[0] == "single" || parts[0] == "s" || parts[0] == "step") {
|
||||||
single_step = true;
|
state->single_step = true;
|
||||||
|
|
||||||
if (parts.size() == 2)
|
if (parts.size() == 2)
|
||||||
n_single_step = std::stoi(parts[1]);
|
state->n_single_step = std::stoi(parts[1]);
|
||||||
else
|
else
|
||||||
n_single_step = 1;
|
state->n_single_step = 1;
|
||||||
|
|
||||||
*stop_event = EVENT_NONE;
|
*stop_event = EVENT_NONE;
|
||||||
}
|
}
|
||||||
|
@ -794,7 +787,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf("Breakpoint not found");
|
cnsl->put_string_lf("Breakpoint not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "lbp") {
|
else if (cmd == "lbp") {
|
||||||
auto bps = c->list_breakpoints();
|
auto bps = c->list_breakpoints();
|
||||||
|
@ -807,9 +800,9 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
if (bps.empty())
|
if (bps.empty())
|
||||||
cnsl->put_string_lf("(none)");
|
cnsl->put_string_lf("(none)");
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "disassemble" || parts[0] == "d") {
|
else if (parts[0] == "disassemble" || parts[0] == "dis") {
|
||||||
uint16_t pc = kv.find("pc") != kv.end() ? std::stoi(kv.find("pc")->second, nullptr, 8) : c->getPC();
|
uint16_t 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;
|
int n = kv.find("n") != kv.end() ? std::stoi(kv.find("n") ->second, nullptr, 10) : 1;
|
||||||
|
|
||||||
|
@ -823,7 +816,16 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
show_registers = false;
|
show_registers = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
|
}
|
||||||
|
else if (parts[0] == "D" && parts.size() == 3) { // SIMH compatibility
|
||||||
|
uint16_t v = std::stoi(parts.at(2), nullptr, 8);
|
||||||
|
if (parts[1] == "PC")
|
||||||
|
c->setPC(v);
|
||||||
|
else {
|
||||||
|
uint16_t a = std::stoi(parts.at(1), nullptr, 8);
|
||||||
|
c->getBus()->write_word(a, v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (parts[0] == "setpc") {
|
else if (parts[0] == "setpc") {
|
||||||
if (parts.size() == 2) {
|
if (parts.size() == 2) {
|
||||||
|
@ -836,12 +838,12 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf("setpc requires an (octal address as) parameter");
|
cnsl->put_string_lf("setpc requires an (octal address as) parameter");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "getpc") {
|
else if (parts[0] == "getpc") {
|
||||||
cnsl->put_string_lf(format("PC = %06o", c->getPC()));
|
cnsl->put_string_lf(format("PC = %06o", c->getPC()));
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "setreg") {
|
else if (parts[0] == "setreg") {
|
||||||
if (parts.size() == 3) {
|
if (parts.size() == 3) {
|
||||||
|
@ -855,7 +857,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf("setreg requires a register and an octal value");
|
cnsl->put_string_lf("setreg requires a register and an octal value");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "getreg") {
|
else if (parts[0] == "getreg") {
|
||||||
if (parts.size() == 2) {
|
if (parts.size() == 2) {
|
||||||
|
@ -866,7 +868,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf("getreg requires a register");
|
cnsl->put_string_lf("getreg requires a register");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "setstack") {
|
else if (parts[0] == "setstack") {
|
||||||
if (parts.size() == 3) {
|
if (parts.size() == 3) {
|
||||||
|
@ -881,7 +883,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf("setstack requires a register and an octal value");
|
cnsl->put_string_lf("setstack requires a register and an octal value");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "getstack") {
|
else if (parts[0] == "getstack") {
|
||||||
if (parts.size() == 2) {
|
if (parts.size() == 2) {
|
||||||
|
@ -892,7 +894,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf("getreg requires a stack register");
|
cnsl->put_string_lf("getreg requires a stack register");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "setpsw") {
|
else if (parts[0] == "setpsw") {
|
||||||
if (parts.size() == 2) {
|
if (parts.size() == 2) {
|
||||||
|
@ -905,12 +907,12 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf("setpsw requires an octal value");
|
cnsl->put_string_lf("setpsw requires an octal value");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "getpsw") {
|
else if (parts[0] == "getpsw") {
|
||||||
cnsl->put_string_lf(format("PSW = %06o", c->getPSW()));
|
cnsl->put_string_lf(format("PSW = %06o", c->getPSW()));
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "getmem") {
|
else if (parts[0] == "getmem") {
|
||||||
auto a_it = kv.find("a");
|
auto a_it = kv.find("a");
|
||||||
|
@ -922,7 +924,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf(format("MEM %06o = %03o", a, c->getBus()->read_byte(a)));
|
cnsl->put_string_lf(format("MEM %06o = %03o", a, c->getBus()->read_byte(a)));
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "setmem") {
|
else if (parts[0] == "setmem") {
|
||||||
auto a_it = kv.find("a");
|
auto a_it = kv.find("a");
|
||||||
|
@ -939,7 +941,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf(format("Set %06o to %03o", a, v));
|
cnsl->put_string_lf(format("Set %06o to %03o", a, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "toggle") {
|
else if (parts[0] == "toggle") {
|
||||||
auto s_it = kv.find("s");
|
auto s_it = kv.find("s");
|
||||||
|
@ -956,14 +958,14 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf(format("Set switch %d to %d", s, t));
|
cnsl->put_string_lf(format("Set switch %d to %d", s, t));
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "trace" || parts[0] == "t") {
|
else if (parts[0] == "trace" || parts[0] == "t") {
|
||||||
settrace(!gettrace());
|
settrace(!gettrace());
|
||||||
|
|
||||||
cnsl->put_string_lf(format("Tracing set to %s", gettrace() ? "ON" : "OFF"));
|
cnsl->put_string_lf(format("Tracing set to %s", gettrace() ? "ON" : "OFF"));
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "state") {
|
else if (parts[0] == "state") {
|
||||||
if (parts[1] == "rl02")
|
if (parts[1] == "rl02")
|
||||||
|
@ -983,7 +985,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
else
|
else
|
||||||
cnsl->put_string_lf(format("Device \"%s\" is not known", parts[1].c_str()));
|
cnsl->put_string_lf(format("Device \"%s\" is not known", parts[1].c_str()));
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "mmures") {
|
else if (parts[0] == "mmures") {
|
||||||
if (parts.size() == 2)
|
if (parts.size() == 2)
|
||||||
|
@ -991,26 +993,26 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
else
|
else
|
||||||
cnsl->put_string_lf("Parameter missing");
|
cnsl->put_string_lf("Parameter missing");
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "regdump") {
|
else if (parts[0] == "regdump") {
|
||||||
reg_dump(cnsl, c);
|
reg_dump(cnsl, c);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "strace") {
|
else if (parts[0] == "strace") {
|
||||||
if (parts.size() != 2) {
|
if (parts.size() != 2) {
|
||||||
trace_start_addr = -1;
|
state->trace_start_addr = -1;
|
||||||
|
|
||||||
cnsl->put_string_lf("Tracing start address reset");
|
cnsl->put_string_lf("Tracing start address reset");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
trace_start_addr = std::stoi(parts[1], nullptr, 8);
|
state->trace_start_addr = std::stoi(parts[1], nullptr, 8);
|
||||||
|
|
||||||
cnsl->put_string_lf(format("Tracing start address set to %06o", trace_start_addr));
|
cnsl->put_string_lf(format("Tracing start address set to %06o", state->trace_start_addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "examine" || parts[0] == "e") {
|
else if (parts[0] == "examine" || parts[0] == "e") {
|
||||||
if (parts.size() < 3)
|
if (parts.size() < 3)
|
||||||
|
@ -1022,7 +1024,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
if (parts[2] != "p" && parts[2] != "v") {
|
if (parts[2] != "p" && parts[2] != "v") {
|
||||||
cnsl->put_string_lf("expected p (physical address) or v (virtual address)");
|
cnsl->put_string_lf("expected p (physical address) or v (virtual address)");
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string out;
|
std::string out;
|
||||||
|
@ -1060,45 +1062,45 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf(out);
|
cnsl->put_string_lf(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "reset" || cmd == "r") {
|
else if (cmd == "reset" || cmd == "r") {
|
||||||
*stop_event = EVENT_NONE;
|
*stop_event = EVENT_NONE;
|
||||||
b->reset();
|
b->reset();
|
||||||
cnsl->put_string_lf("resetted");
|
cnsl->put_string_lf("resetted");
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "cfgdisk") {
|
else if (cmd == "cfgdisk") {
|
||||||
configure_disk(b, cnsl);
|
configure_disk(b, cnsl);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
else if (cmd == "cfgnet") {
|
else if (cmd == "cfgnet") {
|
||||||
configure_network(cnsl);
|
configure_network(cnsl);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "chknet") {
|
else if (cmd == "chknet") {
|
||||||
check_network(cnsl);
|
check_network(cnsl);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "startnet") {
|
else if (cmd == "startnet") {
|
||||||
start_network(cnsl);
|
start_network(cnsl);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "pm" && parts.size() == 2) {
|
else if (parts[0] == "pm" && parts.size() == 2) {
|
||||||
reinterpret_cast<console_esp32 *>(cnsl)->set_panel_mode(parts[1] == "bits" ? console_esp32::PM_BITS : console_esp32::PM_POINTER);
|
reinterpret_cast<console_esp32 *>(cnsl)->set_panel_mode(parts[1] == "bits" ? console_esp32::PM_BITS : console_esp32::PM_POINTER);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (cmd == "stats") {
|
else if (cmd == "stats") {
|
||||||
show_run_statistics(cnsl, c);
|
show_run_statistics(cnsl, c);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "ramsize") {
|
else if (parts[0] == "ramsize") {
|
||||||
if (parts.size() == 2)
|
if (parts.size() == 2)
|
||||||
|
@ -1109,7 +1111,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf(format("Memory size: %u pages or %u kB (decimal)", n_pages, n_pages * 8192 / 1024));
|
cnsl->put_string_lf(format("Memory size: %u pages or %u kB (decimal)", n_pages, n_pages * 8192 / 1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "bl" && parts.size() == 2) {
|
else if (parts[0] == "bl" && parts.size() == 2) {
|
||||||
if (parts.at(1) == "rk05")
|
if (parts.at(1) == "rk05")
|
||||||
|
@ -1121,32 +1123,32 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
else
|
else
|
||||||
cnsl->put_string_lf("???");
|
cnsl->put_string_lf("???");
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "trl") {
|
else if (parts[0] == "trl") {
|
||||||
if (parts.size() == 1)
|
if (parts.size() == 1)
|
||||||
t_rl.reset();
|
state->t_rl.reset();
|
||||||
else
|
else
|
||||||
t_rl = std::stoi(parts.at(1));
|
state->t_rl = std::stoi(parts.at(1));
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "cls") {
|
else if (cmd == "cls") {
|
||||||
const char cls[] = { 27, '[', '2', 'J', 12, 0 };
|
const char cls[] = { 27, '[', '2', 'J', 27, '[', 'H', 12, 0 };
|
||||||
|
|
||||||
cnsl->put_string_lf(cls);
|
cnsl->put_string_lf(cls);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "turbo") {
|
else if (cmd == "turbo") {
|
||||||
turbo = !turbo;
|
state->turbo = !state->turbo;
|
||||||
|
|
||||||
if (turbo)
|
if (state->turbo)
|
||||||
c->set_debug(false);
|
c->set_debug(false);
|
||||||
|
|
||||||
cnsl->put_string_lf(format("Turbo set to %s", turbo ? "ON" : "OFF"));
|
cnsl->put_string_lf(format("Turbo set to %s", state->turbo ? "ON" : "OFF"));
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "debug") {
|
else if (cmd == "debug") {
|
||||||
bool new_mode = !c->get_debug();
|
bool new_mode = !c->get_debug();
|
||||||
|
@ -1154,7 +1156,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
|
|
||||||
cnsl->put_string_lf(format("Debug mode set to %s", new_mode ? "ON" : "OFF"));
|
cnsl->put_string_lf(format("Debug mode set to %s", new_mode ? "ON" : "OFF"));
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "setll" && parts.size() == 2) {
|
else if (parts[0] == "setll" && parts.size() == 2) {
|
||||||
auto ll_parts = split(parts[1], ",");
|
auto ll_parts = split(parts[1], ",");
|
||||||
|
@ -1180,17 +1182,17 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
setll(ll_screen, ll_file);
|
setll(ll_screen, ll_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
#if IS_POSIX
|
#if IS_POSIX
|
||||||
else if (parts[0] == "ser" && parts.size() == 2) {
|
else if (parts[0] == "ser" && parts.size() == 2) {
|
||||||
serialize_state(cnsl, b, parts.at(1));
|
serialize_state(cnsl, b, parts.at(1));
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (parts[0] == "setinthz" && parts.size() == 2) {
|
else if (parts[0] == "setinthz" && parts.size() == 2) {
|
||||||
set_kw11_l_interrupt_freq(cnsl, b, std::stoi(parts.at(1)));
|
set_kw11_l_interrupt_freq(cnsl, b, std::stoi(parts.at(1)));
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "setsl" && parts.size() == 3) {
|
else if (parts[0] == "setsl" && parts.size() == 3) {
|
||||||
if (setloghost(parts.at(1).c_str(), parse_ll(parts[2])) == false)
|
if (setloghost(parts.at(1).c_str(), parse_ll(parts[2])) == false)
|
||||||
|
@ -1198,22 +1200,22 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
else
|
else
|
||||||
send_syslog(info, "Hello, world!");
|
send_syslog(info, "Hello, world!");
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "pts" && parts.size() == 2) {
|
else if (parts[0] == "pts" && parts.size() == 2) {
|
||||||
cnsl->enable_timestamp(std::stoi(parts[1]));
|
cnsl->enable_timestamp(std::stoi(parts[1]));
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "qi") {
|
else if (cmd == "qi") {
|
||||||
show_queued_interrupts(cnsl, c);
|
show_queued_interrupts(cnsl, c);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "log") {
|
else if (parts[0] == "log") {
|
||||||
DOLOG(info, true, cmd.c_str());
|
DOLOG(info, true, cmd.c_str());
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "bic" && parts.size() == 2) {
|
else if (parts[0] == "bic" && parts.size() == 2) {
|
||||||
auto rc = load_tape(b, parts[1].c_str());
|
auto rc = load_tape(b, parts[1].c_str());
|
||||||
|
@ -1226,7 +1228,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
cnsl->put_string_lf("BIC/LDA failed to load");
|
cnsl->put_string_lf("BIC/LDA failed to load");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "lt") {
|
else if (parts[0] == "lt") {
|
||||||
if (parts.size() == 2)
|
if (parts.size() == 2)
|
||||||
|
@ -1234,42 +1236,42 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
else
|
else
|
||||||
tm11_load_tape(cnsl, b, { });
|
tm11_load_tape(cnsl, b, { });
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "dir" || cmd == "ls") {
|
else if (cmd == "dir" || cmd == "ls") {
|
||||||
ls_l(cnsl);
|
ls_l(cnsl);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "ult") {
|
else if (cmd == "ult") {
|
||||||
tm11_unload_tape(b);
|
tm11_unload_tape(b);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (parts[0] == "testdc11") {
|
else if (parts[0] == "testdc11") {
|
||||||
b->getDC11()->test_ports(cmd);
|
b->getDC11()->test_ports(cmd);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "dp") {
|
else if (cmd == "dp") {
|
||||||
cnsl->stop_panel_thread();
|
cnsl->stop_panel_thread();
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "cdc11") {
|
else if (cmd == "cdc11") {
|
||||||
configure_comm(cnsl, *b->getDC11()->get_comm_interfaces());
|
configure_comm(cnsl, *b->getDC11()->get_comm_interfaces());
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "serdc11") {
|
else if (cmd == "serdc11") {
|
||||||
serdc11(cnsl, b);
|
serdc11(cnsl, b);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "dserdc11") {
|
else if (cmd == "dserdc11") {
|
||||||
deserdc11(cnsl, b);
|
deserdc11(cnsl, b);
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "bt") {
|
else if (cmd == "bt") {
|
||||||
if (c->get_debug() == false)
|
if (c->get_debug() == false)
|
||||||
|
@ -1280,17 +1282,17 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
for(auto & element: backtrace)
|
for(auto & element: backtrace)
|
||||||
cnsl->put_string_lf(format("%06o %s", element.first, element.second.c_str()));
|
cnsl->put_string_lf(format("%06o %s", element.first, element.second.c_str()));
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == "quit" || cmd == "q") {
|
else if (cmd == "quit" || cmd == "q") {
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
#endif
|
#endif
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
else if (cmd == "help" || cmd == "h" || cmd == "?") {
|
else if (cmd == "help" || cmd == "h" || cmd == "?") {
|
||||||
constexpr const char *const help[] = {
|
constexpr const char *const help[] = {
|
||||||
"disassemble/d - show current instruction (pc=/n=)",
|
"dis[assemble] - show current instruction (pc=/n=)",
|
||||||
"go - run until trap or ^e",
|
"go - run until trap or ^e",
|
||||||
#if !defined(ESP32)
|
#if !defined(ESP32)
|
||||||
"quit/q - stop emulator",
|
"quit/q - stop emulator",
|
||||||
|
@ -1359,11 +1361,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
size_t i=0;
|
size_t i=0;
|
||||||
while(help[i])
|
while(help[i])
|
||||||
cnsl->put_string_lf(help[i++]);
|
cnsl->put_string_lf(help[i++]);
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cnsl->put_string_lf("?");
|
cnsl->put_string_lf("?");
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->emulation_start();
|
c->emulation_start();
|
||||||
|
@ -1372,7 +1374,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
|
|
||||||
bool reset_cpu = true;
|
bool reset_cpu = true;
|
||||||
|
|
||||||
if (turbo) {
|
if (state->turbo) {
|
||||||
while(*stop_event == EVENT_NONE)
|
while(*stop_event == EVENT_NONE)
|
||||||
c->step();
|
c->step();
|
||||||
}
|
}
|
||||||
|
@ -1380,25 +1382,25 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
reset_cpu = false;
|
reset_cpu = false;
|
||||||
|
|
||||||
while(*stop_event == EVENT_NONE) {
|
while(*stop_event == EVENT_NONE) {
|
||||||
if (trace_start_addr != -1 && c->getPC() == trace_start_addr)
|
if (state->trace_start_addr != -1 && c->getPC() == state->trace_start_addr)
|
||||||
settrace(true);
|
settrace(true);
|
||||||
|
|
||||||
if ((gettrace() || single_step) && (t_rl.has_value() == false || t_rl.value() == c->getPSW_runmode())) {
|
if ((gettrace() || state->single_step) && (state->t_rl.has_value() == false || state->t_rl.value() == c->getPSW_runmode())) {
|
||||||
if (!single_step)
|
if (!state->single_step)
|
||||||
TRACE("---");
|
TRACE("---");
|
||||||
|
|
||||||
disassemble(c, single_step ? cnsl : nullptr, c->getPC(), false);
|
disassemble(c, state->single_step ? cnsl : nullptr, c->getPC(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bp_result = c->check_breakpoint();
|
auto bp_result = c->check_breakpoint();
|
||||||
if (bp_result.has_value() && !single_step) {
|
if (bp_result.has_value() && !state->single_step) {
|
||||||
cnsl->put_string_lf("Breakpoint: " + bp_result.value());
|
cnsl->put_string_lf("Breakpoint: " + bp_result.value());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->step();
|
c->step();
|
||||||
|
|
||||||
if (single_step && --n_single_step == 0)
|
if (state->single_step && --state->n_single_step == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1407,6 +1409,35 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
|
|
||||||
if (reset_cpu)
|
if (reset_cpu)
|
||||||
c->reset();
|
c->reset();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const std::optional<std::string> & init)
|
||||||
|
{
|
||||||
|
debugger_state state;
|
||||||
|
|
||||||
|
b->set_debug_mode();
|
||||||
|
|
||||||
|
if (init.has_value()) {
|
||||||
|
std::string line;
|
||||||
|
std::ifstream fh;
|
||||||
|
fh.open(init.value());
|
||||||
|
while(std::getline(fh, line)) {
|
||||||
|
if (debugger_do(&state, cnsl, b, stop_event, line) == false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(*stop_event != EVENT_TERMINATE) {
|
||||||
|
try {
|
||||||
|
if (state.marker)
|
||||||
|
cnsl->put_string_lf("---");
|
||||||
|
|
||||||
|
std::string cmd = cnsl->read_line(format("%d", stop_event->load()));
|
||||||
|
|
||||||
|
if (debugger_do(&state, cnsl, b, stop_event, cmd) == false)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
catch(const std::exception & e) {
|
catch(const std::exception & e) {
|
||||||
cnsl->put_string_lf(format("Exception caught: %s", e.what()));
|
cnsl->put_string_lf(format("Exception caught: %s", e.what()));
|
||||||
|
|
|
@ -7,6 +7,6 @@
|
||||||
|
|
||||||
|
|
||||||
int disassemble(cpu *const c, console *const cnsl, const uint16_t pc, const bool instruction_only);
|
int disassemble(cpu *const c, console *const cnsl, const uint16_t pc, const bool instruction_only);
|
||||||
void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event);
|
void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const std::optional<std::string> & init);
|
||||||
|
|
||||||
void run_bic(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const uint16_t bic_start);
|
void run_bic(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const uint16_t bic_start);
|
||||||
|
|
10
main.cpp
10
main.cpp
|
@ -258,6 +258,7 @@ void help()
|
||||||
printf("-b enable bootloader (builtin)\n");
|
printf("-b enable bootloader (builtin)\n");
|
||||||
printf("-n ncurses UI\n");
|
printf("-n ncurses UI\n");
|
||||||
printf("-d enable debugger\n");
|
printf("-d enable debugger\n");
|
||||||
|
printf("-f x first process the commands from file x before entering the debugger\n");
|
||||||
printf("-S x set ram size (in number of 8 kB pages)\n");
|
printf("-S x set ram size (in number of 8 kB pages)\n");
|
||||||
printf("-s x,y set console switche state: set bit x (0...15) to y (0/1)\n");
|
printf("-s x,y set console switche state: set bit x (0...15) to y (0/1)\n");
|
||||||
printf("-t enable tracing (disassemble to stderr, requires -d as well)\n");
|
printf("-t enable tracing (disassemble to stderr, requires -d as well)\n");
|
||||||
|
@ -277,6 +278,7 @@ int main(int argc, char *argv[])
|
||||||
std::string disk_type = "rk05";
|
std::string disk_type = "rk05";
|
||||||
|
|
||||||
bool run_debugger = false;
|
bool run_debugger = false;
|
||||||
|
std::optional<std::string> debugger_init;
|
||||||
|
|
||||||
bool enable_bootloader = false;
|
bool enable_bootloader = false;
|
||||||
bootloader_t bootloader = BL_NONE;
|
bootloader_t bootloader = BL_NONE;
|
||||||
|
@ -311,13 +313,17 @@ int main(int argc, char *argv[])
|
||||||
std::optional<std::string> dc11_device;
|
std::optional<std::string> dc11_device;
|
||||||
|
|
||||||
int opt = -1;
|
int opt = -1;
|
||||||
while((opt = getopt(argc, argv, "hqD:MT:Br:R:p:ndtL:bl:s:Q:N:J:XS:P1:")) != -1)
|
while((opt = getopt(argc, argv, "hqD:MT:Br:R:p:ndf:tL:bl:s:Q:N:J:XS:P1:")) != -1)
|
||||||
{
|
{
|
||||||
switch(opt) {
|
switch(opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
help();
|
help();
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
debugger_init = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case '1':
|
case '1':
|
||||||
dc11_device = optarg;
|
dc11_device = optarg;
|
||||||
break;
|
break;
|
||||||
|
@ -612,7 +618,7 @@ int main(int argc, char *argv[])
|
||||||
if (is_bic)
|
if (is_bic)
|
||||||
run_bic(cnsl, b, &event, bic_start.value());
|
run_bic(cnsl, b, &event, bic_start.value());
|
||||||
else if (run_debugger || (bootloader == BL_NONE && test.empty() && tape.empty()))
|
else if (run_debugger || (bootloader == BL_NONE && test.empty() && tape.empty()))
|
||||||
debugger(cnsl, b, &event);
|
debugger(cnsl, b, &event, debugger_init);
|
||||||
else if (benchmark) {
|
else if (benchmark) {
|
||||||
// FILL MEMORY
|
// FILL MEMORY
|
||||||
memory *m = b->getRAM();
|
memory *m = b->getRAM();
|
||||||
|
|
Loading…
Add table
Reference in a new issue