diff --git a/sim/atomsim.cpp b/sim/atomsim.cpp index 2445c37b..c886c3f7 100755 --- a/sim/atomsim.cpp +++ b/sim/atomsim.cpp @@ -1,5 +1,4 @@ #include "atomsim.hpp" -#include "simstate.hpp" #include #include "util.hpp" @@ -57,14 +56,11 @@ int Atomsim::run() // *** Simulation Loop *** while (bkend_running_) { - // Refresh state - backend_.refresh_state(); - int breakpoint_hit = -1; // Evaluate breakpoints (early) for(int i=0; i sim_config_.maxitr) { + if(backend_.get_total_tick_count() > sim_config_.maxitr) { throwError("SIM0", "Simulation iterations exceeded maxitr("+std::to_string(sim_config_.maxitr)+")\n"); exitcode = EXIT_FAILURE; break; diff --git a/sim/atomsim.hpp b/sim/atomsim.hpp index 9640d732..f31fe1d3 100755 --- a/sim/atomsim.hpp +++ b/sim/atomsim.hpp @@ -5,7 +5,6 @@ // #include #include TARGET_HEADER -#include "simstate.hpp" enum Rcode{ RC_NONE, RC_OK, RC_STEP, RC_RUN, RC_EXIT @@ -77,11 +76,6 @@ class Atomsim * @brief Backend object */ Backend_atomsim backend_; - - /** - * @brief Middle-end object (cached state of backend) - */ - Simstate simstate_; /** * @brief tracks if the VCD trace is opened @@ -100,16 +94,6 @@ class Atomsim */ std::map disassembly_; - /** - * @brief Register ABI names used in debug display - */ - const std::vector reg_names_ = - { - "x0 (zero) ", "x1 (ra) ", "x2 (sp) ", "x3 (gp) ", "x4 (tp) ", "x5 (t0) ", "x6 (t1) ", "x7 (t2) ", - "x8 (s0/fp)", "x9 (s1) ", "x10 (a0) ", "x11 (a1) ", "x12 (a2) ", "x13 (a3) ", "x14 (a4) ", "x15 (a5) ", - "x16 (a6) ", "x17 (a7) ", "x18 (s2) ", "x19 (s3) ", "x20 (s4) ", "x21 (s5) ", "x22 (s6) ", "x23 (s7) ", - "x24 (s8) ", "x25 (s9) ", "x26 (s10) ", "x27 (s11) ", "x28 (t3) ", "x29 (t4) ", "x30 (t5) ", "x31 (t6) " - }; friend class Backend_atomsim; diff --git a/sim/backend.hpp b/sim/backend.hpp index 32815375..b1b64c7c 100644 --- a/sim/backend.hpp +++ b/sim/backend.hpp @@ -6,10 +6,23 @@ #include +enum Regwidth_t { + R8=8, + R16=16, + R32=32, + R64=64 +}; + +struct ArchReg_t { + std::string name; + std::string alt_name; + Regwidth_t width; + void * ptr; + bool is_arch_reg; +}; // Forward declaration class Atomsim; -class Simstate; /** * @brief Backend class @@ -27,7 +40,7 @@ class Backend { public: - Backend(Atomsim *sim_ptr, Simstate *simstate_ptr); + Backend(Atomsim *sim_ptr); /** * @brief Get the Target Name [** OVERRIDE **] @@ -40,12 +53,6 @@ class Backend */ void reset(); - /** - * @brief probe all internal signals and registers and - * update state of middle-end [** OVERRIDE **] - */ - virtual void refresh_state() = 0; - /** * @brief Tick for one cycle */ @@ -100,39 +107,51 @@ class Backend */ virtual void store(const uint32_t start_addr, uint8_t *buf, const uint32_t buf_sz); + /** + * @brief read register value [** MAY OVERRIDE **] + * + * @param reg_id register ID + */ + virtual uint64_t read_reg(const std::string name); + + /** + * @brief write register value [** MAY OVERRIDE **] + * + * @param reg_id register ID + * @param buf value + */ + virtual void write_reg(const std::string name, uint64_t value); + protected: /** * @brief Pointer to Atomsim object */ Atomsim *sim_; - /** - * @brief Pointer to middle-end - */ - Simstate *simstate_; - /** * @brief Pointer to testbench object * NOTE: To be initialized and deleted by child class */ Testbench *tb; + + /** + * @brief Map or architectural registers + */ + std::vector regs_; + + friend class Atomsim; }; template -Backend::Backend(Atomsim *sim_ptr, Simstate *simstate_ptr): - sim_(sim_ptr), - simstate_(simstate_ptr) +Backend::Backend(Atomsim *sim_ptr): + sim_(sim_ptr) {} template void Backend::reset() { tb->reset(); - // tb->m_core->eval(); - - // Update simstate - refresh_state(); } template @@ -185,4 +204,50 @@ template void Backend::store(const uint32_t /*start_addr*/, uint8_t */*buf*/, const uint32_t /*buf_sz*/) { throw Atomsim_exception("storing to current target's memory is not supported"); +} + +template +uint64_t Backend::read_reg(const std::string name) +{ + if (regs_.size() == 0) + throw Atomsim_exception("Reading register value in current target is not supported"); + + uint64_t val; + for(auto it = regs_.begin(); it != regs_.end(); it++){ + if(it->name == name || it->alt_name == name) { + switch(it->width){ + case R8: val = *((uint64_t*)it->ptr) & 0xffULL; break; + case R16: val = *((uint64_t*)it->ptr) & 0xffffULL; break; + case R32: val = *((uint64_t*)it->ptr) & 0xffffffffULL; break; + case R64: + default: + val = *((uint64_t*)it->ptr); break; + } + return val; + } + } + + throw Atomsim_exception("Invalid register: " + name); +} + +template +void Backend::write_reg(const std::string name, uint64_t value) +{ + if (regs_.size() == 0) + throw Atomsim_exception("W`riting register value in current target is not supported"); + + for(auto it = regs_.begin(); it != regs_.end(); it++){ + if(it->name == name || it->alt_name == name) { + switch(it->width){ + case R8: *((uint8_t*)it->ptr) = (uint8_t) (value & 0xffULL); break; + case R16: *((uint16_t*)it->ptr) = (uint16_t) (value & 0xffffULL); break; + case R32: *((uint32_t*)it->ptr) = (uint32_t) (value & 0xffffffffULL); break; + case R64: + default: + *((uint64_t*)it->ptr) = value; break; + } + } + } + + throw Atomsim_exception("Invalid register: " + name); } \ No newline at end of file diff --git a/sim/backend_atombones.cpp b/sim/backend_atombones.cpp index 564a9268..aa34913e 100755 --- a/sim/backend_atombones.cpp +++ b/sim/backend_atombones.cpp @@ -1,12 +1,11 @@ #include "backend_atombones.hpp" #include "atomsim.hpp" -#include "simstate.hpp" -// #include "testbench.hpp" #include "memory.hpp" #include "vuart.hpp" #include "except.hpp" #include "util.hpp" +#include "rvdefs.hpp" #include "build/verilated/VAtomBones_headers.h" @@ -14,10 +13,8 @@ #define UART_ADDR 0x40000000 - - Backend_atomsim::Backend_atomsim(Atomsim * sim, Backend_config config): - Backend(sim, &(sim->simstate_)), + Backend(sim), config_(config), using_vuart_(config.vuart_portname != "") { @@ -34,7 +31,14 @@ Backend_atomsim::Backend_atomsim(Atomsim * sim, Backend_config config): { std::cerr << e.what() << '\n'; } - + + // Construct reg map + regs_.push_back({.name="pc", .alt_name="", .width=R32, .ptr=(void *)&tb->m_core->AtomBones->atom_core->ProgramCounter_Old, .is_arch_reg=false}); + regs_.push_back({.name="ir", .alt_name="", .width=R32, .ptr=(void *)&tb->m_core->AtomBones->atom_core->InstructionRegister, .is_arch_reg=false}); + for (int i=0; i<32; i++) { + std::string regname = "x"+std::to_string(i); + regs_.push_back({.name=regname, .alt_name=rv_abi_regnames[i], .width=R32, .ptr=(void *)&tb->m_core->AtomBones->atom_core->rf->regs[i], .is_arch_reg=true}); + } // ====== Initialize ======== // Initialize memory @@ -163,30 +167,6 @@ void Backend_atomsim::service_mem_req() } -void Backend_atomsim::refresh_state() -{ - // Get PC - simstate_->state_.pc_f = tb->m_core->AtomBones->atom_core->ProgramCounter; - simstate_->state_.pc_e = tb->m_core->AtomBones->atom_core->ProgramCounter_Old; - - // Get IR - simstate_->state_.ins_e = tb->m_core->AtomBones->atom_core->InstructionRegister; - - // Get Regs - for(int i=0; i<32; i++) - { - simstate_->state_.rf[i] = tb->m_core->AtomBones->atom_core->rf->regs[i]; - } - - // Get Signals - simstate_->signals_.jump_decision = tb->m_core->AtomBones->atom_core->__PVT__jump_decision; - - // get Tickcounts - simstate_->state_.tickcount = tb->m_tickcount; - simstate_->state_.tickcount_total = tb->m_tickcount_total; -} - - int Backend_atomsim::tick() { // return if backend finished diff --git a/sim/backend_atombones.hpp b/sim/backend_atombones.hpp index 880ab334..e9658cb0 100755 --- a/sim/backend_atombones.hpp +++ b/sim/backend_atombones.hpp @@ -52,8 +52,6 @@ class Backend_atomsim: public Backend */ void service_mem_req(); - void refresh_state(); - void UART(); int tick(); diff --git a/sim/backend_hydrogensoc.cpp b/sim/backend_hydrogensoc.cpp index de75e602..90afe72c 100644 --- a/sim/backend_hydrogensoc.cpp +++ b/sim/backend_hydrogensoc.cpp @@ -1,13 +1,11 @@ #include "backend_hydrogensoc.hpp" #include "atomsim.hpp" -#include "simstate.hpp" -// #include "testbench.hpp" #include "memory.hpp" #include "vuart.hpp" #include "bitbang_uart.hpp" #include "except.hpp" -// #include "util.hpp" +#include "rvdefs.hpp" #include "build/verilated/VHydrogenSoC_headers.h" @@ -28,10 +26,10 @@ #define RAM_SIZE 49152 // 48 KB #define BBUART_FRATIO 3 - #define BOOTMODE_PIN_OFFSET 8 -Backend_atomsim::Backend_atomsim(Atomsim *sim, Backend_config config) : Backend(sim, &(sim->simstate_)), + +Backend_atomsim::Backend_atomsim(Atomsim *sim, Backend_config config) : Backend(sim), config_(config), using_vuart_(config.vuart_portname != "") { @@ -57,6 +55,14 @@ Backend_atomsim::Backend_atomsim(Atomsim *sim, Backend_config config) : Backend( // Construct Testbench object tb = new Testbench(); + // Construct reg map + regs_.push_back({.name="pc", .alt_name="", .width=R32, .ptr=(void *)&tb->m_core->HydrogenSoC->atom_wb_core->atom_core->ProgramCounter_Old, .is_arch_reg=false}); + regs_.push_back({.name="ir", .alt_name="", .width=R32, .ptr=(void *)&tb->m_core->HydrogenSoC->atom_wb_core->atom_core->InstructionRegister, .is_arch_reg=false}); + for (int i=0; i<32; i++) { + std::string regname = "x"+std::to_string(i); + regs_.push_back({.name=regname, .alt_name=rv_abi_regnames[i], .width=R32, .ptr=(void *)&tb->m_core->HydrogenSoC->atom_wb_core->atom_core->rf->regs[i], .is_arch_reg=true}); + } + // ====== Initialize ======== // init ram if(sim_->sim_config_.verbose_flag) @@ -106,26 +112,6 @@ Backend_atomsim::~Backend_atomsim() delete tb; } -void Backend_atomsim::refresh_state() -{ - // Get PC - simstate_->state_.pc_f = tb->m_core->HydrogenSoC->atom_wb_core->atom_core->ProgramCounter; - simstate_->state_.pc_e = tb->m_core->HydrogenSoC->atom_wb_core->atom_core->ProgramCounter_Old; - - // Get IR - simstate_->state_.ins_e = tb->m_core->HydrogenSoC->atom_wb_core->atom_core->InstructionRegister; - - // Get Regs - for (int i = 0; i < 32; i++) - simstate_->state_.rf[i] = tb->m_core->HydrogenSoC->atom_wb_core->atom_core->rf->regs[i]; - - // Get Signals - simstate_->signals_.jump_decision = tb->m_core->HydrogenSoC->atom_wb_core->atom_core->__PVT__jump_decision; - - // get Tickcounts - simstate_->state_.tickcount = tb->m_tickcount; - simstate_->state_.tickcount_total = tb->m_tickcount_total; -} void Backend_atomsim::UART() { diff --git a/sim/interactive.cpp b/sim/interactive.cpp index cf1550b4..1b2d2f81 100755 --- a/sim/interactive.cpp +++ b/sim/interactive.cpp @@ -20,61 +20,51 @@ #define ATOMSIM_HISTORY_FILE ".atomsim_history" #define ATOMSIM_HISTORY_LENGTH 1000 +#define DEBUG_SCREEN_RF_COLS 2 void Atomsim::display_dbg_screen() -{ // calculate change in PC. - unsigned int pc_change = simstate_.state_.pc_f - simstate_.state_.pc_e; - - // Check if it's a jump - bool isJump = simstate_.signals_.jump_decision; - - // Fetch Values +{ uint64_t tickcount = backend_.get_total_tick_count(); + uint64_t pc = backend_.read_reg("pc"); + uint64_t ir = backend_.read_reg("ir"); - const int disam_width = 39; - std::string disam = (disassembly_[simstate_.state_.pc_e].instr == simstate_.state_.ins_e) ? disassembly_[simstate_.state_.pc_e].disassembly : "_"; - if(disam.length() > disam_width) { - disam.resize(disam_width-3); - disam += " .."; - } - else if (disam.length()< disam_width) - disam.append(disam_width-disam.length(), ' '); - - ////////////////////////////////////////////////////////////////////////////////////////// - // Print debug screen + std::string disasm = trimstr((disassembly_[pc].instr == ir) ? disassembly_[pc].disassembly : "_", 40); + + //////////////////////////////////////////////////////////////////////////// + // Non verbose debug screen if(!sim_config_.verbose_flag){ - printf("[%10ld] PC: 0x%08x, IR: 0x%08x, %s%s%s\n", tickcount, simstate_.state_.pc_e, simstate_.state_.ins_e, ansicode(FG_BLUE), disam.c_str(), ansicode(FG_RESET)); + printf("[%10ld] PC: 0x%08lx, IR: 0x%08lx, %s%s%s\n", tickcount, pc, ir, ansicode(FG_BLUE), disasm.c_str(), ansicode(FG_RESET)); return; } - + + //////////////////////////////////////////////////////////////////////////// + // Verbose debug screen + static uint64_t last_pc = 0; + int64_t pc_change = pc - last_pc; + last_pc = pc; + printf("┌─[%10ld]─────────────────────────────────────────────┐\n", tickcount); - printf("│ %sPC: 0x%08x%s%s PC_f: 0x%08x (%+10d%s)%s │\n", ansicode(S_BOLD), simstate_.state_.pc_e, ansicode(SN_BOLD), - ansicode(S_DIM), simstate_.state_.pc_f, pc_change, (isJump ? ", J": " "), ansicode(SN_DIM)); - printf("│ IR: 0x%08x %s%s%s│\n", simstate_.state_.ins_e, ansicode(FG_CYAN), disam.c_str(), ansicode(FG_RESET)); + printf("│ %sPC: 0x%08lx%s %s%-+15ld%s │\n", ansicode(S_BOLD), pc, ansicode(SN_BOLD), + ansicode(S_DIM), pc_change, ansicode(SN_DIM)); + printf("│ IR: 0x%08lx %s%s%s │\n", ir, ansicode(FG_CYAN), disasm.c_str(), ansicode(FG_RESET)); printf("└──────────────────────────────────────────────────────────┘\n"); - // Print Register File - int cols = 2; // no of columns per rows - #ifndef DEBUG_PRINT_T2B - for(int i=0; i<32; i++) // print in left-right fashion - { - printf("r%-2d: 0x%08x ", i, simstate_.state_.rf[i]); - if(i%cols == cols-1) - printf("\n"); - } - #else - for(int i=0; i<32/cols; i++) // print in topdown fashion - { - for(int j=0; jreg_names_[i+(32/cols)*j].c_str(), simstate_.state_.rf[i+(32/cols)*j]); - } - printf("\n"); - } - #endif - + // Print architecture registers in DEBUG_SCREEN_RF_COLS columns + cmd_info({"reg", "-a", "-c", std::to_string(DEBUG_SCREEN_RF_COLS)}); } +void print_reg(ArchReg_t reg, bool append_alt_name){ + printf("%-10s : ", (reg.name + ((append_alt_name && reg.alt_name != "") ? (" ("+reg.alt_name+")") : "")).c_str()); + switch(reg.width){ + case R8: printf("%02x", (uint8_t) (*((uint64_t*)reg.ptr) & 0xffULL)); break; + case R16: printf("%04x", (uint16_t) (*((uint64_t*)reg.ptr) & 0xffffULL)); break; + case R32: printf("%08x", (uint32_t) (*((uint64_t*)reg.ptr) & 0xffffffffULL)); break; + case R64: printf("%016lx", (uint64_t) (*((uint64_t*)reg.ptr))); break; + default: + printf("%16s", " - "); + break; + } +} void _parse_line(const std::string s, std::string &cmd, std::vector &args) { @@ -476,13 +466,15 @@ Rcode Atomsim::cmd_break(const std::vector &args) return RC_OK; } + + Rcode Atomsim::cmd_info(const std::vector &args) { - if(args.size() == 0) // step 1 + if(args.size() == 0) { display_dbg_screen(); } - else if(args.size() == 1) // step n + else if(args.size() >= 1) { if(args[0] == "b" || args[0] == "break") { // show breakpoints @@ -492,10 +484,69 @@ Rcode Atomsim::cmd_info(const std::vector &args) printf("%3d %s0x%08x%s\n", i, ansicode(FG_BLUE), breakpoints_[i].addr, ansicode(FG_RESET)); } } - } else if (args[0] == "r" || args[0] == "reg") { - printf(" %s: 0x%08x\n", "pc ", simstate_.state_.pc_e); - for(unsigned i=0; i<32; i++) { - printf(" %s: 0x%08x\n", reg_names_[i].c_str(), simstate_.state_.rf[i]); + } + else if(args[0] == "r" || args[0] == "reg") { + // Print registers + bool arch_regs_only = false; + unsigned cols=1; + bool no_alt_names = false; + std::string regname; + for(int i=1; i regs; + if(regname.length()) { + // If regname provided, search for it + auto it = backend_.regs_.begin(); + for(; it != backend_.regs_.end(); it++) { + if(it->name == regname || it->alt_name == regname) { + regs.push_back(*it); break; + } + } + + if(it == backend_.regs_.end()) { + throw Atomsim_exception("Invalid register: "+ regname); + } + } + else { + // Show all regs + regs = backend_.regs_; + } + + // Filter out non arch registers + if(arch_regs_only) { + regs.erase(std::remove_if(regs.begin(), regs.end(), [](const ArchReg_t& r) { + return !r.is_arch_reg; + }), regs.end()); + } + + unsigned nregs = regs.size(); + unsigned nregs_per_col = ceil((float)nregs/(float)cols); + + for(unsigned i=0; i= nregs) break; + + auto reg = regs[i+nregs_per_col*j]; + // regname + print_reg(reg, !no_alt_names); + + printf(" "); + } + printf("\n"); } } } diff --git a/sim/rvdefs.hpp b/sim/rvdefs.hpp new file mode 100644 index 00000000..8be21cef --- /dev/null +++ b/sim/rvdefs.hpp @@ -0,0 +1,13 @@ +#pragma once +#include + +const std::string rv_abi_regnames [32] = { + "zero", "ra", "sp", "gp", + "tp", "t0", "t1", "t2", + "s0/fp", "s1", "a0", "a1", + "a2", "a3", "a4", "a5", + "a6", "a7", "s2", "s3", + "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", + "t3", "t4", "t5", "t6" +}; diff --git a/sim/simstate.cpp b/sim/simstate.cpp deleted file mode 100644 index 25d4ec02..00000000 --- a/sim/simstate.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "simstate.hpp" -#include "util.hpp" - -void Simstate::dump_simstate(std::string filename) -{ - std::vector fcontents; - char line[50]; - sprintf(line, "pc 0x%08x", state_.pc_e); - fcontents.push_back(std::string(line)); - sprintf(line, "ir 0x%08x", state_.ins_e); - fcontents.push_back(std::string(line)); - for (int i=0; i<32; i++) { - sprintf(line, "x%d 0x%08x", i, state_.rf[i]); - fcontents.push_back(std::string(line)); - } - fWrite(fcontents, filename); -} diff --git a/sim/simstate.hpp b/sim/simstate.hpp deleted file mode 100755 index 31d44209..00000000 --- a/sim/simstate.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once -#include -#include - -/** - * @brief Struct to hold CPU state - */ -struct CPUState -{ - // Fetch-Stage - unsigned int pc_f; - unsigned int ins_f; - - // Execute Stage - unsigned int pc_e; - unsigned int ins_e; - - // Register File - unsigned int rf[32]; - - // Tick counts - uint64_t tickcount_total; - uint64_t tickcount; -}; - - -/** - * @brief Struct to hold CPU signal values - */ -struct CPUSignals -{ - bool jump_decision; -}; - - -/** - * @brief AtomSim Middle end - */ -class Simstate -{ -public: - /** - * @brief CPU State - */ - CPUState state_; - - /** - * @brief CPU signal values - */ - struct CPUSignals signals_; - - /** - * @brief Dump simstate into a file - * @param filename - */ - void dump_simstate(std::string filename); -}; \ No newline at end of file diff --git a/sim/util.cpp b/sim/util.cpp index 65c8f467..445a7b35 100755 --- a/sim/util.cpp +++ b/sim/util.cpp @@ -81,6 +81,17 @@ std::string strip(const std::string& s) } +std::string trimstr(std::string str, size_t len) +{ + if(str.length() > len){ + str.resize(len-3); + str+=" .."; + } + else if (str.length()< len) + str.append(len-str.length(), ' '); + return str; +} + size_t tokenize(const std::string &txt, std::vector &strs, char ch) { size_t pos = txt.find( ch ); diff --git a/sim/util.hpp b/sim/util.hpp index ef75b692..4a6cdca1 100755 --- a/sim/util.hpp +++ b/sim/util.hpp @@ -101,6 +101,14 @@ std::string rStrip(const std::string& s); */ std::string strip(const std::string& s); +/** + * @brief trims string to specified length, inserts ' ..' suffix if len exceeds + * + * @param str input string + * @param len desired length + * @return trimmed string +*/ +std::string trimstr(std::string str, size_t len); ////////////////////////////////////////////////////////////////////////////// // String Tokenizing