Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix spike trap #727

Open
wants to merge 6 commits into
base: real-rocket-v
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 116 additions & 13 deletions difftest/spike_interfaces/spike_interfaces.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ const char *proc_disassemble(spike_processor_t *proc) {
return strdup(disasm->disassemble(fetch.insn).c_str());
}

const char *proc_disassemble_with_pc(spike_processor_t *proc, reg_t 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()};
}
Expand All @@ -67,20 +74,79 @@ spike_state_t *proc_get_state(spike_processor_t *proc) {
}

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);
try {
return fetch.func(proc->p, fetch.insn, pc);
reg_t pc = proc->p->get_state()->pc;
mmu_t* mmu = proc->p->get_mmu();
insn_fetch_t fetch;
reg_t res;
// todo: consider interrupt
try {
fetch = mmu->load_insn(pc);
res = fetch.func(proc->p, fetch.insn, pc);
} catch (trap_t &trap) {
std::cerr << "Error: spike trapped with " << trap.name()
<< " (tval=" << std::uppercase << std::setfill('0')
<< std::setw(8) << std::hex << trap.get_tval()
<< ", tval2=" << std::setw(8) << std::hex << trap.get_tval2()
<< ", tinst=" << std::setw(8) << std::hex << trap.get_tinst()
<< ")" << std::endl;
throw trap;
}
//printf("catch exception\n");
unsigned max_xlen = proc->p->get_const_xlen();
state_t* state = proc->p->get_state();
reg_t hsdeleg = (state->prv <= PRV_S) ? state->medeleg->read() : 0;
bool curr_virt = state->v;
reg_t bit = trap.cause();

if (state->prv <= PRV_S && bit < max_xlen && ((hsdeleg >> bit) & 1)) {
reg_t vector = (state->nonvirtual_stvec->read() & 1) ? 4 * bit : 0;
state->pc = (state->nonvirtual_stvec->read() & ~(reg_t)1) + vector;
state->nonvirtual_scause->write(trap.cause());
state->nonvirtual_sepc->write(pc);
state->nonvirtual_stval->write(trap.get_tval());
state->htval->write(trap.get_tval2());
state->htinst->write(trap.get_tinst());

reg_t s = state->nonvirtual_sstatus->read();
s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
s = set_field(s, MSTATUS_SPP, state->prv);
s = set_field(s, MSTATUS_SIE, 0);
s = set_field(s, MSTATUS_SPELP, state->elp);
state->elp = elp_t::NO_LP_EXPECTED;
state->nonvirtual_sstatus->write(s);
proc->p->set_privilege(PRV_S, false);
} else {
const reg_t vector = (state->mtvec->read() & 1) ? 4 * bit : 0;
const reg_t trap_handler_address = (state->mtvec->read() & ~(reg_t)1) + vector;

// todo: consider nmi
//const reg_t rnmi_trap_handler_address = 0;
//const bool nmie = !(state->mnstatus && !get_field(state->mnstatus->read(), MNSTATUS_NMIE));
//state->pc = !nmie ? rnmi_trap_handler_address : trap_handler_address;
state->pc = trap_handler_address;
state->mepc->write(pc);
state->mcause->write(trap.cause());
state->mtval->write(trap.get_tval());
state->mtval2->write(trap.get_tval2());
state->mtinst->write(trap.get_tinst());

reg_t s = state->mstatus->read();
s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
s = set_field(s, MSTATUS_MPP, state->prv);
s = set_field(s, MSTATUS_MIE, 0);
s = set_field(s, MSTATUS_MPV, curr_virt);
s = set_field(s, MSTATUS_GVA, trap.has_gva());
s = set_field(s, MSTATUS_MPELP, state->elp);
state->elp = elp_t::NO_LP_EXPECTED;
state->mstatus->write(s);
if (state->mstatush) state->mstatush->write(s >> 32);
//state->tcontrol->write((state->tcontrol->read() & CSR_TCONTROL_MTE) ? CSR_TCONTROL_MPTE : 0);
proc->p->set_privilege(PRV_M, false);
}
//std::cerr << "Error: spike trapped with " << trap.name()
// << " (tval=" << std::uppercase << std::setfill('0')
// << std::setw(8) << std::hex << trap.get_tval()
// << ", tval2=" << std::setw(8) << std::hex << trap.get_tval2()
// << ", tinst=" << std::setw(8) << std::hex << trap.get_tinst()
// << ")" << std::endl;
//throw trap;
proc->is_exception = true;
res = state->pc;
}

return res;
}

