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; }