From b96a280e10a800cf2962704b03db430ecc47f6b3 Mon Sep 17 00:00:00 2001 From: xinyangli Date: Fri, 9 Aug 2024 13:10:47 +0800 Subject: [PATCH] feat: support switching targets through monitor commands --- include/difftest.hpp | 2 ++ src/difftest.cpp | 50 +++++++++++++++++++++++++++++++++++++------- src/gdbstub.cpp | 12 +++++++++-- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/include/difftest.hpp b/include/difftest.hpp index c585844..2f7b301 100644 --- a/include/difftest.hpp +++ b/include/difftest.hpp @@ -46,6 +46,8 @@ public: bool check_all(); int sync_regs_to_ref(void); + std::string list_targets(void); + std::string switch_target(int index); inline void halt() { __atomic_store_n(&halt_status, true, __ATOMIC_RELAXED); diff --git a/src/difftest.cpp b/src/difftest.cpp index e5648d1..0567ae3 100644 --- a/src/difftest.cpp +++ b/src/difftest.cpp @@ -1,9 +1,12 @@ #include "api.hpp" +#include #include #include #include #include +#include #include +#include Difftest::Difftest(Target &&dut, std::vector &&refs) { this->dut = std::move(dut); @@ -82,8 +85,12 @@ Difftest::ExecRet Difftest::exec(size_t n, gdb_action_t *ret) { gdb_action_t Difftest::stepi() { gdb_action_t ret = {.reason = gdb_action_t::ACT_NONE}; - exec(1, &ret); - check_all(); + ExecRet exec_result = exec(1, &ret); + if (exec_result.do_difftest) { + check_all(); + } else { + sync_regs_to_ref(); + } return ret; } @@ -93,11 +100,14 @@ gdb_action_t Difftest::cont() { start_run(); while (!is_halt()) { exec_ret = exec(1, &ret); - if (exec_ret.do_difftest) - if (check_all() == false) { - ret.reason = gdb_action_t::ACT_BREAKPOINT; - break; - } + if (exec_ret.do_difftest) { + check_all(); + } else { + size_t pc = 0; + read_reg(32, &pc); + spdlog::debug("Difftest skipped at {}", (void *)pc); + sync_regs_to_ref(); + } if (exec_ret.at_breakpoint) break; }; @@ -135,6 +145,32 @@ int Difftest::sync_regs_to_ref(void) { return ret; } +std::string Difftest::list_targets(void) { + std::ostringstream os; + int i = 0; + for (auto it = this->begin(); it != this->end(); ++it, ++i) { + auto &target = *it; + os << i << ": " << target.meta.name << std::endl; + } + os << "current: " << current_target->meta.name << std::endl; + return os.str(); +} + +std::string Difftest::switch_target(int index) { + std::ostringstream os; + int i = 0; + for (auto it = this->begin(); it != this->end(); ++it, ++i) { + auto &target = *it; + if (i == index) { + current_target = ⌖ + os << "Switched to " << current_target->meta.name << std::endl; + return os.str(); + } + } + os << "Invalid target target index: " << index << std::endl; + return os.str(); +} + int Difftest::read_mem(size_t addr, size_t len, void *val) { return current_target->ops.read_mem(current_target->args.data(), addr, len, val); diff --git a/src/gdbstub.cpp b/src/gdbstub.cpp index e5774f2..4bb585c 100644 --- a/src/gdbstub.cpp +++ b/src/gdbstub.cpp @@ -1,3 +1,4 @@ +#include "api.hpp" #include #include #include @@ -69,12 +70,19 @@ static char *gdbstub_monitor(void *args, const char *s) { CLI::App parser; std::string ret = ""; + auto sync = parser.add_subcommand("sync", "Sync states between targets") + ->callback([&]() { diff->sync_regs_to_ref(); }); + parser.add_subcommand("list", "List targets.")->callback([&]() { + ret = diff->list_targets(); + }); parser.add_subcommand("help", "Print help message")->callback([&]() { ret = parser.help(); }); - auto sync = parser.add_subcommand("sync", "Sync states between targets") - ->callback([&]() { diff->sync_regs_to_ref(); }); + int target_index = -1; + parser.add_subcommand("switch", "Switch to another target") + ->callback([&]() { ret = diff->switch_target(target_index); }) + ->add_option("target_index", target_index, "Index of the target"); std::string cmdstr; int slen = strlen(s); int ch;