reg_t proc_get_insn(spike_processor_t *proc) {
Expand All @@ -90,6 +156,16 @@ reg_t proc_get_insn(spike_processor_t *proc) {
return fetch.insn.bits();
}

reg_t proc_get_insn_with_pc(spike_processor_t *proc, reg_t pc) {
try {
auto mmu = proc->p->get_mmu();
auto fetch = mmu->load_insn(pc);
return fetch.insn.bits();
} catch(...) {
return 0;
}
}

uint8_t proc_get_vreg_data(spike_processor_t *proc, uint32_t vreg_idx,
uint32_t vreg_offset) {
return proc->p->VU.elt<uint8_t>(vreg_idx, vreg_offset);
Expand All @@ -109,18 +185,45 @@ uint32_t proc_get_rs1(spike_processor_t *proc) {
return (uint32_t)fetch.insn.rs1();
}

uint32_t proc_get_rs1_with_pc(spike_processor_t *proc, reg_t pc) {
try{
auto fetch = proc->p->get_mmu()->load_insn(pc);
return (uint32_t)fetch.insn.rs1();
} catch(...) {
return 0;
}
}

uint32_t proc_get_rs2(spike_processor_t *proc) {
auto pc = proc->p->get_state()->pc;
auto fetch = proc->p->get_mmu()->load_insn(pc);
return (uint32_t)fetch.insn.rs2();
}

uint32_t proc_get_rs2_with_pc(spike_processor_t *proc, reg_t pc) {
try{
auto fetch = proc->p->get_mmu()->load_insn(pc);
return (uint32_t)fetch.insn.rs2();
} catch(...) {
return 0;
}
}

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();
}

uint32_t proc_get_rd_with_pc(spike_processor_t *proc, reg_t pc) {
try {
auto fetch = proc->p->get_mmu()->load_insn(pc);
return fetch.insn.rd();
} catch(...) {
return 0;
}
}

uint64_t proc_vu_get_vtype(spike_processor_t *proc) {
return proc->p->VU.vtype->read();
}
Expand Down
1 change: 1 addition & 0 deletions difftest/spike_interfaces/spike_interfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct spike_t {
};
struct spike_processor_t {
processor_t *p;
bool is_exception;
};
struct spike_state_t {
state_t *s;
Expand Down
5 changes: 5 additions & 0 deletions difftest/spike_interfaces/spike_interfaces_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,22 @@ void spike_register_callback(void *ffi_target, ffi_callback callback);
spike_t *spike_new(const char *set, const char *lvl,
size_t lane_number);
const char *proc_disassemble(spike_processor_t *proc);
const char *proc_disassemble_with_pc(spike_processor_t *proc, reg_t pc);
void proc_reset(spike_processor_t *proc);
spike_processor_t *spike_get_proc(spike_t *spike);
spike_state_t *proc_get_state(spike_processor_t *proc);

uint64_t proc_func(spike_processor_t *proc);
uint64_t proc_get_insn(spike_processor_t *proc);
uint64_t proc_get_insn_with_pc(spike_processor_t *proc, reg_t pc);
uint8_t proc_get_vreg_data(spike_processor_t *proc, uint32_t vreg_idx,
uint32_t vreg_offset);
uint32_t proc_get_rs1(spike_processor_t *proc);
uint32_t proc_get_rs1_with_pc(spike_processor_t *proc, reg_t pc);
uint32_t proc_get_rs2(spike_processor_t *proc);
uint32_t proc_get_rs2_with_pc(spike_processor_t *proc, reg_t pc);
uint32_t proc_get_rd(spike_processor_t *proc);
uint32_t proc_get_rd_with_pc(spike_processor_t *proc, reg_t pc);

uint64_t proc_vu_get_vtype(spike_processor_t *proc);
uint32_t proc_vu_get_vxrm(spike_processor_t *proc);
Expand Down
2 changes: 1 addition & 1 deletion rocketemu/driver/src/sim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub struct SimulationArgs {
pub log_level: String,

/// The timeout value
#[arg(long, default_value_t = 1_0000)]
#[arg(long, default_value_t = 3_00000)]
pub timeout: u64,

#[cfg(feature = "trace")]
Expand Down
1 change: 1 addition & 0 deletions rocketemu/nix/verilated-csrc.nix
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ stdenv.mkDerivation {
-O1 \
-Wno-WIDTHEXPAND \
-Wno-LATCH \
-Wno-UNOPTTHREADS \
--cc TestBench

echo "[nix] building verilated C lib"
Expand Down
2 changes: 1 addition & 1 deletion rocketemu/offline/src/difftest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl Difftest {
}
if se.is_rd_written() && se.rd_idx != 0 {
let event = self.dut.step()?;

match event {
JsonEvents::RegWrite { addr, data, cycle } => {
self.runner.cycle = *cycle;
Expand Down
38 changes: 37 additions & 1 deletion rocketemu/spike_rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl Spike {

pub fn get_proc(&self) -> Processor {
let processor = unsafe { spike_get_proc(self.spike) };
Processor { processor }
Processor { processor: processor, is_exception: false }
}

pub fn load_bytes_to_mem(
Expand Down Expand Up @@ -88,6 +88,7 @@ impl Drop for Spike {

pub struct Processor {
processor: *mut (),
is_exception: bool,
}

impl Processor {
Expand All @@ -97,6 +98,12 @@ impl Processor {
format!("{}", c_str.to_string_lossy())
}

pub fn disassemble_with_pc(&self, pc: u64) -> String {
let bytes = unsafe { proc_disassemble_with_pc(self.processor, pc) };
let c_str = unsafe { CStr::from_ptr(bytes as *mut c_char) };
format!("{}", c_str.to_string_lossy())
}

pub fn reset(&self) {
unsafe { proc_reset(self.processor) }
}
Expand All @@ -114,6 +121,10 @@ impl Processor {
unsafe { proc_get_insn(self.processor) as u32 }
}

pub fn get_insn_with_pc(&self, pc: u64) -> u32 {
unsafe { proc_get_insn_with_pc(self.processor, pc) as u32 }
}

pub fn get_vreg_data(&self, idx: u32, offset: u32) -> u8 {
unsafe { proc_get_vreg_data(self.processor, idx, offset) }
}
Expand All @@ -122,14 +133,26 @@ impl Processor {
unsafe { proc_get_rs1(self.processor) }
}

pub fn get_rs1_with_pc(&self, pc: u64) -> u32 {
unsafe { proc_get_rs1_with_pc(self.processor, pc) }
}

pub fn get_rs2(&self) -> u32 {
unsafe { proc_get_rs2(self.processor) }
}

pub fn get_rs2_with_pc(&self, pc: u64) -> u32 {
unsafe { proc_get_rs2_with_pc(self.processor, pc) }
}

pub fn get_rd(&self) -> u32 {
unsafe { proc_get_rd(self.processor) }
}

pub fn get_rd_with_pc(&self, pc: u64) -> u32 {
unsafe { proc_get_rd_with_pc(self.processor, pc) }
}

// vu
pub fn vu_get_vtype(&self) -> u32 {
unsafe { proc_vu_get_vtype(self.processor) as u32 }
Expand Down Expand Up @@ -158,6 +181,14 @@ impl Processor {
pub fn vu_get_vstart(&self) -> u16 {
unsafe { proc_vu_get_vstart(self.processor) }
}

pub fn is_exception(&self) -> bool {
self.is_exception
}

pub fn reset_exception(&mut self) {
self.is_exception = false
}
}

impl Drop for Processor {
Expand Down Expand Up @@ -249,14 +280,19 @@ extern "C" {
fn spike_get_proc(spike: *mut ()) -> *mut ();
fn spike_destruct(spike: *mut ());
fn proc_disassemble(proc: *mut ()) -> *mut c_char;
fn proc_disassemble_with_pc(proc: *mut(), pc: u64) -> *mut c_char;
fn proc_reset(proc: *mut ());
fn proc_get_state(proc: *mut ()) -> *mut ();
fn proc_func(proc: *mut ()) -> u64;
fn proc_get_insn(proc: *mut ()) -> u64;
fn proc_get_insn_with_pc(proc: *mut(), pc: u64) -> u64;
fn proc_get_vreg_data(proc: *mut (), vreg_idx: u32, vreg_offset: u32) -> u8;
fn proc_get_rs1(proc: *mut ()) -> u32;
fn proc_get_rs1_with_pc(proc: *mut(), pc: u64) -> u32;
fn proc_get_rs2(proc: *mut ()) -> u32;
fn proc_get_rs2_with_pc(proc: *mut(), pc: u64) -> u32;
fn proc_get_rd(proc: *mut ()) -> u32;
fn proc_get_rd_with_pc(proc: *mut(), pc: u64) -> u32;

fn proc_vu_get_vtype(proc: *mut ()) -> u64;
fn proc_vu_get_vxrm(proc: *mut ()) -> u32;
Expand Down
Loading