-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[difftest] add spike wrapper to run elf with spike purely
[difftest] print pc with hex format [difftest] use space instead of tab
- Loading branch information
Showing
16 changed files
with
1,479 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
cmake_minimum_required(VERSION 3.20) | ||
project(spike_interfaces LANGUAGES CXX) | ||
set(CMAKE_CXX_STANDARD 17) | ||
|
||
find_package(libspike REQUIRED) | ||
|
||
add_library(${CMAKE_PROJECT_NAME} SHARED spike_interfaces.cc) | ||
|
||
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC libspike) | ||
|
||
target_include_directories(${CMAKE_PROJECT_NAME} INTERFACE | ||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> | ||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||
) | ||
|
||
# just playing with CMake export, maybe not necessary | ||
target_sources(${CMAKE_PROJECT_NAME} PUBLIC | ||
FILE_SET HEADERS | ||
FILES spike_interfaces.h spike_interfaces_c.h) | ||
|
||
install( | ||
TARGETS ${CMAKE_PROJECT_NAME} | ||
EXPORT ${CMAKE_PROJECT_NAME}_targets | ||
PUBLIC_HEADER | ||
FILE_SET HEADERS | ||
) | ||
|
||
install( | ||
EXPORT ${CMAKE_PROJECT_NAME}_targets | ||
NAMESPACE ${CMAKE_PROJECT_NAME}:: | ||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${CMAKE_PROJECT_NAME} | ||
) | ||
|
||
install(FILES ${CMAKE_PROJECT_NAME}-config.cmake DESTINATION lib/cmake/${CMAKE_PROJECT_NAME}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ lib, stdenv, cmake, libspike }: | ||
|
||
stdenv.mkDerivation { | ||
name = "libspike_interfaces"; | ||
src = with lib.fileset; toSource { | ||
root = ./.; | ||
fileset = fileFilter (file: file.name != "default.nix") ./.; | ||
}; | ||
nativeBuildInputs = [ cmake ]; | ||
propagatedBuildInputs = [ libspike ]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
include(CMakeFindDependencyMacro) | ||
find_dependency(libspike 0.1.0) | ||
include(${CMAKE_CURRENT_LIST_DIR}/libspike_interface_targets.cmake) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
#include "spike_interfaces.h" | ||
|
||
constexpr uint32_t CSR_MSIMEND = 0x7cc; | ||
|
||
cfg_t make_spike_cfg(const std::string& varch) { | ||
cfg_t cfg; | ||
cfg.initrd_bounds = std::make_pair((reg_t)0, (reg_t)0), | ||
cfg.bootargs = nullptr; | ||
cfg.isa = DEFAULT_ISA; | ||
cfg.priv = DEFAULT_PRIV; | ||
cfg.varch = varch.data(); | ||
cfg.misaligned = false; | ||
cfg.endianness = endianness_little; | ||
cfg.pmpregions = 16; | ||
cfg.pmpgranularity = 4; | ||
cfg.mem_layout = std::vector<mem_cfg_t>(); | ||
cfg.hartids = std::vector<size_t>(); | ||
cfg.explicit_hartids = false; | ||
cfg.real_time_clint = false; | ||
cfg.trigger_count = 4; | ||
return cfg; | ||
} | ||
|
||
Spike::Spike(const char* arch, const char* set, const char* lvl) | ||
: sim(), | ||
varch(arch), | ||
isa(set, lvl), | ||
cfg(make_spike_cfg(varch)), | ||
proc( | ||
/*isa*/ &isa, | ||
/*cfg*/ &cfg, | ||
/*sim*/ &sim, | ||
/*id*/ 0, | ||
/*halt on reset*/ true, | ||
/*log_file_t*/ nullptr, | ||
/*sout*/ std::cerr) { | ||
auto& csrmap = proc.get_state()->csrmap; | ||
csrmap[CSR_MSIMEND] = std::make_shared<basic_csr_t>(&proc, CSR_MSIMEND, 1); | ||
proc.enable_log_commits(); | ||
} | ||
|
||
spike_t* spike_new(const char* arch, const char* set, const char* lvl) { | ||
return new spike_t{new Spike(arch, set, lvl)}; | ||
} | ||
|
||
const char* proc_disassemble(spike_processor_t* proc) { | ||
auto pc = proc->p->get_state()->pc; | ||
auto mmu = proc->p->get_mmu(); | ||
auto disasm = proc->p->get_disassembler(); | ||
auto fetch = mmu->load_insn(pc); | ||
return strdup(disasm->disassemble(fetch.insn).c_str()); | ||
} | ||
|
||
spike_processor_t* spike_get_proc(spike_t* spike) { | ||
return new spike_processor_t{spike->s->get_proc()}; | ||
} | ||
|
||
void proc_reset(spike_processor_t* proc) { | ||
proc->p->reset(); | ||
} | ||
|
||
spike_state_t* proc_get_state(spike_processor_t* proc) { | ||
return new spike_state_t{proc->p->get_state()}; | ||
} | ||
|
||
reg_t proc_func(spike_processor_t* proc) { | ||
auto pc = proc->p->get_state()->pc; | ||
auto mmu = proc->p->get_mmu(); | ||
auto fetch = mmu->load_insn(pc); | ||
return fetch.func(proc->p, fetch.insn, pc); | ||
} | ||
|
||
reg_t proc_get_insn(spike_processor_t* proc) { | ||
auto pc = proc->p->get_state()->pc; | ||
auto mmu = proc->p->get_mmu(); | ||
auto fetch = mmu->load_insn(pc); | ||
return fetch.insn.bits(); | ||
} | ||
|
||
uint8_t* proc_get_vreg_addr(spike_processor_t* proc) { | ||
return &proc->p->VU.elt<uint8_t>(0, 0); | ||
} | ||
|
||
uint32_t extract_f32(freg_t f) { return (uint32_t)f.v[0]; } | ||
|
||
inline uint32_t clip(uint32_t binary, int a, int b) { | ||
int nbits = b - a + 1; | ||
uint32_t mask = nbits >= 32 ? (uint32_t)-1 : (1 << nbits) - 1; | ||
return (binary >> a) & mask; | ||
} | ||
|
||
uint64_t proc_get_rs(spike_processor_t* proc) { | ||
auto pc = proc->p->get_state()->pc; | ||
auto fetch = proc->p->get_mmu()->load_insn(pc); | ||
return (uint64_t)fetch.insn.rs1() << 32 | (uint64_t)fetch.insn.rs2(); | ||
} | ||
|
||
uint32_t proc_get_rd(spike_processor_t* proc) { | ||
auto pc = proc->p->get_state()->pc; | ||
auto fetch = proc->p->get_mmu()->load_insn(pc); | ||
return fetch.insn.rd(); | ||
} | ||
|
||
uint64_t proc_get_rs_bits(spike_processor_t* proc) { | ||
auto state = proc->p->get_state(); | ||
auto &xr = state->XPR; | ||
auto &fr = state->FPR; | ||
auto pc = state->pc; | ||
auto inst_bits = proc_get_insn(proc); | ||
|
||
uint32_t opcode = clip(inst_bits, 0, 6); | ||
uint32_t width = clip(inst_bits, 12, 14); // also funct3 | ||
auto fetch = proc->p->get_mmu()->load_insn(pc); | ||
uint32_t rs1_bits, rs2_bits; | ||
bool is_fp_operands = opcode == 0b1010111 && (width == 0b101 /* OPFVF */); | ||
if (is_fp_operands) { | ||
rs1_bits = extract_f32(fr[fetch.insn.rs1()]); | ||
rs2_bits = extract_f32(fr[fetch.insn.rs2()]); | ||
} else { | ||
rs1_bits = xr[fetch.insn.rs1()]; | ||
rs2_bits = xr[fetch.insn.rs2()]; | ||
} | ||
|
||
return (uint64_t)rs1_bits << 32 | (uint64_t)rs2_bits; | ||
} | ||
|
||
uint64_t proc_vu_get_vtype(spike_processor_t* proc) { | ||
return proc->p->VU.vtype->read(); | ||
} | ||
|
||
uint32_t proc_vu_get_vxrm(spike_processor_t* proc) { | ||
return proc->p->VU.vxrm->read(); | ||
} | ||
|
||
uint32_t proc_vu_get_vnf(spike_processor_t* proc) { | ||
auto pc = proc->p->get_state()->pc; | ||
auto fetch = proc->p->get_mmu()->load_insn(pc); | ||
return fetch.insn.v_nf(); | ||
} | ||
|
||
bool proc_vu_get_vill(spike_processor_t* proc) { | ||
return proc->p->VU.vill; | ||
} | ||
|
||
bool proc_vu_get_vxsat(spike_processor_t* proc) { | ||
return proc->p->VU.vxsat->read(); | ||
} | ||
|
||
uint32_t proc_vu_get_vl(spike_processor_t* proc) { | ||
return proc->p->VU.vl->read(); | ||
} | ||
|
||
uint16_t proc_vu_get_vstart(spike_processor_t* proc) { | ||
return proc->p->VU.vstart->read(); | ||
} | ||
|
||
reg_t state_get_pc(spike_state_t* state) { | ||
return state->s->pc; | ||
} | ||
|
||
void state_clear(spike_state_t* state) { | ||
state->s->log_reg_write.clear(); | ||
state->s->log_mem_read.clear(); | ||
state->s->log_mem_write.clear(); | ||
} | ||
|
||
static void state_set_serialized(spike_state_t* state, bool serialized) { | ||
state->s->serialized = serialized; | ||
} | ||
|
||
uint64_t state_handle_pc(spike_state_t* state, uint64_t new_pc) { | ||
if ((new_pc & 1) == 0) { | ||
state_set_pc(state, new_pc); | ||
} else { | ||
switch (new_pc) { | ||
case PC_SERIALIZE_BEFORE: | ||
state_set_serialized(state, true); | ||
break; | ||
case PC_SERIALIZE_AFTER: | ||
break; | ||
default: | ||
return -1; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
void state_set_pc(spike_state_t* state, uint64_t pc) { | ||
state->s->pc = pc; | ||
} | ||
|
||
uint32_t state_get_mem_write_size(spike_state_t* state) { | ||
return state->s->log_mem_write.size(); | ||
} | ||
|
||
uint32_t state_get_mem_write_addr(spike_state_t* state, uint32_t index) { | ||
return std::get<0>(state->s->log_mem_write[index]) & 0xffffffff; | ||
} | ||
|
||
uint64_t state_get_mem_write_value(spike_state_t* state, uint32_t index) { | ||
return std::get<1>(state->s->log_mem_write[index]); | ||
} | ||
|
||
uint8_t state_get_mem_write_size_by_byte(spike_state_t* state, uint32_t index) { | ||
return std::get<2>(state->s->log_mem_write[index]); | ||
} | ||
|
||
uint32_t state_get_mem_read_size(spike_state_t* state) { | ||
return state->s->log_mem_read.size(); | ||
} | ||
|
||
uint32_t state_get_mem_read_addr(spike_state_t* state, uint32_t index) { | ||
return std::get<0>(state->s->log_mem_read[index]) & 0xffffffff; | ||
} | ||
|
||
uint8_t state_get_mem_read_size_by_byte(spike_state_t* state, uint32_t index) { | ||
return std::get<2>(state->s->log_mem_read[index]); | ||
} | ||
|
||
reg_t state_exit(spike_state_t* state) { | ||
auto& csrmap = state->s->csrmap; | ||
return csrmap[CSR_MSIMEND]->read(); | ||
} | ||
|
||
void spike_register_callback(ffi_callback callback) { | ||
ffi_addr_to_mem = callback; | ||
|
||
return; | ||
} | ||
|
||
void spike_destruct(spike_t* spike) { | ||
delete spike; | ||
} | ||
|
||
void proc_destruct(spike_processor_t* proc) { | ||
delete proc; | ||
} | ||
|
||
void state_destruct(spike_state_t* state) { | ||
delete state; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#ifndef __SPIKE_INTERFCES_H__ | ||
#define __SPIKE_INTERFCES_H__ | ||
|
||
#include "cfg.h" | ||
#include "decode_macros.h" | ||
#include "disasm.h" | ||
#include "mmu.h" | ||
#include "processor.h" | ||
#include "simif.h" | ||
#include "spike_interfaces_c.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
ffi_callback ffi_addr_to_mem; | ||
|
||
class sim_t : public simif_t { | ||
public: | ||
sim_t() {} | ||
~sim_t() {} | ||
char* addr_to_mem(reg_t addr) override { return ffi_addr_to_mem(addr); } | ||
bool mmio_load(reg_t addr, size_t len, uint8_t* bytes) override { throw std::logic_error("not implemented"); } | ||
bool mmio_store(reg_t addr, size_t len, const uint8_t* bytes) override { throw std::logic_error("not implemented"); } | ||
virtual void proc_reset(unsigned id) override { } | ||
virtual const char* get_symbol(uint64_t addr) override { throw std::logic_error("not implemented"); } | ||
[[nodiscard]] const cfg_t& get_cfg() const override { throw std::logic_error("not implemented"); } | ||
[[nodiscard]] const std::map<size_t, processor_t*>& get_harts() | ||
const override { throw std::logic_error("not implemented"); } | ||
}; | ||
|
||
class Spike { | ||
public: | ||
Spike(const char* arch, const char* set, const char* lvl); | ||
processor_t* get_proc() { return &proc; } | ||
|
||
private: | ||
std::string varch; | ||
cfg_t cfg; | ||
sim_t sim; | ||
isa_parser_t isa; | ||
processor_t proc; | ||
}; | ||
|
||
struct spike_t { | ||
Spike* s; | ||
ffi_callback ffi_addr_to_mem; | ||
}; | ||
struct spike_processor_t { | ||
processor_t* p; | ||
}; | ||
struct spike_state_t { | ||
state_t* s; | ||
}; | ||
struct spike_mmu_t { | ||
mmu_t* m; | ||
}; | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif // __SPIKE_INTERFCES_H__ |
Oops, something went wrong.