load init file
Some checks are pending
CodeQL / Analyze (push) Waiting to run

This commit is contained in:
Folkert van Heusden 2025-04-15 19:31:36 +02:00
parent 7e976f0a78
commit 517db4657a
Signed by untrusted user who does not match committer: folkert
GPG key ID: 6B6455EDFEED3BD1
3 changed files with 711 additions and 674 deletions

View file

@ -1,6 +1,7 @@
// (C) 2018-2024 by Folkert van Heusden
// (C) 2018-2025 by Folkert van Heusden
// Released under MIT license
#include <fstream>
#include <optional>
#include "gen.h"
#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");
}
void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event)
{
int32_t trace_start_addr = -1;
int n_single_step = 1;
bool turbo = false;
bool marker = false;
struct debugger_state {
int32_t trace_start_addr { -1 };
int n_single_step { 1 };
bool turbo { false };
bool marker { false };
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();
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 kv = split(parts, "=");
if (parts.empty())
continue;
return true;
if (cmd == "go") {
single_step = false;
state->single_step = false;
*stop_event = EVENT_NONE;
}
else if (cmd == "marker")
marker = !marker;
state->marker = !state->marker;
else if (parts[0] == "single" || parts[0] == "s" || parts[0] == "step") {
single_step = true;
state->single_step = true;
if (parts.size() == 2)
n_single_step = std::stoi(parts[1]);
state->n_single_step = std::stoi(parts[1]);
else
n_single_step = 1;
state->n_single_step = 1;
*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");
}
continue;
return true;
}
else if (cmd == "lbp") {
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())
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();
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;
}
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") {
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");
}
continue;
return true;
}
else if (parts[0] == "getpc") {
cnsl->put_string_lf(format("PC = %06o", c->getPC()));
continue;
return true;
}
else if (parts[0] == "setreg") {
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");
}
continue;
return true;
}
else if (parts[0] == "getreg") {
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");
}
continue;
return true;
}
else if (parts[0] == "setstack") {
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");
}
continue;
return true;
}
else if (parts[0] == "getstack") {
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");
}
continue;
return true;
}
else if (parts[0] == "setpsw") {
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");
}
continue;
return true;
}
else if (parts[0] == "getpsw") {
cnsl->put_string_lf(format("PSW = %06o", c->getPSW()));
continue;
return true;
}
else if (parts[0] == "getmem") {
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)));
}
continue;
return true;
}
else if (parts[0] == "setmem") {
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));
}
continue;
return true;
}
else if (parts[0] == "toggle") {
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));
}
continue;
return true;
}
else if (parts[0] == "trace" || parts[0] == "t") {
settrace(!gettrace());
cnsl->put_string_lf(format("Tracing set to %s", gettrace() ? "ON" : "OFF"));
continue;
return true;
}
else if (parts[0] == "state") {
if (parts[1] == "rl02")
@ -983,7 +985,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
else
cnsl->put_string_lf(format("Device \"%s\" is not known", parts[1].c_str()));
continue;
return true;
}
else if (parts[0] == "mmures") {
if (parts.size() == 2)
@ -991,26 +993,26 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
else
cnsl->put_string_lf("Parameter missing");
continue;
return true;
}
else if (parts[0] == "regdump") {
reg_dump(cnsl, c);
continue;
return true;
}
else if (parts[0] == "strace") {
if (parts.size() != 2) {
trace_start_addr = -1;
state->trace_start_addr = -1;
cnsl->put_string_lf("Tracing start address reset");
}
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") {
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") {
cnsl->put_string_lf("expected p (physical address) or v (virtual address)");
continue;
return true;
}
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);
}
continue;
return true;
}
else if (cmd == "reset" || cmd == "r") {
*stop_event = EVENT_NONE;
b->reset();
cnsl->put_string_lf("resetted");
continue;
return true;
}
else if (cmd == "cfgdisk") {
configure_disk(b, cnsl);
continue;
return true;
}
#if defined(ESP32)
else if (cmd == "cfgnet") {
configure_network(cnsl);
continue;
return true;
}
else if (cmd == "chknet") {
check_network(cnsl);
continue;
return true;
}
else if (cmd == "startnet") {
start_network(cnsl);
continue;
return true;
}
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);
continue;
return true;
}
#endif
else if (cmd == "stats") {
show_run_statistics(cnsl, c);
continue;
return true;
}
else if (parts[0] == "ramsize") {
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));
}
continue;
return true;
}
else if (parts[0] == "bl" && parts.size() == 2) {
if (parts.at(1) == "rk05")
@ -1121,32 +1123,32 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
else
cnsl->put_string_lf("???");
continue;
return true;
}
else if (parts[0] == "trl") {
if (parts.size() == 1)
t_rl.reset();
state->t_rl.reset();
else
t_rl = std::stoi(parts.at(1));
state->t_rl = std::stoi(parts.at(1));
continue;
return true;
}
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);
continue;
return true;
}
else if (cmd == "turbo") {
turbo = !turbo;
state->turbo = !state->turbo;
if (turbo)
if (state->turbo)
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") {
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"));
continue;
return true;
}
else if (parts[0] == "setll" && parts.size() == 2) {
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);
}
continue;
return true;
}
#if IS_POSIX
else if (parts[0] == "ser" && parts.size() == 2) {
serialize_state(cnsl, b, parts.at(1));
continue;
return true;
}
#endif
else if (parts[0] == "setinthz" && parts.size() == 2) {
set_kw11_l_interrupt_freq(cnsl, b, std::stoi(parts.at(1)));
continue;
return true;
}
else if (parts[0] == "setsl" && parts.size() == 3) {
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
send_syslog(info, "Hello, world!");
continue;
return true;
}
else if (parts[0] == "pts" && parts.size() == 2) {
cnsl->enable_timestamp(std::stoi(parts[1]));
continue;
return true;
}
else if (cmd == "qi") {
show_queued_interrupts(cnsl, c);
continue;
return true;
}
else if (parts[0] == "log") {
DOLOG(info, true, cmd.c_str());
continue;
return true;
}
else if (parts[0] == "bic" && parts.size() == 2) {
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");
}
continue;
return true;
}
else if (parts[0] == "lt") {
if (parts.size() == 2)
@ -1234,42 +1236,42 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
else
tm11_load_tape(cnsl, b, { });
continue;
return true;
}
else if (cmd == "dir" || cmd == "ls") {
ls_l(cnsl);
continue;
return true;
}
else if (cmd == "ult") {
tm11_unload_tape(b);
continue;
return true;
}
else if (parts[0] == "testdc11") {
b->getDC11()->test_ports(cmd);
continue;
return true;
}
else if (cmd == "dp") {
cnsl->stop_panel_thread();
continue;
return true;
}
else if (cmd == "cdc11") {
configure_comm(cnsl, *b->getDC11()->get_comm_interfaces());
continue;
return true;
}
else if (cmd == "serdc11") {
serdc11(cnsl, b);
continue;
return true;
}
else if (cmd == "dserdc11") {
deserdc11(cnsl, b);
continue;
return true;
}
else if (cmd == "bt") {
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)
cnsl->put_string_lf(format("%06o %s", element.first, element.second.c_str()));
continue;
return true;
}
else if (cmd == "quit" || cmd == "q") {
#if defined(ESP32)
ESP.restart();
#endif
break;
return false;
}
else if (cmd == "help" || cmd == "h" || cmd == "?") {
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",
#if !defined(ESP32)
"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;
while(help[i])
cnsl->put_string_lf(help[i++]);
continue;
return true;
}
else {
cnsl->put_string_lf("?");
continue;
return true;
}
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;
if (turbo) {
if (state->turbo) {
while(*stop_event == EVENT_NONE)
c->step();
}
@ -1380,25 +1382,25 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
reset_cpu = false;
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);
if ((gettrace() || single_step) && (t_rl.has_value() == false || t_rl.value() == c->getPSW_runmode())) {
if (!single_step)
if ((gettrace() || state->single_step) && (state->t_rl.has_value() == false || state->t_rl.value() == c->getPSW_runmode())) {
if (!state->single_step)
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();
if (bp_result.has_value() && !single_step) {
if (bp_result.has_value() && !state->single_step) {
cnsl->put_string_lf("Breakpoint: " + bp_result.value());
break;
}
c->step();
if (single_step && --n_single_step == 0)
if (state->single_step && --state->n_single_step == 0)
break;
}
}
@ -1407,6 +1409,35 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
if (reset_cpu)
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) {
cnsl->put_string_lf(format("Exception caught: %s", e.what()));

View file

@ -7,6 +7,6 @@
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);

View file

@ -258,6 +258,7 @@ void help()
printf("-b enable bootloader (builtin)\n");
printf("-n ncurses UI\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,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");
@ -277,6 +278,7 @@ int main(int argc, char *argv[])
std::string disk_type = "rk05";
bool run_debugger = false;
std::optional<std::string> debugger_init;
bool enable_bootloader = false;
bootloader_t bootloader = BL_NONE;
@ -311,13 +313,17 @@ int main(int argc, char *argv[])
std::optional<std::string> dc11_device;
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) {
case 'h':
help();
return 1;
case 'f':
debugger_init = optarg;
break;
case '1':
dc11_device = optarg;
break;
@ -612,7 +618,7 @@ int main(int argc, char *argv[])
if (is_bic)
run_bic(cnsl, b, &event, bic_start.value());
else if (run_debugger || (bootloader == BL_NONE && test.empty() && tape.empty()))
debugger(cnsl, b, &event);
debugger(cnsl, b, &event, debugger_init);
else if (benchmark) {
// FILL MEMORY
memory *m = b->getRAM();