From 85d7840804704be4da16a6c3933c7cbdf2984daf Mon Sep 17 00:00:00 2001 From: xinyangli Date: Thu, 1 Aug 2024 18:53:17 +0800 Subject: [PATCH 1/2] npc: split gdbstub api into seperate file --- .gitignore | 1 + flake.nix | 10 +- npc/CMakeLists.txt | 4 +- npc/csrc/Flow/CMakeLists.txt | 8 +- npc/csrc/Flow/config.cpp | 9 +- npc/csrc/Flow/gdbstub_wrapper.cpp | 196 +++++++++++++++++++++++++++ npc/csrc/Flow/main.cpp | 177 +----------------------- npc/csrc/devices/CMakeLists.txt | 1 + npc/csrc/devices/include/devices.hpp | 11 +- npc/csrc_nvboard/Keyboard/main.cpp | 7 +- npc/include/components.hpp | 59 +++----- npc/include/config.hpp | 7 +- npc/include/types.h | 23 +++- npc/include/vl_wrapper.hpp | 40 +++--- npc/include/vpi_wrapper.hpp | 4 + 15 files changed, 287 insertions(+), 270 deletions(-) create mode 100644 npc/csrc/Flow/gdbstub_wrapper.cpp diff --git a/.gitignore b/.gitignore index 76cec07..dcecdc1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +**/.gdbinit !*/ difftest/ !/nemu/* diff --git a/flake.nix b/flake.nix index d5c35f1..74de402 100644 --- a/flake.nix +++ b/flake.nix @@ -93,7 +93,7 @@ devShells.npc = pkgs.mkShell.override { stdenv = pkgs.ccacheStdenv; } { inherit (self.checks.${system}.pre-commit-check) shellHook; CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin"; - NPC_IMAGES_DIR="${self.packages.${system}.am-kernels-npc}/share/am-kernels"; + NPC_IMAGES_PATH = "${self.packages.${system}.rv32Cross.am-kernels-npc}/share/am-kernels"; packages = with pkgs; [ clang-tools cmake @@ -109,6 +109,7 @@ nativeBuildInputs = with pkgs; [ cmake + ninja sbt nvboard nixpkgs-circt162.legacyPackages.${system}.circt @@ -117,10 +118,11 @@ flex bison verilator - self.packages.${system}.am-kernels-npc + self.packages.${system}.rv32Cross.am-kernels-npc ]; buildInputs = with pkgs; [ + spdlog nvboard openssl libllvm @@ -128,10 +130,6 @@ readline mini-gdbstub ] ++ self.checks.${system}.pre-commit-check.enabledPackages; - - cmakeFlags = [ - "-DDIFFTEST_LIB:string=${self.packages.${system}.nemu-lib}/lib/riscv32-nemu-interpreter-so" - ]; }; } ); diff --git a/npc/CMakeLists.txt b/npc/CMakeLists.txt index 4b4424e..2903475 100644 --- a/npc/CMakeLists.txt +++ b/npc/CMakeLists.txt @@ -41,6 +41,7 @@ if(BUILD_SIM_NVBOARD_TARGET) find_package(SDL2_image REQUIRED) endif() find_package(CLI11 CONFIG REQUIRED) +find_package(spdlog REQUIRED) option(ENABLE_SDB "Enable simple debugger" OFF) @@ -58,9 +59,6 @@ set(CHISEL_OUTPUT_VERILATOR_CONF ${CHISEL_OUTPUT_DIR}/conf.vlt) set(CHISEL_OUTPUT_TOPMODULE ${CHISEL_OUTPUT_DIR}/${TOPMODULE}.sv) set(CHISEL_EMIT_ARGS "--target-dir ${CHISEL_OUTPUT_DIR}") -# -- Find difftest binaries -file(GLOB_RECURSE DIFFTEST_BINARY_FILES "${DIFFTEST_RESOURCE_DIR}/*.bin") - # -- Build NVBoard executable if(BUILD_SIM_NVBOARD_TARGET) add_subdirectory(csrc_nvboard) diff --git a/npc/csrc/Flow/CMakeLists.txt b/npc/csrc/Flow/CMakeLists.txt index d64cfca..2af6a5b 100644 --- a/npc/csrc/Flow/CMakeLists.txt +++ b/npc/csrc/Flow/CMakeLists.txt @@ -1,6 +1,6 @@ include(ChiselBuild) -add_executable(V${TOPMODULE} config.cpp main.cpp) -target_link_libraries(V${TOPMODULE} PRIVATE devices gdbstub) +add_executable(V${TOPMODULE} config.cpp gdbstub_wrapper.cpp main.cpp) +target_link_libraries(V${TOPMODULE} PRIVATE devices gdbstub spdlog::spdlog) target_include_directories(V${TOPMODULE} PRIVATE ${CMAKE_SOURCE_DIR}/include) verilate( @@ -28,8 +28,8 @@ foreach(DIFFTEST_BINARY_FILE IN LISTS DIFFTEST_BINARY_FILES) unset(FILENAME) endforeach() -add_library(${TOPMODULE} SHARED config.cpp main.cpp) -target_link_libraries(${TOPMODULE} PRIVATE devices gdbstub) +add_library(${TOPMODULE} SHARED config.cpp gdbstub_wrapper.cpp) +target_link_libraries(${TOPMODULE} PRIVATE devices gdbstub spdlog::spdlog) target_include_directories(${TOPMODULE} PRIVATE ${CMAKE_SOURCE_DIR}/include) set_property(TARGET PROPERTY POSITION_INDEPENDENT_CODE ON) target_link_options(${TOPMODULE} PRIVATE -Wl,-E) diff --git a/npc/csrc/Flow/config.cpp b/npc/csrc/Flow/config.cpp index 71e042f..035fe24 100644 --- a/npc/csrc/Flow/config.cpp +++ b/npc/csrc/Flow/config.cpp @@ -2,8 +2,10 @@ void Config::cli_parse(int argc, char **argv) { CLI::App app; + app.add_option("-l,--listen", gdbsocket, + "Listen to debugger at this address"); + app.add_flag("-g", do_debug, "Listen for gdb"); app.add_option("-m,--memory", memory_file, "Content of memory") - ->required() ->check(CLI::ExistingFile); app.add_flag("!--no-bin", memory_file_binary, "Memory file is in text format"); @@ -12,11 +14,6 @@ void Config::cli_parse(int argc, char **argv) { app.add_option("--diff-lib", lib_ref, "Dynamic library file of difftest reference") ->check(CLI::ExistingFile); - app.add_flag("--mtrace", do_mtrace, "Enable memory tracing"); - app.add_option( - "--mtrace-range", mtrace_ranges, - "Specify memory tracing range (default: 0x80000000-0x8fffffff)") - ->delimiter(','); try { app.parse(argc, argv); diff --git a/npc/csrc/Flow/gdbstub_wrapper.cpp b/npc/csrc/Flow/gdbstub_wrapper.cpp new file mode 100644 index 0000000..970ce55 --- /dev/null +++ b/npc/csrc/Flow/gdbstub_wrapper.cpp @@ -0,0 +1,196 @@ +extern "C" { +#include +} +#include "components.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using Registers = _RegistersVPI; +using VlModule = VlModuleInterfaceCommon; + +// SDB::SDB sdb_dut; +bool g_skip_memcheck = false; +VlModule *top; +Registers *regs; +vpiHandle pc = nullptr; + +const size_t PMEM_START = 0x80000000; +const size_t PMEM_END = 0x87ffffff; + +extern "C" { +/* === Memory Access === */ +using MMap = MemoryMap, Devices::DeviceMap>; +void *pmem_get() { + static Devices::DeviceMap devices{ + new Devices::Serial(0x10000000, 0x1000), + new Devices::RTC(0x10001000, 0x1000), + }; + static auto pmem = new MemoryMap, Devices::DeviceMap>( + std::make_unique>(config.memory_file, true, PMEM_START, + PMEM_END), + std::make_unique(devices)); + return pmem; +} + +int pmem_read(int raddr) { + void *pmem = pmem_get(); + auto mem = static_cast(pmem); + // TODO: Do memory difftest at memory read and write to diagnose at a finer + // granularity + mem->trace(raddr, true, regs->get_pc()); + if (g_skip_memcheck) + return mem->read(PMEM_START); + return mem->read(raddr); +} + +void pmem_write(int waddr, int wdata, char wmask) { + void *pmem = pmem_get(); + auto mem = static_cast(pmem); + mem->trace((std::size_t)waddr, false, regs->get_pc(), wdata); + return mem->write((std::size_t)waddr, wdata, wmask); +} + +/* === For gdbstub === */ + +int npc_read_mem(void *args, size_t addr, size_t len, void *val) { + void *pmem = pmem_get(); + auto mmap = static_cast(pmem); + return mmap->copy_to(addr, (uint8_t *)val, len); +} + +int npc_write_mem(void *args, size_t addr, size_t len, void *val) { + void *pmem = pmem_get(); + auto mmap = static_cast(pmem); + return mmap->copy_from(addr, (uint8_t *)val, len); +} + +int npc_read_reg(void *args, int regno, size_t *value) { + if (regno == 32) + *value = regs->get_pc(); + else + *value = (*regs)[regno]; + return 0; +} + +int npc_write_reg(void *args, int regno, size_t value) { return 1; } + +inline void breakpoint_to_action(const Breakpoint *bp, gdb_action_t *res) { + if (bp == nullptr) { + res->reason = gdb_action_t::ACT_NONE; + return; + } + switch (bp->type) { + case BP_SOFTWARE: + res->reason = gdb_action_t::ACT_BREAKPOINT; + break; + case BP_ACCESS: + res->reason = gdb_action_t::ACT_WATCH; + break; + case BP_WRITE: + res->reason = gdb_action_t::ACT_WWATCH; + break; + case BP_READ: + res->reason = gdb_action_t::ACT_RWATCH; + break; + } + res->data = bp->addr; +} + +void npc_cont(void *args, gdb_action_t *res) { + DbgState *dbg = (DbgState *)args; + const Breakpoint *stopped_at = nullptr; + stopped_at = top->cont(*dbg->bp); + breakpoint_to_action(stopped_at, res); +} + +void npc_stepi(void *args, gdb_action_t *res) { + DbgState *dbg = (DbgState *)args; + const Breakpoint *stopped_at = nullptr; + stopped_at = top->stepi(*dbg->bp); + breakpoint_to_action(stopped_at, res); +} + +bool npc_set_bp(void *args, size_t addr, bp_type_t type) { + DbgState *dbg = (DbgState *)args; + for (const auto &bp : *dbg->bp) { + if (bp.addr == addr && bp.type == type) { + return true; + } + } + dbg->bp->push_back({.addr = addr, .type = type}); + return true; +} + +bool npc_del_bp(void *args, size_t addr, bp_type_t type) { + DbgState *dbg = (DbgState *)args; + for (auto it = dbg->bp->begin(); it != dbg->bp->end(); it++) { + if (it->addr == addr && it->type == type) { + std::swap(*it, *dbg->bp->rbegin()); + dbg->bp->pop_back(); + return true; + } + } + return false; +} + +void npc_on_interrupt(void *args) { ; } + +void npc_init(void *args) { + DbgState *dbg = (DbgState *)args; + void *mem = pmem_get(); + dbg->bp = new std::vector; + + top = new VlModule; + regs = new Registers("TOP.Flow.reg_0.regFile_", "TOP.Flow.pc.out"); + top->setup(config.wavefile, regs); + top->reset_eval(10); +} + +bool npc_do_difftest = true; + +static gdbstub_t gdbstub_priv; +arch_info_t npc_isa_arch_info{ + .target_desc = strdup(TARGET_RV32), .reg_num = 32, .reg_byte = 4}; + +size_t npc_dbg_state_size = sizeof(DbgState); + +} // extern "C" + +int gdbstub_loop() { + DbgState dbg; + + target_ops npc_gdbstub_ops = {.cont = npc_cont, + .stepi = npc_stepi, + .read_reg = npc_read_reg, + .write_reg = npc_write_reg, + .read_mem = npc_read_mem, + .write_mem = npc_write_mem, + .set_bp = npc_set_bp, + .del_bp = npc_del_bp, + .on_interrupt = NULL}; + + if (!config.do_debug) { + gdb_action_t res; + npc_init(&dbg); + npc_cont(&dbg, &res); + return !(res.reason == gdb_action_t::ACT_SHUTDOWN); + } + + if (!gdbstub_init(&gdbstub_priv, &npc_gdbstub_ops, + (arch_info_t)npc_isa_arch_info, NULL, + config.gdbsocket.c_str())) { + return EINVAL; + } + npc_init(&dbg); + + bool success = gdbstub_run(&gdbstub_priv, &dbg); + // gdbstub_close(&gdbstub_priv); + return !success; +} diff --git a/npc/csrc/Flow/main.cpp b/npc/csrc/Flow/main.cpp index 069abe4..ff35334 100644 --- a/npc/csrc/Flow/main.cpp +++ b/npc/csrc/Flow/main.cpp @@ -1,180 +1,13 @@ -extern "C" { -#include -} -// #include "VFlow___024root.h" -#include "components.hpp" -#include #include -#include -#include -#include -#include +#include +#include #include -#include -#include -#include -#include -using Registers = _RegistersVPI; -using VlModule = VlModuleInterfaceCommon; - -// SDB::SDB sdb_dut; -bool g_skip_memcheck = false; -VlModule *top; -Registers *regs; -vpiHandle pc = nullptr; - -const size_t PMEM_START = 0x80000000; -const size_t PMEM_END = 0x87ffffff; - -struct DbgState { - std::vector *bp; -}; - -extern "C" { - -/* === Memory Access === */ -using MMap = MemoryMap, Devices::DeviceMap>; -void *pmem_get() { - static Devices::DeviceMap devices{ - new Devices::Serial(0x10000000, 0x1000), - new Devices::RTC(0x10001000, 0x1000), - }; - static auto pmem = new MemoryMap, Devices::DeviceMap>( - std::make_unique>( - "/nix/store/" - "nv2c00y24qwz1jihfbaip9n1lskbzyb3-am-kernel-riscv32-none-elf-2024-07-" - "10/share/am-kernels/add.bin", - config.memory_file_binary, PMEM_START, PMEM_END), - std::make_unique(devices), config.mtrace_ranges); - return pmem; -} - -int pmem_read(int raddr) { - void *pmem = pmem_get(); - auto mem = static_cast(pmem); - // TODO: Do memory difftest at memory read and write to diagnose at a finer - // granularity - if (config.do_mtrace) - mem->trace(raddr, true, regs->get_pc()); - if (g_skip_memcheck) - return mem->read(PMEM_START); - return mem->read(raddr); -} - -void pmem_write(int waddr, int wdata, char wmask) { - void *pmem = pmem_get(); - auto mem = static_cast(pmem); - if (config.do_mtrace) - mem->trace((std::size_t)waddr, false, regs->get_pc(), wdata); - return mem->write((std::size_t)waddr, wdata, wmask); -} - -/* === For gdbstub === */ - -int npc_read_mem(void *args, size_t addr, size_t len, void *val) { - void *pmem = pmem_get(); - auto mmap = static_cast(pmem); - mmap->copy_to(addr, (uint8_t *)val, len); - return 0; -} - -int npc_write_mem(void *args, size_t addr, size_t len, void *val) { - void *pmem = pmem_get(); - auto mmap = static_cast(pmem); - mmap->copy_from(addr, (uint8_t *)val, len); - return 0; -} - -int npc_read_reg(void *args, int regno, size_t *value) { - if (regno == 32) - *value = regs->get_pc(); - else - *value = (*regs)[regno]; - return 0; -} - -int npc_write_reg(void *args, int regno, size_t value) { return 1; } - -void npc_cont(void *args, gdb_action_t *res) { - DbgState *dbg = (DbgState *)args; - *res = top->eval(*dbg->bp); -} - -void npc_stepi(void *args, gdb_action_t *res) { - DbgState *dbg = (DbgState *)args; - *res = top->eval(*dbg->bp); -} - -bool npc_set_bp(void *args, size_t addr, bp_type_t type) { - DbgState *dbg = (DbgState *)args; - for (const auto &bp : *dbg->bp) { - if (bp.addr == addr && bp.type == type) { - return true; - } - } - dbg->bp->push_back({.addr = addr, .type = type}); - return true; -} - -bool npc_del_bp(void *args, size_t addr, bp_type_t type) { - DbgState *dbg = (DbgState *)args; - for (auto it = dbg->bp->begin(); it != dbg->bp->end(); it++) { - if (it->addr == addr && it->type == type) { - std::swap(*it, *dbg->bp->rbegin()); - dbg->bp->pop_back(); - return true; - } - } - return false; -} - -void npc_on_interrupt(void *args) { ; } - -void npc_init(void *args) { - DbgState *dbg = (DbgState *)args; - dbg->bp = new std::vector; - - top = new VlModule; - regs = new Registers("TOP.Flow.reg_0.regFile_", "TOP.Flow.pc.out"); - top->setup(config.wavefile, regs); - top->reset_eval(10); -} - -static gdbstub_t gdbstub_priv; -arch_info_t isa_arch_info = { - .target_desc = strdup(TARGET_RV32), .reg_num = 32, .reg_byte = 4}; - -size_t argsize = sizeof(DbgState); - -} // extern "C" - -int gdbstub_loop() { - DbgState dbg; - - target_ops npc_gdbstub_ops = {.cont = npc_cont, - .stepi = npc_stepi, - .read_reg = npc_read_reg, - .write_reg = npc_write_reg, - .read_mem = npc_read_mem, - .write_mem = npc_write_mem, - .set_bp = npc_set_bp, - .del_bp = npc_del_bp, - .on_interrupt = NULL}; - - if (!gdbstub_init(&gdbstub_priv, &npc_gdbstub_ops, (arch_info_t)isa_arch_info, - strdup("/tmp/gdbstub-npc.sock"))) { - return EINVAL; - } - npc_init(&dbg); - - bool success = gdbstub_run(&gdbstub_priv, &dbg); - // gdbstub_close(&gdbstub_priv); - return !success; -} +int gdbstub_loop(); int main(int argc, char **argv, char **env) { + spdlog::cfg::load_env_levels(); config.cli_parse(argc, argv); - + spdlog::debug("Configuration parsed"); return gdbstub_loop(); } diff --git a/npc/csrc/devices/CMakeLists.txt b/npc/csrc/devices/CMakeLists.txt index fa33794..3480105 100644 --- a/npc/csrc/devices/CMakeLists.txt +++ b/npc/csrc/devices/CMakeLists.txt @@ -1,3 +1,4 @@ add_library(devices serial.cpp rtc.cpp) target_include_directories(devices PUBLIC include) +target_link_libraries(devices PRIVATE spdlog::spdlog) diff --git a/npc/csrc/devices/include/devices.hpp b/npc/csrc/devices/include/devices.hpp index 4954ac0..0470a44 100644 --- a/npc/csrc/devices/include/devices.hpp +++ b/npc/csrc/devices/include/devices.hpp @@ -1,14 +1,12 @@ -#include -#include #include #include #include #include #include -#include #include #include -#include +#include +#include #include namespace Devices { @@ -55,6 +53,7 @@ public: class DeviceMap { std::map addr_to_device; + std::shared_ptr logger = spdlog::stdout_color_mt("devicemap"); public: DeviceMap(std::initializer_list devices) { @@ -66,8 +65,8 @@ public: auto it = addr_to_device.upper_bound(addr); if (it == addr_to_device.begin() || (--it)->second->addr + it->second->len <= addr) { - std::cerr << "Use of a unintialized device at memory addr: 0x" << std::hex - << addr << std::dec << std::endl; + logger->error("Accessed an unintialized device at memory addr: 0x{:x}", + addr); return false; } auto &device = it->second; diff --git a/npc/csrc_nvboard/Keyboard/main.cpp b/npc/csrc_nvboard/Keyboard/main.cpp index 8f5ea74..372bbaa 100644 --- a/npc/csrc_nvboard/Keyboard/main.cpp +++ b/npc/csrc_nvboard/Keyboard/main.cpp @@ -49,11 +49,10 @@ int main(int argc, char **argv, char **env) { while (true) { nvboard_update(); cycle(top, [&] { - if (keycode != top->io_ps2_data){ + if (keycode != top->io_ps2_data) { keycode = top->io_ps2_data; printf("%d\n", keycode); - } - }); + }); } delete top; -} \ No newline at end of file + } diff --git a/npc/include/components.hpp b/npc/include/components.hpp index bf16895..cfd05f1 100644 --- a/npc/include/components.hpp +++ b/npc/include/components.hpp @@ -3,23 +3,21 @@ #define _NPC_COMPONENTS_H_ #include "types.h" #include -#include #include #include -#include #include #include #include -#include -#include -#include +#include +#include #include #include -#include template class _RegistersBase { std::array regs; T pc; + std::shared_ptr logger = spdlog::stdout_color_mt("registers"); + virtual T fetch_pc() const; virtual T fetch_reg(std::size_t id) const; @@ -33,12 +31,6 @@ public: } }; -// class MemoryFile { -// std::filesystem::path filepath; -// public: - -// }; - template class Memory { paddr_t pmem_start, pmem_end; @@ -83,15 +75,13 @@ public: template class MemoryMap { std::unique_ptr ram; std::unique_ptr devices; - const std::vector> &trace_ranges; + std::shared_ptr logger = spdlog::stdout_color_mt("mmap"); public: - MemoryMap(std::unique_ptr &&ram, std::unique_ptr &&devices, - const std::vector> &trace_ranges) - : ram(std::move(ram)), devices(std::move(devices)), - trace_ranges(trace_ranges) {} + MemoryMap(std::unique_ptr &&ram, std::unique_ptr &&devices) + : ram(std::move(ram)), devices(std::move(devices)) {} + void write(paddr_t waddr, word_t wdata, char wmask) { - // printf("waddr: 0x%x\n", waddr); size_t len = (wmask & 1) + ((wmask & 2) >> 1) + ((wmask & 4) >> 2) + ((wmask & 8) >> 3); if (ram->in_pmem(waddr)) { @@ -99,47 +89,38 @@ public: } else if (devices->handle(waddr, (uint8_t *)&wdata, len, true)) { } } + word_t read(paddr_t raddr) const { word_t res = 0; - // printf("raddr: 0x%x, in_pmem: %d\n", raddr, ram->in_pmem(raddr)); if (ram->in_pmem(raddr)) { ram->transfer(raddr, (uint8_t *)&res, 4, false); } else if (devices->handle(raddr, (uint8_t *)&res, 4, false)) { } return res; } - void copy_to(paddr_t addr, uint8_t *buf, size_t len) const { + + int copy_to(paddr_t addr, uint8_t *buf, size_t len) const { if (ram->in_pmem(addr)) { ram->transfer(addr, buf, len, false); + return 0; } else { - std::cerr << "0x" << std::hex << addr << " not in pmem" << std::endl; + return EINVAL; } } - void copy_from(paddr_t addr, uint8_t *buf, size_t len) { + + int copy_from(paddr_t addr, uint8_t *buf, size_t len) { if (ram->in_pmem(addr)) { ram->transfer(addr, buf, len, true); + return 0; } else { - std::cerr << "0x" << std::hex << addr << " not in pmem" << std::endl; + return EINVAL; } } + void *get_pmem() { return ram->mem.data(); } + void trace(paddr_t addr, bool is_read, word_t pc = 0, word_t value = 0) { - for (auto &r : trace_ranges) { - if (r[0] <= addr && r[1] >= addr) { - std::stringstream os; - if (pc != 0) - os << "0x" << std::hex << pc << " "; - if (is_read) - os << "[R] " - << "0x" << addr << ": 0x" << this->read(addr); - else - os << "[W] " << value << " -> " - << "0x" << addr; - os << std::dec << std::endl; - std::cout << os.rdbuf(); - break; - } - } + logger->trace("[{}] 0x{:x}", is_read ? 'R' : 'W', this->read(addr)); } }; #endif diff --git a/npc/include/config.hpp b/npc/include/config.hpp index c57ca2e..8c12f31 100644 --- a/npc/include/config.hpp +++ b/npc/include/config.hpp @@ -3,17 +3,14 @@ #include #include #include -#include #include -#include struct Config { std::filesystem::path memory_file; + std::string gdbsocket = "gdbstub-npc.sock"; + bool do_debug{false}; bool interactive{false}; bool memory_file_binary = {true}; - bool do_mtrace{false}; - std::vector> mtrace_ranges{ - {0x80000000, 0x8ffffffff}}; std::filesystem::path wavefile; std::filesystem::path lib_ref; void cli_parse(int argc, char **argv); diff --git a/npc/include/types.h b/npc/include/types.h index e991d8a..fcc14e4 100644 --- a/npc/include/types.h +++ b/npc/include/types.h @@ -1,6 +1,11 @@ #ifndef _NPC_TYPES_H__ #define _NPC_TYPES_H__ +#ifdef __cplusplus +extern "C" { +#endif +#include #include +#include typedef uint32_t word_t; typedef int32_t sword_t; @@ -16,9 +21,19 @@ typedef uint32_t paddr_t; #define FMT_ADDR "0x%08x" typedef uint16_t ioaddr_t; +struct Breakpoint { + size_t addr; + bp_type_t type; +}; + +#ifdef __cplusplus +} +#endif + #ifdef __cplusplus #include #include +#include const std::map riscv32_regs_by_name{ {"$0", 0}, {"ra", 1}, {"sp", 2}, {"gp", 3}, {"tp", 4}, {"t0", 5}, @@ -27,12 +42,10 @@ const std::map riscv32_regs_by_name{ {"s2", 18}, {"s3", 19}, {"s4", 20}, {"s5", 21}, {"s6", 22}, {"s7", 23}, {"s8", 24}, {"s9", 25}, {"s10", 26}, {"s11", 27}, {"t3", 28}, {"t4", 29}, {"t5", 30}, {"t6", 31}}; -#endif -#include -struct Breakpoint { - size_t addr; - bp_type_t type; +struct DbgState { + std::vector *bp; }; +#endif #endif diff --git a/npc/include/vl_wrapper.hpp b/npc/include/vl_wrapper.hpp index 02a6ac5..aa8e798 100644 --- a/npc/include/vl_wrapper.hpp +++ b/npc/include/vl_wrapper.hpp @@ -2,6 +2,7 @@ #define _NPC_TRACER_H_ #include "components.hpp" #include "types.h" +#include "verilated.h" #include #include #include @@ -47,7 +48,7 @@ public: registers = r; } - void eval() { + void eval(void) { if (this->is_posedge()) { posedge_cnt++; } @@ -57,35 +58,34 @@ public: if (tracer) tracer->update(); } - void eval(int n) { - for (int i = 0; i < n; i++) { - this->eval(); + + const Breakpoint *stepi(const std::vector &breakpoints) { + this->eval(); + this->eval(); + size_t pc = registers->get_pc(); + for (const auto &bp : breakpoints) { + if (pc == bp.addr) { + return &bp; + } } + return nullptr; } - gdb_action_t eval(const std::vector &breakpoints) { - gdb_action_t res; + const Breakpoint *cont(const std::vector &breakpoints) { + const Breakpoint *res = nullptr; do { - this->eval(); - size_t pc = registers->get_pc(); - for (const auto &bp : breakpoints) { - if (pc == bp.addr) { - res.data = bp.addr; - switch (bp.type) { - default: - res.reason = gdb_action_t::ACT_BREAKPOINT; - } - return res; - } - } - } while (true); + res = stepi(breakpoints); + } while (res == nullptr); + return res; } void reset_eval(int n) { extern bool g_skip_memcheck; g_skip_memcheck = true; this->reset = 1; - this->eval(n); + do { + this->eval(); + } while (--n); this->reset = 0; g_skip_memcheck = false; } diff --git a/npc/include/vpi_wrapper.hpp b/npc/include/vpi_wrapper.hpp index 4aaaeb8..25f26fb 100644 --- a/npc/include/vpi_wrapper.hpp +++ b/npc/include/vpi_wrapper.hpp @@ -1,12 +1,16 @@ #ifndef _NPC_VPI_WRAPPER_H_ #define _NPC_VPI_WRAPPER_H_ #include +#include +#include +#include #include template class _RegistersVPI : public _RegistersBase { std::array reg_handles; vpiHandle pc_handle; + T vpi_get(vpiHandle vh) const { s_vpi_value v; v.format = vpiIntVal; From de9f770d08e70fbd8c790f36ed9ffde875c7352d Mon Sep 17 00:00:00 2001 From: xinyangli Date: Fri, 2 Aug 2024 11:18:52 +0800 Subject: [PATCH 2/2] npc,refactor: remove original difftest wrapper, cleanup code --- npc/cmake/ChiselBuild.cmake | 41 ++--- npc/core/src/main/scala/components/ALU.scala | 31 ++-- npc/core/src/main/scala/components/Mem.scala | 8 +- npc/csrc/Flow/config.cpp | 3 - npc/include/components.hpp | 67 ++++---- npc/include/config.hpp | 1 - npc/include/trm_difftest.hpp | 102 ------------ npc/include/trm_interface.hpp | 158 ------------------- npc/include/types.h | 15 +- npc/include/vpi_wrapper.hpp | 5 + 10 files changed, 80 insertions(+), 351 deletions(-) delete mode 100644 npc/include/trm_difftest.hpp delete mode 100644 npc/include/trm_interface.hpp diff --git a/npc/cmake/ChiselBuild.cmake b/npc/cmake/ChiselBuild.cmake index 789b476..f446790 100644 --- a/npc/cmake/ChiselBuild.cmake +++ b/npc/cmake/ChiselBuild.cmake @@ -1,20 +1,19 @@ -# -- Add an always run target to generate verilog files with sbt/bloop, -# as we don't know if the result files will be different from cmake -# NOTE: Must reconfigure if we add new files in SCALA_CORE directory +# -- Add an always run target to generate verilog files with sbt/bloop, as we +# don't know if the result files will be different from cmake NOTE: Must +# reconfigure if we add new files in SCALA_CORE directory file(GLOB_RECURSE SCALA_CORE_SOURCES "${SCALA_CORE}/src/main/scala/*.scala") file(GLOB_RECURSE SCALA_CORE_RESOURCES "${SCALA_CORE}/src/main/resources/*") message(STATUS "Found scala source file: ${SCALA_CORE_SOURCES}") -set(CHISEL_DEPENDENCY ${SCALA_CORE_SOURCES} ${SCALA_CORE_RESOURCES} ${SCALA_CORE}/build.sbt) +set(CHISEL_DEPENDENCY ${SCALA_CORE_SOURCES} ${SCALA_CORE_RESOURCES} + ${SCALA_CORE}/build.sbt) if(BUILD_USE_BLOOP) + message(STATUS "Building core using bloop") set(CHISEL_TARGET bloop_${TOPMODULE}) set(CHISEL_TEST_TARGET bloop_${TOPMODULE}_test) # Export sbt build config to bloop if(NOT EXISTS ${SCALA_CORE}/.bloop) - execute_process( - COMMAND sbt bloopInstall - WORKING_DIRECTORY ${SCALA_CORE} - ) + execute_process(COMMAND sbt bloopInstall WORKING_DIRECTORY ${SCALA_CORE}) endif() string(REPLACE " " ";" CHISEL_EMIT_ARGS_LIST ${CHISEL_EMIT_ARGS}) list(TRANSFORM CHISEL_EMIT_ARGS_LIST PREPEND "--args;") @@ -24,14 +23,11 @@ if(BUILD_USE_BLOOP) WORKING_DIRECTORY ${SCALA_CORE} DEPENDS ${CHISEL_DEPENDENCY} COMMAND_EXPAND_LISTS - COMMENT "Run bloop from CMake" - ) -# add_test( -# NAME bloop_${TOPMODULE}_test -# COMMAND bloop test -# WORKING_DIRECTORY ${SCALA_CORE} -# ) + COMMENT "Run bloop from CMake") + # add_test( NAME bloop_${TOPMODULE}_test COMMAND bloop test WORKING_DIRECTORY + # ${SCALA_CORE} ) else() + message(STATUS "Building core using sbt") set(CHISEL_TARGET sbt_${TOPMODULE}) set(CHISEL_TEST_TARGET sbt_${TOPMODULE}_test) add_custom_command( @@ -40,19 +36,16 @@ else() WORKING_DIRECTORY ${SCALA_CORE} DEPENDS ${CHISEL_DEPENDENCY} VERBATIM - COMMENT "Run sbt from CMake" - ) + COMMENT "Run sbt from CMake") add_test( NAME sbt_${TOPMODULE}_test COMMAND sbt test - WORKING_DIRECTORY ${SCALA_CORE} - ) + WORKING_DIRECTORY ${SCALA_CORE}) endif() if(NOT EXISTS ${CHISEL_OUTPUT_TOPMODULE}) - # Probably cold build, generate verilog at configure time to produce top module file - execute_process( - COMMAND sbt "run ${CHISEL_EMIT_ARGS}" - WORKING_DIRECTORY ${SCALA_CORE} - ) + # Probably cold build, generate verilog at configure time to produce top + # module file + execute_process(COMMAND sbt "run ${CHISEL_EMIT_ARGS}" + WORKING_DIRECTORY ${SCALA_CORE}) endif() diff --git a/npc/core/src/main/scala/components/ALU.scala b/npc/core/src/main/scala/components/ALU.scala index 44e9c14..0c1f0ae 100644 --- a/npc/core/src/main/scala/components/ALU.scala +++ b/npc/core/src/main/scala/components/ALU.scala @@ -6,7 +6,8 @@ import shapeless.{HNil, ::} class ALUControlInterface extends Bundle { object OpSelect extends ChiselEnum { - val aOpAdd, aOpSub, aOpNot, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpSltu, aOpSll, aOpSrl, aOpSra = Value + val aOpAdd, aOpSub, aOpNot, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpSltu, aOpSll, + aOpSrl, aOpSra = Value } object SrcASelect extends ChiselEnum { val aSrcARs1, aSrcAPc, aSrcAZero = Value @@ -54,19 +55,21 @@ class ALU[T <: UInt](tpe: T) extends Module { import control.OpSelect._ - out.result := MuxLookup(control.op, 0.U)(Seq( - aOpAdd -> add, - aOpSub -> sub, - aOpNot -> not, - aOpAnd -> and, - aOpOr -> or, - aOpXor -> xor, - aOpSlt -> slt, - aOpSltu -> sltu, - aOpSll -> sll, - aOpSrl -> srl, - aOpSra -> sra.asUInt - )) + out.result := MuxLookup(control.op, 0.U)( + Seq( + aOpAdd -> add, + aOpSub -> sub, + aOpNot -> not, + aOpAnd -> and, + aOpOr -> or, + aOpXor -> xor, + aOpSlt -> slt, + aOpSltu -> sltu, + aOpSll -> sll, + aOpSrl -> srl, + aOpSra -> sra.asUInt + ) + ) } object ALU { diff --git a/npc/core/src/main/scala/components/Mem.scala b/npc/core/src/main/scala/components/Mem.scala index 24f9927..a9d3e22 100644 --- a/npc/core/src/main/scala/components/Mem.scala +++ b/npc/core/src/main/scala/components/Mem.scala @@ -1,13 +1,15 @@ package flow.components import chisel3._ +import chisel3.experimental.noPrefix import chisel3.util.HasBlackBoxPath import chisel3.util.HasBlackBoxResource import chisel3.util.log2Ceil -import chisel3.experimental.noPrefix -import scala.collection.SeqMap import flow.components -import shapeless.{HNil, ::} +import shapeless.:: +import shapeless.HNil + +import scala.collection.SeqMap class RamControlInterface(addrWidth: Int) extends Bundle { val valid = Input(Bool()) diff --git a/npc/csrc/Flow/config.cpp b/npc/csrc/Flow/config.cpp index 035fe24..e8e224b 100644 --- a/npc/csrc/Flow/config.cpp +++ b/npc/csrc/Flow/config.cpp @@ -11,9 +11,6 @@ void Config::cli_parse(int argc, char **argv) { "Memory file is in text format"); app.add_option("--wav", wavefile, "output .vcd file path"); app.add_flag("-i", interactive, "Launch sdb for interactive session"); - app.add_option("--diff-lib", lib_ref, - "Dynamic library file of difftest reference") - ->check(CLI::ExistingFile); try { app.parse(argc, argv); diff --git a/npc/include/components.hpp b/npc/include/components.hpp index cfd05f1..887ded0 100644 --- a/npc/include/components.hpp +++ b/npc/include/components.hpp @@ -14,32 +14,48 @@ #include template class _RegistersBase { - std::array regs; - T pc; std::shared_ptr logger = spdlog::stdout_color_mt("registers"); - virtual T fetch_pc() const; - virtual T fetch_reg(std::size_t id) const; + virtual T fetch_pc() const = 0; + virtual T fetch_reg(std::size_t id) const = 0; public: T operator[](size_t id) const { return fetch_reg(id); } T get_pc() const { return fetch_pc(); } - void update() { - for (int i = 0; i < regs.size(); i++) { - regs[i] = fetch_reg(i); - } - } }; template class Memory { - paddr_t pmem_start, pmem_end; - public: std::array mem; - // TODO: Read memory file before init and use memcpy to initialize memory. + Memory(std::filesystem::path filepath, bool is_binary, paddr_t pmem_start, paddr_t pmem_end) : pmem_start(pmem_start), pmem_end(pmem_end) { + read_memory(filepath, is_binary); + } + + const word_t &operator[](std::size_t addr) { return this->read(addr); } + + void transfer(paddr_t addr, uint8_t data[], size_t len, bool is_write) { + if (is_write) { + // memcpy(guest_to_host(addr), data, len); + size_t offset = (addr - pmem_start); + std::copy(data, data + len, &mem[offset]); + } else { + // memcpy(data, guest_to_host(addr), len); + size_t offset = (addr - pmem_start); + std::copy(&mem[offset], &mem[offset + len], data); + } + } + + bool in_pmem(paddr_t addr) const { + return addr >= pmem_start && addr <= pmem_end; + } + +private: + paddr_t pmem_start, pmem_end; + + void read_memory(std::filesystem::path filepath, bool is_binary) { if (!std::filesystem::exists(filepath)) throw std::runtime_error("Memory file not found"); if (is_binary) { @@ -55,30 +71,12 @@ public: } } } - const word_t &operator[](std::size_t addr) { return this->read(addr); } - void transfer(paddr_t addr, uint8_t data[], size_t len, bool is_write) { - if (is_write) { - // memcpy(guest_to_host(addr), data, len); - size_t offset = (addr - pmem_start); - std::copy(data, data + len, &mem[offset]); - } else { - // memcpy(data, guest_to_host(addr), len); - size_t offset = (addr - pmem_start); - std::copy(&mem[offset], &mem[offset + len], data); - } - } - bool in_pmem(paddr_t addr) const { - return addr >= pmem_start && addr <= pmem_end; - } }; template class MemoryMap { - std::unique_ptr ram; - std::unique_ptr devices; - std::shared_ptr logger = spdlog::stdout_color_mt("mmap"); - public: - MemoryMap(std::unique_ptr &&ram, std::unique_ptr &&devices) + MemoryMap(std::unique_ptr &&ram, + std::unique_ptr &&devices) noexcept : ram(std::move(ram)), devices(std::move(devices)) {} void write(paddr_t waddr, word_t wdata, char wmask) { @@ -122,5 +120,10 @@ public: void trace(paddr_t addr, bool is_read, word_t pc = 0, word_t value = 0) { logger->trace("[{}] 0x{:x}", is_read ? 'R' : 'W', this->read(addr)); } + +private: + std::unique_ptr ram; + std::unique_ptr devices; + std::shared_ptr logger = spdlog::stdout_color_mt("mmap"); }; #endif diff --git a/npc/include/config.hpp b/npc/include/config.hpp index 8c12f31..8d6bf33 100644 --- a/npc/include/config.hpp +++ b/npc/include/config.hpp @@ -12,7 +12,6 @@ struct Config { bool interactive{false}; bool memory_file_binary = {true}; std::filesystem::path wavefile; - std::filesystem::path lib_ref; void cli_parse(int argc, char **argv); }; diff --git a/npc/include/trm_difftest.hpp b/npc/include/trm_difftest.hpp deleted file mode 100644 index ef8bde0..0000000 --- a/npc/include/trm_difftest.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef _DIFFTEST_DIFFTEST_H_ -#define _DIFFTEST_DIFFTEST_H_ -#include "disasm.hpp" -#include "types.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using paddr_t = uint32_t; -struct DifftestTrmInterface : public TrmInterface { - TrmInterface &dut; - TrmInterface &ref; - - DifftestTrmInterface(TrmInterface &dut, TrmInterface &ref, void *mem, - size_t mem_size) - : dut(dut), ref(ref) { - init = [this, mem, mem_size](int n) { - this->ref.init(n); - this->dut.init(n); - paddr_t reset_vector = 0x80000000; - this->ref.memcpy(reset_vector, mem, mem_size, TRM_TO_MACHINE); - this->dut.memcpy(reset_vector, mem, mem_size, TRM_TO_MACHINE); - fetch_state(); - }; - exec = [this](uint64_t 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); - 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 TrmRuntimeException(TrmRuntimeException::DIFFTEST_FAILED, - "Difftest failed"); - } - } - }; - - // NOTE: Different from normal Trm, we copy 2 * sizeof(CPUState) to/from p, - // which represents ref_state and dut state - regcpy = [this](void *p, bool direction) { - // this->ref.regcpy(p, direction); - // this->dut.regcpy(p, direction); - }; - - memcpy = [this](paddr_t paddr, void *p, size_t n, bool direction) { - this->dut.memcpy(paddr, p, n, direction); - this->ref.memcpy(paddr, (uint8_t *)p + n, n, direction); - }; - } - - word_t at(std::string name) const override { - if (name.empty()) { - throw std::runtime_error("Empty register name"); - } else if (name[0] == 'r') { - std::cout << name.substr(1) << std::endl; - this->ref.at(name.substr(1)); - } else if (name[0] == 'd') { - this->dut.at(name.substr(1)); - } else { - throw std::runtime_error("Register name provided to difftest interface " - "must start with r or d."); - } - return 0; - } - - word_t at(paddr_t addr) const override { - std::cout << ref.at(addr) << "\t" << dut.at(addr) << std::endl; - return dut.at(addr); - } - - void print(std::ostream &os) const override { - os << "REF state:\n" - << *(CPUState *)ref.cpu_state << "DUT state:\n" - << *(CPUState *)dut.cpu_state << std::endl; - } -}; -#endif \ No newline at end of file diff --git a/npc/include/trm_interface.hpp b/npc/include/trm_interface.hpp deleted file mode 100644 index 5410820..0000000 --- a/npc/include/trm_interface.hpp +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef _NPC_TRM_INTERFACE_HEADER_FILE_ -#define _NPC_TRM_INTERFACE_HEADER_FILE_ -#include -#include -#include -#include -#include -#include -#include - -extern Disassembler d; - -template struct CPUStateBase { - R reg[nr_reg] = {0}; - word_t pc = 0x80000000; - - static const std::map inline regs_by_name = - riscv32_regs_by_name; - CPUStateBase() { - for (int i = 0; i < nr_reg; i++) - reg[i] = 0; - } - - bool operator==(const CPUStateBase &other) const { - if (pc != other.pc) - return false; - for (int i = 0; i < nr_reg; ++i) { - if (reg[i] != other.reg[i]) - return false; - } - return true; - } - - bool operator!=(const CPUStateBase &other) const { - return !(*this == other); // Reuse the == operator for != implementation - } - - /* This does not update the register!!! */ - R at(std::string name) { - // FIXME: Using this to get pc seems broken - return name == "pc" ? pc : reg[regs_by_name.at(name)]; - } - - uint32_t reg_str2val(const char *name, bool *success) { - try { - *success = true; - return this->at(name); - } catch (std::runtime_error) { - *success = false; - return 0; - } - } -}; - -template -std::ostream &operator<<(std::ostream &os, const CPUStateBase &cpu) { - os << "PC: " << std::hex << cpu.pc << std::endl; - for (int i = 0; i < nr_reg; i++) { - os << "reg " << std::dec << std::setw(2) << i << ":" << std::hex - << std::setw(10) << cpu.reg[i]; - if (i % 4 == 3) { - os << std::endl; - } else { - os << " | "; - } - } - return os; -} - -using CPUState = CPUStateBase; - -enum { TRM_FROM_MACHINE, TRM_TO_MACHINE }; - -class TrmInterface { -protected: - using memcpy_t = void (*)(paddr_t, void *, size_t, bool); - using regcpy_t = void (*)(void *, bool); - using exec_t = void (*)(uint64_t); - using init_t = void (*)(int); - std::function regcpy; - -public: - std::function exec; - std::function init; - // TODO: paddr_t can probably changed to (void *)? - std::function memcpy; - // Managed by callee - void *cpu_state; - - TrmInterface() {} - TrmInterface(memcpy_t f_memcpy, regcpy_t f_regcpy, exec_t f_exec, - init_t f_init, void *cpu_state) - : memcpy(f_memcpy), regcpy(f_regcpy), exec(f_exec), init(f_init), - cpu_state(cpu_state) {} - - void fetch_state() { this->regcpy(cpu_state, TRM_FROM_MACHINE); } - void push_state() { this->regcpy(cpu_state, TRM_TO_MACHINE); } - virtual word_t at(std::string) const = 0; - virtual word_t at(word_t addr) const = 0; - 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); - if (handle == nullptr) { - throw std::runtime_error("Failed to open diff library file"); - }; - memcpy = (memcpy_t)dlsym(handle, "difftest_memcpy"); - if (handle == nullptr) { - throw std::runtime_error("Failed to find `difftest_memcpy`"); - }; - regcpy = (regcpy_t)dlsym(handle, "difftest_regcpy"); - if (handle == nullptr) { - throw std::runtime_error("Failed to find `difftest_regcpy`"); - }; - exec = (exec_t)dlsym(handle, "difftest_exec"); - if (handle == nullptr) { - throw std::runtime_error("Failed to find `difftest_exec`"); - }; - init = (init_t)dlsym(handle, "difftest_init"); - if (handle == nullptr) { - throw std::runtime_error("Failed to find `difftest_init`"); - }; - cpu_state = new CPUState{}; - } - - ~RefTrmInterface() { delete (CPUState *)cpu_state; } - - word_t at(std::string name) const override { - return ((CPUState *)cpu_state)->at(name); - } - - word_t at(paddr_t addr) const override { - word_t buf; - this->memcpy(addr, &buf, sizeof(word_t), TRM_FROM_MACHINE); - return buf; - } - - void print(std::ostream &os) const override { os << *(CPUState *)cpu_state; } -}; - -#endif diff --git a/npc/include/types.h b/npc/include/types.h index fcc14e4..f34f168 100644 --- a/npc/include/types.h +++ b/npc/include/types.h @@ -4,8 +4,7 @@ extern "C" { #endif #include -#include -#include +#include typedef uint32_t word_t; typedef int32_t sword_t; @@ -15,10 +14,8 @@ static const sword_t SWORD_T_MIN = INT32_MIN; #define WORD_BYTES 4 #define REG_COUNT 32 -#define FMT_WORD "0x%08x" typedef uint32_t vaddr_t; typedef uint32_t paddr_t; -#define FMT_ADDR "0x%08x" typedef uint16_t ioaddr_t; struct Breakpoint { @@ -31,18 +28,8 @@ struct Breakpoint { #endif #ifdef __cplusplus -#include -#include #include -const std::map riscv32_regs_by_name{ - {"$0", 0}, {"ra", 1}, {"sp", 2}, {"gp", 3}, {"tp", 4}, {"t0", 5}, - {"t1", 6}, {"t2", 7}, {"s0", 8}, {"s1", 9}, {"a0", 10}, {"a1", 11}, - {"a2", 12}, {"a3", 13}, {"a4", 14}, {"a5", 15}, {"a6", 16}, {"a7", 17}, - {"s2", 18}, {"s3", 19}, {"s4", 20}, {"s5", 21}, {"s6", 22}, {"s7", 23}, - {"s8", 24}, {"s9", 25}, {"s10", 26}, {"s11", 27}, {"t3", 28}, {"t4", 29}, - {"t5", 30}, {"t6", 31}}; - struct DbgState { std::vector *bp; }; diff --git a/npc/include/vpi_wrapper.hpp b/npc/include/vpi_wrapper.hpp index 25f26fb..22b1876 100644 --- a/npc/include/vpi_wrapper.hpp +++ b/npc/include/vpi_wrapper.hpp @@ -23,6 +23,11 @@ class _RegistersVPI : public _RegistersBase { public: _RegistersVPI(const std::string regs_prefix, const std::string pcname) { + init_handlers(regs_prefix, pcname); + } + +private: + void init_handlers(const std::string regs_prefix, const std::string pcname) { for (int i = 0; i < nr; i++) { std::string regname = regs_prefix + std::to_string(i); vpiHandle vh = vpi_handle_by_name((PLI_BYTE8 *)regname.c_str(), nullptr);