diff --git a/.gitmodules b/.gitmodules index e4ce605..7553118 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,3 @@ path = am-kernels url = https://git.xinyang.life/xin/am-kernels.git branch = dev -[submodule "diffu"] - path = diffu - url = https://git.xinyang.life/xin/diffu.git diff --git a/diffu b/diffu deleted file mode 160000 index 0c590d2..0000000 --- a/diffu +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0c590d218be4b2df4f8f827a9fd40278c227a1ca diff --git a/nemu/src/isa/riscv32/reg.c b/nemu/src/isa/riscv32/reg.c index c15d349..52e6ba0 100644 --- a/nemu/src/isa/riscv32/reg.c +++ b/nemu/src/isa/riscv32/reg.c @@ -14,10 +14,9 @@ ***************************************************************************************/ #include "local-include/reg.h" +#include "gdbstub.h" #include "macro.h" -#include #include -#include #include const char *regs[] = {"$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2", @@ -77,6 +76,6 @@ int isa_write_reg(void *args, int regno, size_t data) { return 0; } -__EXPORT arch_info_t isa_arch_info = {.reg_num = 32, - .reg_byte = MUXDEF(CONFIG_RV64, 8, 4), - .target_desc = TARGET_RV32}; +arch_info_t isa_arch_info = {.reg_num = 33, + .reg_byte = MUXDEF(CONFIG_RV64, 8, 4), + .target_desc = TARGET_RV32}; diff --git a/nemu/src/monitor/filelist.mk b/nemu/src/monitor/filelist.mk index 61231fe..07c4fe5 100644 --- a/nemu/src/monitor/filelist.mk +++ b/nemu/src/monitor/filelist.mk @@ -1,4 +1,3 @@ DIRS-y += src/monitor CXXSRC += src/monitor/gdbstub.cc -LIBS += -lgdbstub diff --git a/nemu/src/monitor/gdbstub.cc b/nemu/src/monitor/gdbstub.cc index 8f2d26c..40aa594 100644 --- a/nemu/src/monitor/gdbstub.cc +++ b/nemu/src/monitor/gdbstub.cc @@ -4,27 +4,27 @@ extern "C" { #include #include -#include #include #include #include #include #include #include +} typedef struct { std::vector *bp; bool halt; } DbgState; -__EXPORT int nemu_read_mem(void *args, size_t addr, size_t len, void *val) { +int nemu_read_mem(void *args, size_t addr, size_t len, void *val) { if (!in_pmem(addr)) return EINVAL; memcpy(val, guest_to_host(addr), len); return 0; } -__EXPORT int nemu_write_mem(void *args, size_t addr, size_t len, void *val) { +int nemu_write_mem(void *args, size_t addr, size_t len, void *val) { if (!in_pmem(addr)) return EINVAL; memcpy(guest_to_host(addr), val, len); @@ -35,25 +35,21 @@ static void nemu_is_stopped(gdb_action_t *act, breakpoint_t *stopped_at) { switch (nemu_state.state) { case NEMU_RUNNING: nemu_state.state = NEMU_STOP; - if (stopped_at == NULL) { - act->reason = gdb_action_t::ACT_NONE; - } else { - switch (stopped_at->type) { - case BP_SOFTWARE: - act->reason = gdb_action_t::ACT_BREAKPOINT; - break; - case BP_ACCESS: - act->reason = gdb_action_t::ACT_WATCH; - break; - case BP_WRITE: - act->reason = gdb_action_t::ACT_WWATCH; - break; - case BP_READ: - act->reason = gdb_action_t::ACT_RWATCH; - break; - } - act->data = stopped_at->addr; + switch (stopped_at->type) { + case BP_SOFTWARE: + act->reason = gdb_action_t::ACT_BREAKPOINT; + break; + case BP_ACCESS: + act->reason = gdb_action_t::ACT_WATCH; + break; + case BP_WRITE: + act->reason = gdb_action_t::ACT_WWATCH; + break; + case BP_READ: + act->reason = gdb_action_t::ACT_RWATCH; + break; } + act->data = stopped_at->addr; break; default: @@ -62,21 +58,21 @@ static void nemu_is_stopped(gdb_action_t *act, breakpoint_t *stopped_at) { } } -__EXPORT void nemu_cont(void *args, gdb_action_t *res) { +void nemu_cont(void *args, gdb_action_t *res) { DbgState *dbg_state = (DbgState *)args; breakpoint_t *stopped_at = cpu_exec_with_bp(-1, dbg_state->bp->data(), dbg_state->bp->size()); nemu_is_stopped(res, stopped_at); } -__EXPORT void nemu_stepi(void *args, gdb_action_t *res) { +void nemu_stepi(void *args, gdb_action_t *res) { DbgState *dbg_state = (DbgState *)args; breakpoint_t *stopped_at = cpu_exec_with_bp(1, dbg_state->bp->data(), dbg_state->bp->size()); nemu_is_stopped(res, stopped_at); } -__EXPORT bool nemu_set_bp(void *args, size_t addr, bp_type_t type) { +bool nemu_set_bp(void *args, size_t addr, bp_type_t type) { DbgState *dbg_state = (DbgState *)args; for (const auto &bp : *dbg_state->bp) { if (bp.addr == addr && bp.type == type) { @@ -87,7 +83,7 @@ __EXPORT bool nemu_set_bp(void *args, size_t addr, bp_type_t type) { return true; } -__EXPORT bool nemu_del_bp(void *args, size_t addr, bp_type_t type) { +bool nemu_del_bp(void *args, size_t addr, bp_type_t type) { DbgState *dbg_state = (DbgState *)args; for (auto it = dbg_state->bp->begin(); it != dbg_state->bp->end(); it++) { if (it->addr == addr && it->type == type) { @@ -99,44 +95,24 @@ __EXPORT bool nemu_del_bp(void *args, size_t addr, bp_type_t type) { return false; } -__EXPORT void nemu_on_interrupt(void *args) { +void nemu_on_interrupt(void *args) { // fputs("Not implemented", stderr); } -__EXPORT int nemu_read_reg(void *args, int regno, size_t *data) { - return isa_read_reg(args, regno, data); -} -__EXPORT int nemu_write_reg(void *args, int regno, size_t data) { - return isa_write_reg(args, regno, data); -} -__EXPORT size_t argsize = sizeof(DbgState); - static struct target_ops nemu_gdbstub_ops = {.cont = nemu_cont, .stepi = nemu_stepi, - .read_reg = nemu_read_reg, - .write_reg = nemu_write_reg, + .read_reg = isa_read_reg, + .write_reg = isa_write_reg, .read_mem = nemu_read_mem, .write_mem = nemu_write_mem, .set_bp = nemu_set_bp, .del_bp = nemu_del_bp, .on_interrupt = NULL}; static DbgState dbg; +extern "C" { static gdbstub_t gdbstub_priv; #define SOCKET_ADDR "127.0.0.1:1234" - -__EXPORT void nemu_init(void *args) { - DbgState *dbg_state = (DbgState *)args; - dbg_state->bp = new std::vector(); - dbg_state->halt = 0; - Assert(dbg_state->bp != NULL, "Failed to allocate breakpoint"); - - void init_mem(); - init_mem(); - /* Perform ISA dependent initialization. */ - init_isa(); -} - -__EXPORT int nemu_gdbstub_init() { +int nemu_gdbstub_init() { dbg.bp = new std::vector(); assert(dbg.bp); if (!gdbstub_init(&gdbstub_priv, &nemu_gdbstub_ops, @@ -145,8 +121,7 @@ __EXPORT int nemu_gdbstub_init() { } return 0; } - -__EXPORT int nemu_gdbstub_run() { +int nemu_gdbstub_run() { puts("Waiting for gdb connection at " SOCKET_ADDR); bool success = gdbstub_run(&gdbstub_priv, &dbg); gdbstub_close(&gdbstub_priv); diff --git a/nemu/src/monitor/monitor.c b/nemu/src/monitor/monitor.c index 264d463..b9b343e 100644 --- a/nemu/src/monitor/monitor.c +++ b/nemu/src/monitor/monitor.c @@ -25,7 +25,7 @@ void init_mem(); void init_difftest(char *ref_so_file, long img_size, int port); void init_device(); void init_disasm(const char *triple); -void nemu_init(); +int nemu_gdbstub_init(); static void welcome() { Log("Trace: %s", MUXDEF(CONFIG_TRACE, ANSI_FMT("ON", ANSI_FG_GREEN), @@ -60,8 +60,7 @@ static long load_img() { // Image file is searched from paths in environment variable NEMU_IMAGES_PATH if it's a relative path if (img_file[0] != '/') { char *search_paths = getenv("NEMU_IMAGES_PATH"); - if (search_paths == NULL) - search_paths = "./"; + if(search_paths == NULL) search_paths = "./"; search_paths = strdup(search_paths); Trace("NEMU_IMAGES_PATH=%s", search_paths); @@ -69,10 +68,8 @@ static long load_img() { char *p_start = search_paths; do { char *p = strchr(p_start, ':'); - if (p != NULL) - *p = '\0'; - else - p = paths_end; + if (p != NULL) *p = '\0'; + else p = paths_end; char *file_path = malloc(p - p_start + img_filename_len + 2); strcpy(file_path, p_start); @@ -89,7 +86,7 @@ static long load_img() { Assert(fp != NULL || errno == ENOENT, "Cannot open '%s'", img_file); p_start = p + 1; - } while (p_start < paths_end); + } while(p_start < paths_end); free(search_paths); Assert(fp, "Cannot find '%s'", img_file); @@ -181,11 +178,10 @@ void init_monitor(int argc, char *argv[]) { init_difftest(diff_so_file, img_size, difftest_port); /* Initialize debugger */ - // if (nemu_init()) { - // Error("Failed to init"); - // exit(1); - // } - nemu_init(); + if (nemu_gdbstub_init()) { + Error("Failed to init"); + exit(1); + } // printf("elf_file: %s\n", elf_file); if (elf_file != NULL) { diff --git a/npc/.envrc b/npc/.envrc index beaa935..3f3af37 100644 --- a/npc/.envrc +++ b/npc/.envrc @@ -1 +1 @@ -use flake ".?submodules=1#npc" +use flake ..#npc diff --git a/npc/CMakeLists.txt b/npc/CMakeLists.txt index 4b4424e..035d603 100644 --- a/npc/CMakeLists.txt +++ b/npc/CMakeLists.txt @@ -42,7 +42,7 @@ if(BUILD_SIM_NVBOARD_TARGET) endif() find_package(CLI11 CONFIG REQUIRED) -option(ENABLE_SDB "Enable simple debugger" OFF) +option(ENABLE_SDB "Enable simple debugger" ON) find_library(NVBOARD_LIBRARY NAMES nvboard) find_path(NVBOARD_INCLUDE_DIR NAMES nvboard.h) diff --git a/npc/csrc/Flow/CMakeLists.txt b/npc/csrc/Flow/CMakeLists.txt index f945f7a..5ea7fce 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) +target_link_libraries(V${TOPMODULE} PRIVATE sdb devices) target_include_directories(V${TOPMODULE} PRIVATE ${CMAKE_SOURCE_DIR}/include) verilate( diff --git a/npc/csrc/Flow/main.cpp b/npc/csrc/Flow/main.cpp index 591ebc8..324156f 100644 --- a/npc/csrc/Flow/main.cpp +++ b/npc/csrc/Flow/main.cpp @@ -1,25 +1,30 @@ -extern "C" { -#include -} #include "VFlow___024root.h" #include "components.hpp" #include +#include #include #include #include #include +#include +#include +#include #include +#include +#include +#include #include -#include #include #include #include +using VlModule = VlModuleInterfaceCommon; using Registers = _RegistersVPI; -using VlModule = VlModuleInterfaceCommon; // SDB::SDB sdb_dut; +using CPUState = CPUStateBase; bool g_skip_memcheck = false; +CPUState npc_cpu; VlModule *top; Registers *regs; vpiHandle pc = nullptr; @@ -27,13 +32,7 @@ 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{ @@ -66,99 +65,127 @@ void pmem_write(int waddr, int wdata, char wmask) { 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; -} +namespace NPC { +void npc_memcpy(paddr_t addr, void *buf, size_t sz, bool direction) { + if (direction == TRM_FROM_MACHINE) { + static_cast(pmem_get())->copy_to(addr, (uint8_t *)buf, sz); + } +}; -int npc_read_reg(void *args, int regno, size_t *value) { - if (regno == 32) - *value = regs->get_pc(); - else - *value = (*regs)[regno]; - return 0; -} +void npc_regcpy(void *p, bool direction) { -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; + if (direction == TRM_FROM_MACHINE) { + ((CPUState *)p)->pc = regs->get_pc(); + for (int i = 0; i < 32; i++) { + ((CPUState *)p)->reg[i] = (*regs)[i]; } } - 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; +void npc_exec(uint64_t n) { + while (n--) { + for (int i = 0; i < 2; i++) { + if (top->is_posedge()) { + // Posedge + regs->update(); + } + top->eval(); } } - return false; } -static 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}; +void npc_atexit(void) { + delete top; + delete regs; +} -static gdbstub_t gdbstub_priv; -static DbgState dbg; -arch_info_t isa_arch_info = { - .target_desc = strdup(TARGET_RV32), .reg_num = 33, .reg_byte = 4}; +void npc_init(int port) { + top = new VlModule{config.wavefile}; + regs = new Registers("TOP.Flow.reg_0.regFile_", "TOP.Flow.pc.out"); + atexit(npc_atexit); + top->reset_eval(10); +} -int gdbstub_loop() { - if (!gdbstub_init(&gdbstub_priv, &npc_gdbstub_ops, (arch_info_t)isa_arch_info, - strdup("127.0.0.1:1234"))) { - return EINVAL; +class DutTrmInterface : public TrmInterface { +public: + DutTrmInterface(memcpy_t f_memcpy, regcpy_t f_regcpy, exec_t f_exec, + init_t f_init, void *cpu_state) + : TrmInterface{f_memcpy, f_regcpy, f_exec, f_init, cpu_state} {} + word_t at(std::string name) const override { + return ((CPUState *)cpu_state)->at(name); } - bool success = gdbstub_run(&gdbstub_priv, &dbg); - gdbstub_close(&gdbstub_priv); - return !success; + + 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 { + this->regcpy(cpu_state, TRM_FROM_MACHINE); + os << *(CPUState *)cpu_state << std::endl; + } +}; + +DutTrmInterface npc_interface = + DutTrmInterface{&npc_memcpy, &npc_regcpy, &npc_exec, &npc_init, &npc_cpu}; +}; // namespace NPC + +extern "C" { +word_t reg_str2val(const char *name, bool *success) { + return npc_cpu.reg_str2val(name, success); +} } -} // extern "C" int main(int argc, char **argv, char **env) { config.cli_parse(argc, argv); - top = new VlModule; - regs = new Registers("TOP.Flow.reg_0.regFile_", "TOP.Flow.pc.out"); - top->setup(config.wavefile, regs); - top->reset_eval(10); + if (config.lib_ref.empty()) { + if (config.interactive) { + SDB::SDB sdb_npc{NPC::npc_interface}; + sdb_npc.main_loop(); + return 0; + } else { + NPC::npc_interface.init(0); + while (true) { + word_t inst = NPC::npc_interface.at(regs->get_pc()); + if (inst == 1048691) { + return 0; + } + NPC::npc_interface.exec(1); + } + } + } - return gdbstub_loop(); + /* -- Difftest -- */ + std::filesystem::path ref{config.lib_ref}; + RefTrmInterface ref_interface{ref}; + DifftestTrmInterface diff_interface{ + NPC::npc_interface, ref_interface, + static_cast(pmem_get())->get_pmem(), 128 * 1024}; + if (config.interactive) { + SDB::SDB sdb_diff{diff_interface}; + sdb_diff.main_loop(); + return 0; + } + + try { + diff_interface.init(0); + diff_interface.exec(-1); + } catch (TrmRuntimeException &e) { + switch (e.error_code()) { + case TrmRuntimeException::EBREAK: + return 0; + case TrmRuntimeException::DIFFTEST_FAILED: + std::cout << "Difftest Failed" << std::endl; + diff_interface.print(std::cout); + return 1; + default: + std::cerr << "Unknown error happened" << std::endl; + return 1; + } + } + + return 0; } diff --git a/npc/include/components.hpp b/npc/include/components.hpp index bf16895..ca86156 100644 --- a/npc/include/components.hpp +++ b/npc/include/components.hpp @@ -20,12 +20,12 @@ template class _RegistersBase { std::array regs; T pc; - virtual T fetch_pc() const; - virtual T fetch_reg(std::size_t id) const; + virtual T fetch_pc(); + virtual T fetch_reg(std::size_t id); public: - T operator[](size_t id) const { return fetch_reg(id); } - T get_pc() const { return fetch_pc(); } + T operator[](size_t id) { return fetch_reg(id); } + T get_pc() { return fetch_pc(); } void update() { for (int i = 0; i < regs.size(); i++) { regs[i] = fetch_reg(i); @@ -112,14 +112,14 @@ public: if (ram->in_pmem(addr)) { ram->transfer(addr, buf, len, false); } else { - std::cerr << "0x" << std::hex << addr << " not in pmem" << std::endl; + std::cerr << "Not in pmem" << std::endl; } } - void copy_from(paddr_t addr, uint8_t *buf, size_t len) { + void copy_from(paddr_t addr, const uint8_t *buf, size_t len) { if (ram->in_pmem(addr)) { ram->transfer(addr, buf, len, true); } else { - std::cerr << "0x" << std::hex << addr << " not in pmem" << std::endl; + std::cerr << "Not in pmem" << std::endl; } } void *get_pmem() { return ram->mem.data(); } diff --git a/npc/include/types.h b/npc/include/types.h index e991d8a..6f78cc1 100644 --- a/npc/include/types.h +++ b/npc/include/types.h @@ -29,10 +29,4 @@ const std::map riscv32_regs_by_name{ {"t5", 30}, {"t6", 31}}; #endif -#include -struct Breakpoint { - size_t addr; - bp_type_t type; -}; - -#endif +#endif \ No newline at end of file diff --git a/npc/include/vl_wrapper.hpp b/npc/include/vl_wrapper.hpp index 02a6ac5..61414c4 100644 --- a/npc/include/vl_wrapper.hpp +++ b/npc/include/vl_wrapper.hpp @@ -1,10 +1,7 @@ #ifndef _NPC_TRACER_H_ #define _NPC_TRACER_H_ #include "components.hpp" -#include "types.h" #include -#include -#include #include template class Tracer { @@ -29,24 +26,16 @@ public: void update() { m_trace->dump(cycle++); } }; -template class VlModuleInterfaceCommon : public T { +template class VlModuleInterfaceCommon : public T { uint64_t sim_time = 0; uint64_t posedge_cnt = 0; std::unique_ptr> tracer; public: - const R *registers; - VlModuleInterfaceCommon() { - tracer = nullptr; - registers = nullptr; - } - - void setup(std::filesystem::path wavefile, const R *r) { + VlModuleInterfaceCommon(std::filesystem::path wavefile) { if (!wavefile.empty()) tracer = std::make_unique>(this, wavefile); - registers = r; } - void eval() { if (this->is_posedge()) { posedge_cnt++; @@ -62,25 +51,6 @@ public: this->eval(); } } - - gdb_action_t eval(const std::vector &breakpoints) { - gdb_action_t res; - 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); - } - void reset_eval(int n) { extern bool g_skip_memcheck; g_skip_memcheck = true; diff --git a/npc/include/vpi_wrapper.hpp b/npc/include/vpi_wrapper.hpp index 4aaaeb8..a1dd089 100644 --- a/npc/include/vpi_wrapper.hpp +++ b/npc/include/vpi_wrapper.hpp @@ -7,14 +7,14 @@ template class _RegistersVPI : public _RegistersBase { std::array reg_handles; vpiHandle pc_handle; - T vpi_get(vpiHandle vh) const { + T vpi_get(vpiHandle vh) { s_vpi_value v; v.format = vpiIntVal; vpi_get_value(vh, &v); return v.value.integer; } - T fetch_pc(void) const { return vpi_get(pc_handle); } - T fetch_reg(std::size_t id) const { return vpi_get(reg_handles[id]); } + T fetch_pc(void) { return vpi_get(pc_handle); } + T fetch_reg(std::size_t id) { return vpi_get(reg_handles[id]); } public: _RegistersVPI(const std::string regs_prefix,