diff --git a/CMakeLists.txt b/CMakeLists.txt index 81f8fcb..a9016a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable( kek breakpoint.cpp breakpoint_and.cpp + breakpoint_memory.cpp breakpoint_or.cpp breakpoint_parser.cpp breakpoint_register.cpp diff --git a/breakpoint_memory.cpp b/breakpoint_memory.cpp new file mode 100644 index 0000000..d0b647a --- /dev/null +++ b/breakpoint_memory.cpp @@ -0,0 +1,76 @@ +#include + +#include "breakpoint_memory.h" +#include "cpu.h" +#include "utils.h" + + +breakpoint_memory::breakpoint_memory(bus *const b, const uint32_t addr, const word_mode_t word_mode, const bool is_virtual, const std::set & values): + breakpoint(b), + addr(addr), + word_mode(word_mode), + is_virtual(is_virtual), + values(values) +{ +} + +breakpoint_memory::~breakpoint_memory() +{ +} + +std::optional breakpoint_memory::is_triggered() const +{ + uint16_t v = 0; + + if (is_virtual) + v = b->read(addr, word_mode, rm_cur, true, i_space); + else + v = b->readPhysical(addr); + + auto it = values.find(v); + if (it == values.end()) + return { }; + + return format("MEM%c%c[%08a]=%06o", word_mode == wm_byte ? 'B' : 'W', is_virtual ? 'V' : 'P', addr, v); +} + +std::pair > breakpoint_memory::parse(bus *const b, const std::string & in) +{ + auto parts = split(in, "="); + if (parts.size() != 2) + return { nullptr, "memory: key or value missing" }; + + auto values_in = parts.at(1); + auto v_parts = split(values_in, ","); + std::set values; + for(auto & v: v_parts) + values.insert(std::stoi(v, nullptr, 8)); + + auto key = parts.at(0); + if (key.size() < 8 || (key.substr(0, 3) != "MEM" && key.substr(0, 3) != "mem")) + return { nullptr, { } }; + + word_mode_t wm = toupper(key[3]) == 'B' ? wm_byte : wm_word; + bool is_virtual = toupper(key[4]) == 'V'; + + std::size_t end_marker = key.find(']'); + uint32_t addr = std::stoi(key.substr(6, end_marker - 6), nullptr, 8); + + return { new breakpoint_memory(b, addr, wm, is_virtual, values), { } }; +} + +std::string breakpoint_memory::emit() const +{ + std::string out; + + for(auto & v: values) { + if (out.empty()) + out = format("MEM%c%c[%08a]=", word_mode == wm_byte ? 'B' : 'W', is_virtual ? 'V' : 'P', addr); + else + out += ","; + + out += format("%06o", v); + } + + return out; +} diff --git a/breakpoint_memory.h b/breakpoint_memory.h new file mode 100644 index 0000000..f56fffd --- /dev/null +++ b/breakpoint_memory.h @@ -0,0 +1,26 @@ +#include +#include +#include + +#include "breakpoint.h" +#include "bus.h" + + +class breakpoint_memory : public breakpoint +{ +private: + const uint32_t addr { 0 }; + const word_mode_t word_mode { wm_word }; + const bool is_virtual { false }; + std::set values; + +public: + breakpoint_memory(bus *const b, const uint32_t addr, const word_mode_t word_mode, const bool is_virtual, const std::set & values); + virtual ~breakpoint_memory(); + + virtual std::optional is_triggered() const override; + + static std::pair > parse(bus *const b, const std::string & in); + + virtual std::string emit() const override; +}; diff --git a/breakpoint_parser.cpp b/breakpoint_parser.cpp index 845cab2..4a3141c 100644 --- a/breakpoint_parser.cpp +++ b/breakpoint_parser.cpp @@ -3,6 +3,7 @@ #include "breakpoint.h" #include "breakpoint_and.h" +#include "breakpoint_memory.h" #include "breakpoint_or.h" #include "breakpoint_register.h" #include "bus.h" @@ -82,12 +83,22 @@ std::pair > parse_breakpoint(bus *const combine = combine_single; auto rc_reg = breakpoint_register::parse(b, parts[i]); - if (rc_reg.first == nullptr) { + if (rc_reg.first == nullptr && rc_reg.second.has_value()) { delete_parsed(parsed); - return { nullptr, "not understood" }; + return { nullptr, "not understood: " + rc_reg.second.value() }; } - parsed.push_back(rc_reg.first); + if (rc_reg.first) + parsed.push_back(rc_reg.first); + + auto rc_mem = breakpoint_memory::parse(b, parts[i]); + if (rc_mem.first == nullptr && rc_mem.second.has_value()) { + delete_parsed(parsed); + return { nullptr, "not understood: " + rc_mem.second.value() }; + } + + if (rc_mem.first) + parsed.push_back(rc_mem.first); } } } diff --git a/breakpoint_register.cpp b/breakpoint_register.cpp index ac2a59b..622bf64 100644 --- a/breakpoint_register.cpp +++ b/breakpoint_register.cpp @@ -57,7 +57,7 @@ std::pair > breakpoint_registe return { new breakpoint_register(b, 7, values), { } }; } - return { nullptr, "register: invalid specification" }; + return { nullptr, { } }; } std::string breakpoint_register::emit() const diff --git a/debugger.cpp b/debugger.cpp index f33fde4..137d646 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -1024,7 +1024,9 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto 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(" e.g.: (pc=0123 and r0=123 and (r4=07 or r4=0456))"); + cnsl->put_string_lf(" e.g.: (pc=0123 and memwv[04000]=0200,0300 and (r4=07,05 or r5=0456))"); + cnsl->put_string_lf(" values seperated by ',', char after mem is w/b (word/byte), then + cnsl->put_string_lf(" follows v/p (virtual/physical)"); 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"); diff --git a/main.cpp b/main.cpp index 5d64512..2cde331 100644 --- a/main.cpp +++ b/main.cpp @@ -323,7 +323,7 @@ int main(int argc, char *argv[]) cpu *c = new cpu(b, &event); b->add_cpu(c); - std::pair > rc = parse_breakpoint(b, "(pc=0123 and (r0=01456 or r2=1))"); + 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())