diff --git a/console_posix.cpp b/console_posix.cpp index eee9f52..826232e 100644 --- a/console_posix.cpp +++ b/console_posix.cpp @@ -47,9 +47,7 @@ void console_posix::put_char_ll(const char c) void console_posix::put_string_lf(const std::string & what) { - put_string(what); - - put_string("\r\n"); + put_string(what + "\r\n"); } void console_posix::resize_terminal() diff --git a/cpu.cpp b/cpu.cpp index 14a49bb..8af95f9 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -45,6 +45,11 @@ void cpu::remove_breakpoint(const uint16_t addr) breakpoints.erase(addr); } +std::set cpu::list_breakpoints() +{ + return breakpoints; +} + uint64_t cpu::get_instructions_executed_count() { // this may wreck havoc as it is not protected by a mutex @@ -1507,8 +1512,7 @@ std::map > cpu::disassemble(const uint16_t bool old_trace_output = trace_output; trace_output = false; - uint16_t pc = getPC(); - uint16_t instruction = b->peekWord(pc); + uint16_t instruction = b->peekWord(addr); bool word_mode = !!(instruction & 0x8000); std::string word_mode_str = word_mode ? "B" : ""; @@ -1531,7 +1535,7 @@ std::map > cpu::disassemble(const uint16_t // TODO: 100000011 if (do_opcode == 0b000) { - auto dst_text { addressing_to_string(dst_register, (pc + 2) & 65535, word_mode) }; + auto dst_text { addressing_to_string(dst_register, (addr + 2) & 65535, word_mode) }; auto next_word = dst_text.instruction_part; if (next_word != -1) @@ -1619,7 +1623,7 @@ std::map > cpu::disassemble(const uint16_t } else if (do_opcode == 0b111) { std::string src_text = format("R%d", (instruction >> 6) & 7); - auto dst_text { addressing_to_string(dst_register, (pc + 2) & 65535, word_mode) }; + auto dst_text { addressing_to_string(dst_register, (addr + 2) & 65535, word_mode) }; auto next_word = dst_text.instruction_part; if (next_word != -1) @@ -1687,7 +1691,7 @@ std::map > cpu::disassemble(const uint16_t } // source - auto src_text { addressing_to_string(src_register, (pc + 2) & 65535, word_mode) }; + auto src_text { addressing_to_string(src_register, (addr + 2) & 65535, word_mode) }; auto next_word_src = src_text.instruction_part; if (next_word_src != -1) @@ -1696,7 +1700,7 @@ std::map > cpu::disassemble(const uint16_t work_values.push_back(src_text.work_value); // destination - auto dst_text { addressing_to_string(dst_register, (pc + src_text.length) & 65535, word_mode) }; + auto dst_text { addressing_to_string(dst_register, (addr + src_text.length) & 65535, word_mode) }; auto next_word_dst = dst_text.instruction_part; if (next_word_dst != -1) @@ -1710,7 +1714,7 @@ std::map > cpu::disassemble(const uint16_t if (text.empty()) { // conditional branch instructions uint8_t cb_opcode = (instruction >> 8) & 255; int8_t offset = instruction & 255; - uint16_t new_pc = (pc + 2 + offset * 2) & 65535; + uint16_t new_pc = (addr + 2 + offset * 2) & 65535; switch(cb_opcode) { case 0b00000001: @@ -1847,7 +1851,7 @@ std::map > cpu::disassemble(const uint16_t text = format("TRAP %o", instruction & 255); if ((instruction & ~0b111111) == 0b0000000001000000) { - auto dst_text { addressing_to_string(dst_register, (pc + 2) & 65535, word_mode) }; + auto dst_text { addressing_to_string(dst_register, (addr + 2) & 65535, word_mode) }; auto next_word = dst_text.instruction_part; if (next_word != -1) @@ -1859,7 +1863,7 @@ std::map > cpu::disassemble(const uint16_t } if ((instruction & 0b1111111000000000) == 0b0000100000000000) { - auto dst_text { addressing_to_string(dst_register, (pc + 2) & 65535, word_mode) }; + auto dst_text { addressing_to_string(dst_register, (addr + 2) & 65535, word_mode) }; auto next_word = dst_text.instruction_part; if (next_word != -1) @@ -1901,7 +1905,7 @@ std::map > cpu::disassemble(const uint16_t else if (i == 6) registers.push_back(format("%06o", sp[psw >> 14])); else - registers.push_back(format("%06o", pc)); + registers.push_back(format("%06o", addr)); } out.insert({ "registers", registers }); diff --git a/cpu.h b/cpu.h index 31cefcb..bae1896 100644 --- a/cpu.h +++ b/cpu.h @@ -67,6 +67,7 @@ public: bool check_breakpoint(); void set_breakpoint(const uint16_t addr); void remove_breakpoint(const uint16_t addr); + std::set list_breakpoints(); void disassemble(void) const; std::map > disassemble(const uint16_t addr) const; diff --git a/main.cpp b/main.cpp index 1f63746..c943c60 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -127,10 +128,10 @@ uint16_t loadTape(bus *const b, const char *const file) return start; } -void disassemble(cpu *const c, console *const cnsl) +// returns size of instruction (in bytes) +int disassemble(cpu *const c, console *const cnsl, const int pc, const bool instruction_only) { -#if !defined(ESP32) - auto data = c->disassemble(c->getPC()); + auto data = c->disassemble(pc); auto registers = data["registers"]; auto psw = data["psw"][0]; @@ -145,9 +146,19 @@ void disassemble(cpu *const c, console *const cnsl) std::string instruction = data["instruction-text"].at(0); - std::string result = format("R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %s, PSW: %s, instr: %s: %s - %s", + std::string result; + + if (instruction_only) + result = format("PC: %06o, instr: %s\t%s\t%s", + pc, + instruction_values.c_str(), + instruction.c_str(), + work_values.c_str() + ); + else + result = format("R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %06o, PSW: %s, instr: %s: %s - %s", registers[0].c_str(), registers[1].c_str(), registers[2].c_str(), registers[3].c_str(), registers[4].c_str(), registers[5].c_str(), - registers[6].c_str(), registers[7].c_str(), + registers[6].c_str(), pc, psw.c_str(), instruction_values.c_str(), instruction.c_str(), @@ -158,7 +169,24 @@ void disassemble(cpu *const c, console *const cnsl) cnsl->debug(result); else fprintf(stderr, "%s\n", result.c_str()); -#endif + + return data["instruction-values"].size() * 2; +} + +std::map split(const std::vector & kv_array, const std::string & splitter) +{ + std::map out; + + for(auto pair : kv_array) { + auto kv = split(pair, splitter); + + if (kv.size() == 1) + out.insert({ kv[0], "" }); + else if (kv.size() == 2) + out.insert({ kv[0], kv[1] }); + } + + return out; } volatile bool sw = false; @@ -310,13 +338,43 @@ int main(int argc, char *argv[]) bool temp = terminate; std::string cmd = cnsl->read_line(format("%d%d", event, temp)); auto parts = split(cmd, " "); + auto kv = split(parts, "="); if (cmd == "go") single_step = false; else if (cmd == "single" || cmd == "s") single_step = true; - else if (cmd == "disassemble" || cmd == "d") { - disassemble(c, single_step ? cnsl : nullptr); + else if ((cmd == "sbp" || cmd == "cbp") && parts.size() == 2){ + uint16_t pc = std::stoi(parts.at(1).c_str()); + + if (cmd == "sbp") { + c->set_breakpoint(pc); + + cnsl->put_string_lf(format("Set breakpoint at %06o", pc)); + } + else { + c->remove_breakpoint(pc); + + cnsl->put_string_lf(format("Clear breakpoint at %06o", pc)); + } + + continue; + } + else if (cmd == "lbp") { + auto bps = c->list_breakpoints(); + + cnsl->put_string_lf("Breakpoints:"); + + for(auto pc : bps) + cnsl->put_string_lf(format(" %06o", pc)); + } + 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; + + for(int i=0; iput_string_lf("disassemble/d - show current instruction"); + cnsl->put_string_lf("disassemble/d - show current instruction (pc=/n=)"); cnsl->put_string_lf("go - run until trap or ^e"); cnsl->put_string_lf("quit/q - stop emulator"); 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)"); continue; } @@ -346,7 +405,7 @@ int main(int argc, char *argv[]) while(!event && !terminate && !interrupt_emulation) { if (tracing || single_step) - disassemble(c, single_step ? cnsl : nullptr); + disassemble(c, single_step ? cnsl : nullptr, c->getPC(), false); if (c->check_breakpoint() && !single_step) break;