#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