From e99236f7113aaf66c9f7b0e2be38fdf582827b90 Mon Sep 17 00:00:00 2001 From: xinyangli Date: Thu, 11 Apr 2024 11:44:54 +0800 Subject: [PATCH] feat(npc): ebreak support through external inst matching --- npc/csrc/Flow/main.cpp | 6 ++++-- npc/include/components.hpp | 3 +++ npc/include/trm_difftest.hpp | 18 ++++++++++++---- npc/include/trm_interface.hpp | 15 +++++++++++++ npc/utils/sdb/console.cpp | 6 ++++++ npc/utils/sdb/include/console.hpp | 7 +++++++ npc/utils/sdb/include/sdb.hpp | 35 +++++++++++++++++++++++-------- npc/utils/sdb/sdb.cpp | 32 +++++++++++++++++++--------- 8 files changed, 97 insertions(+), 25 deletions(-) diff --git a/npc/csrc/Flow/main.cpp b/npc/csrc/Flow/main.cpp index f2933b4..ea71189 100644 --- a/npc/csrc/Flow/main.cpp +++ b/npc/csrc/Flow/main.cpp @@ -49,8 +49,10 @@ vpiHandle pc = nullptr; namespace NPC { void npc_memcpy(paddr_t addr, void *buf, size_t sz, bool direction) { if (direction == TRM_FROM_MACHINE) { - memcpy(buf, static_cast *>(pmem_get())->mem.data(), - sz); + memcpy( + buf, + static_cast *>(pmem_get())->guest_to_host(addr), + sz); } }; diff --git a/npc/include/components.hpp b/npc/include/components.hpp index 9b5f546..4f8c592 100644 --- a/npc/include/components.hpp +++ b/npc/include/components.hpp @@ -79,5 +79,8 @@ public: // printf("waddr: 0x%x\n", waddr); mem[addr_to_index((uint32_t)waddr)] = expand_bits(wmask) & wdata; } + void *guest_to_host(std::size_t addr) { + return mem.data() + addr_to_index(addr); + } }; #endif diff --git a/npc/include/trm_difftest.hpp b/npc/include/trm_difftest.hpp index dc75c4d..dd2a93d 100644 --- a/npc/include/trm_difftest.hpp +++ b/npc/include/trm_difftest.hpp @@ -34,19 +34,29 @@ struct DifftestTrmInterface : public TrmInterface { fetch_state(); }; exec = [this](uint64_t n) { - while (n--) { + bool enable_disasm = true; + if (n > 30) { + enable_disasm = false; + } + while (n--) { word_t pc = this->ref.at("pc"); word_t inst = this->ref.at(pc); - std::cout << d.disassemble(pc, (uint8_t *)&inst, WORD_BYTES) - << std::endl; + if (enable_disasm) + std::cout << d.disassemble(pc, (uint8_t *)&inst, WORD_BYTES) + << std::endl; + if (inst == 1048691) { + // ebreak + throw TrmRuntimeException(TrmRuntimeException::EBREAK, "ebreak"); + } this->ref.exec(1); this->dut.exec(1); this->ref.fetch_state(); this->dut.fetch_state(); if (*(CPUState *)this->ref.cpu_state != *(CPUState *)this->dut.cpu_state) { - throw std::runtime_error("Difftest failed"); + throw TrmRuntimeException(TrmRuntimeException::DIFFTEST_FAILED, + "Difftest failed"); } } }; diff --git a/npc/include/trm_interface.hpp b/npc/include/trm_interface.hpp index 22a37cf..716745d 100644 --- a/npc/include/trm_interface.hpp +++ b/npc/include/trm_interface.hpp @@ -96,6 +96,21 @@ public: virtual void print(std::ostream &os) const = 0; }; +class TrmRuntimeException : public std::exception { +private: + const char *msg_; + int code_; + +public: + enum { EBREAK, DIFFTEST_FAILED }; + TrmRuntimeException(int code, const char *message) + : code_(code), msg_(message) {} + + virtual const char *what() const throw() { return msg_; } + + int error_code() const { return code_; } +}; + struct RefTrmInterface : TrmInterface { RefTrmInterface(std::filesystem::path lib_file) { void *handle = dlopen(lib_file.c_str(), RTLD_LAZY); diff --git a/npc/utils/sdb/console.cpp b/npc/utils/sdb/console.cpp index 485e192..61c9452 100644 --- a/npc/utils/sdb/console.cpp +++ b/npc/utils/sdb/console.cpp @@ -83,6 +83,12 @@ void Console::registerCommand(const std::string &s, CommandFunction f) { pimpl_->commands_[s] = f; } +void Console::removeCommands(const std::vector sv) { + for (auto const &s : sv) { + pimpl_->commands_.erase(s); + } +} + std::vector Console::getRegisteredCommands() const { std::vector allCommands; for (auto &pair : pimpl_->commands_) diff --git a/npc/utils/sdb/include/console.hpp b/npc/utils/sdb/include/console.hpp index 538ce2f..69c4099 100644 --- a/npc/utils/sdb/include/console.hpp +++ b/npc/utils/sdb/include/console.hpp @@ -64,6 +64,13 @@ public: */ void registerCommand(const std::string &s, CommandFunction f); + /** + * @brief This function removes a list of registered commands. + * + * @param sv The vector of command names to be removed. + */ + void removeCommands(const std::vector sv); + /** * @brief This function returns a list with the currently available commands. * diff --git a/npc/utils/sdb/include/sdb.hpp b/npc/utils/sdb/include/sdb.hpp index 54ec69b..f3e1ab0 100644 --- a/npc/utils/sdb/include/sdb.hpp +++ b/npc/utils/sdb/include/sdb.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -13,7 +14,12 @@ using ret = cr::Console::ReturnCode; namespace SDB { -enum SDBStatus { SDB_SUCCESS, SDB_WRONG_ARGUMENT, SDB_DIFFTEST_FAILED }; +enum SDBStatus { + SDB_SUCCESS, + SDB_EBREAK = 2, + SDB_WRONG_ARGUMENT, + SDB_DIFFTEST_FAILED +}; class SDBHandlers; @@ -36,10 +42,11 @@ private: int cmd_step(const std::vector &input); int cmd_info_registers(const std::vector &input); int cmd_print(const std::vector &input); + int exec_catch(uint64_t); public: SDBHandlers(const TrmInterface &funcs) : funcs(funcs){}; - void registerHandlers(cr::Console *c); + void register_handlers(cr::Console *c); }; class SDB { @@ -54,24 +61,34 @@ public: : handlers(SDBHandlers{funcs}), funcs(funcs) { c = std::make_unique(greeting); - handlers.registerHandlers(c.get()); + handlers.register_handlers(c.get()); }; int main_loop() { - int retCode; + int ret_code; funcs.init(0); + std::vector step_commands{"c", "continue", "si", + "step-instruction"}; do { - retCode = c->readLine(); + ret_code = c->readLine(); // We can also change the prompt based on last return value: - if (retCode == ret::Ok) + if (ret_code == SDB_SUCCESS || ret_code == SDB_EBREAK) c->setGreeting("\033[1;34m(npc)\033[0m "); else c->setGreeting("\033[1;31m(npc)\033[0m "); - if (retCode == SDB_WRONG_ARGUMENT) { - std::cout << "Wrong argument give to command\n"; + switch (ret_code) { + case SDB_EBREAK: { + std::cout << "\033[1;31m=== ebreak ===\033[0m" << std::endl; + c->removeCommands(step_commands); + break; } - } while (retCode != ret::Quit); + case SDB_WRONG_ARGUMENT: { + std::cout << "Wrong argument(s) is given to command handler\n"; + break; + } + } + } while (ret_code != ret::Quit); return 0; } }; diff --git a/npc/utils/sdb/sdb.cpp b/npc/utils/sdb/sdb.cpp index 61c8853..d38ea02 100644 --- a/npc/utils/sdb/sdb.cpp +++ b/npc/utils/sdb/sdb.cpp @@ -20,11 +20,28 @@ std::ostream &operator<<(std::ostream &os, const TrmInterface &d) { namespace SDB { +int SDBHandlers::exec_catch(uint64_t n) { + try { + this->funcs.exec(n); + } catch (TrmRuntimeException &e) { + switch (e.error_code()) { + case TrmRuntimeException::EBREAK: + return SDB_EBREAK; + case TrmRuntimeException::DIFFTEST_FAILED: + std::cout << "Difftest Failed" << std::endl << funcs << std::endl; + return SDB_DIFFTEST_FAILED; + default: + std::cerr << "Unknown error code" << std::endl; + exit(1); + } + } + return SDB_SUCCESS; +} + int SDBHandlers::cmd_continue(const cr::Console::Arguments &input) { if (input.size() > 1) return SDB_WRONG_ARGUMENT; - this->funcs.exec(-1); - return SDB_SUCCESS; + return exec_catch(-1); } int SDBHandlers::cmd_step(const std::vector &input) { @@ -32,14 +49,8 @@ int SDBHandlers::cmd_step(const std::vector &input) { return SDB_WRONG_ARGUMENT; } uint64_t step_count = input.size() == 2 ? std::stoull(input[1]) : 1; - try { - this->funcs.exec(step_count); - } catch (std::runtime_error) { - std::cout << "Difftest Failed" << std::endl << funcs << std::endl; - return SDB_DIFFTEST_FAILED; - } + return exec_catch(step_count); // std::cout << funcs << std::endl; - return SDB_SUCCESS; } int SDBHandlers::cmd_info_registers(const std::vector &input) { @@ -72,7 +83,7 @@ int SDBHandlers::cmd_print(const std::vector &input) { return SDB_SUCCESS; } -void SDBHandlers::registerHandlers(cr::Console *c) { +void SDBHandlers::register_handlers(cr::Console *c) { for (auto &h : this->all_handlers) { for (auto &name : h.names) { std::function)> f{ @@ -81,4 +92,5 @@ void SDBHandlers::registerHandlers(cr::Console *c) { } } } + } // namespace SDB