Skip to content

Commit

Permalink
[difftest] add spike wrapper to run elf with spike purely
Browse files Browse the repository at this point in the history
[difftest] print pc with hex format

[difftest] use space instead of tab
  • Loading branch information
Clo91eaf committed May 14, 2024
1 parent 245a4e5 commit ae09f5f
Show file tree
Hide file tree
Showing 16 changed files with 1,479 additions and 0 deletions.
34 changes: 34 additions & 0 deletions difftest/libspike_interfaces/CMakeLists.txt
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})
11 changes: 11 additions & 0 deletions difftest/libspike_interfaces/default.nix
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 ];
}
3 changes: 3 additions & 0 deletions difftest/libspike_interfaces/spike_interfaces-config.cmake
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)
241 changes: 241 additions & 0 deletions difftest/libspike_interfaces/spike_interfaces.cc
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;
}
63 changes: 63 additions & 0 deletions difftest/libspike_interfaces/spike_interfaces.h
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__
Loading

0 comments on commit ae09f5f

Please sign in to comment.