npc,refactor: remove original difftest wrapper, cleanup code
This commit is contained in:
parent
85d7840804
commit
de9f770d08
10 changed files with 80 additions and 351 deletions
|
@ -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()
|
||||
|
|
|
@ -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,7 +55,8 @@ class ALU[T <: UInt](tpe: T) extends Module {
|
|||
|
||||
import control.OpSelect._
|
||||
|
||||
out.result := MuxLookup(control.op, 0.U)(Seq(
|
||||
out.result := MuxLookup(control.op, 0.U)(
|
||||
Seq(
|
||||
aOpAdd -> add,
|
||||
aOpSub -> sub,
|
||||
aOpNot -> not,
|
||||
|
@ -66,7 +68,8 @@ class ALU[T <: UInt](tpe: T) extends Module {
|
|||
aOpSll -> sll,
|
||||
aOpSrl -> srl,
|
||||
aOpSra -> sra.asUInt
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
object ALU {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -14,32 +14,48 @@
|
|||
#include <string>
|
||||
|
||||
template <typename T, std::size_t nr> class _RegistersBase {
|
||||
std::array<T, nr> regs;
|
||||
T pc;
|
||||
std::shared_ptr<spdlog::logger> 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 <std::size_t n> class Memory {
|
||||
paddr_t pmem_start, pmem_end;
|
||||
|
||||
public:
|
||||
std::array<uint8_t, n> 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 <typename Mem, typename DevMap> class MemoryMap {
|
||||
std::unique_ptr<Mem> ram;
|
||||
std::unique_ptr<DevMap> devices;
|
||||
std::shared_ptr<spdlog::logger> logger = spdlog::stdout_color_mt("mmap");
|
||||
|
||||
public:
|
||||
MemoryMap(std::unique_ptr<Mem> &&ram, std::unique_ptr<DevMap> &&devices)
|
||||
MemoryMap(std::unique_ptr<Mem> &&ram,
|
||||
std::unique_ptr<DevMap> &&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<Mem> ram;
|
||||
std::unique_ptr<DevMap> devices;
|
||||
std::shared_ptr<spdlog::logger> logger = spdlog::stdout_color_mt("mmap");
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
#ifndef _DIFFTEST_DIFFTEST_H_
|
||||
#define _DIFFTEST_DIFFTEST_H_
|
||||
#include "disasm.hpp"
|
||||
#include "types.h"
|
||||
#include <cassert>
|
||||
#include <components.hpp>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <dlfcn.h>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <trm_interface.hpp>
|
||||
|
||||
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
|
|
@ -1,158 +0,0 @@
|
|||
#ifndef _NPC_TRM_INTERFACE_HEADER_FILE_
|
||||
#define _NPC_TRM_INTERFACE_HEADER_FILE_
|
||||
#include <disasm.hpp>
|
||||
#include <dlfcn.h>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <types.h>
|
||||
|
||||
extern Disassembler d;
|
||||
|
||||
template <typename R, size_t nr_reg> struct CPUStateBase {
|
||||
R reg[nr_reg] = {0};
|
||||
word_t pc = 0x80000000;
|
||||
|
||||
static const std::map<std::string, int> 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 <typename R, size_t nr_reg>
|
||||
std::ostream &operator<<(std::ostream &os, const CPUStateBase<R, nr_reg> &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<word_t, REG_COUNT>;
|
||||
|
||||
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<void(void *, bool)> regcpy;
|
||||
|
||||
public:
|
||||
std::function<void(uint64_t)> exec;
|
||||
std::function<void(int)> init;
|
||||
// TODO: paddr_t can probably changed to (void *)?
|
||||
std::function<void(paddr_t, void *, size_t, bool)> 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
|
|
@ -4,8 +4,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
#include <gdbstub.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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 <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
const std::map<std::string, int> 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<Breakpoint> *bp;
|
||||
};
|
||||
|
|
|
@ -23,6 +23,11 @@ class _RegistersVPI : public _RegistersBase<T, nr> {
|
|||
public:
|
||||
_RegistersVPI<T, nr>(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);
|
||||
|
|
Loading…
Reference in a new issue