From 47e52af62806bbfc521fd6a300d0118a084f4e3b Mon Sep 17 00:00:00 2001 From: lewislzh Date: Wed, 13 Nov 2024 13:11:39 +0800 Subject: [PATCH] feat(dbltrp): support full dbltrp extension in spike --- difftest/difftest-def.h | 3 ++- difftest/difftest.cc | 8 ++++++++ difftest/difftest.h | 1 + riscv/csr_init.cc | 2 +- riscv/csrs.cc | 19 ++++++++++++++++++- riscv/csrs.h | 3 +++ riscv/processor.cc | 29 +++++++++++++++++++++++++---- riscv/processor.h | 3 ++- 8 files changed, 60 insertions(+), 8 deletions(-) diff --git a/difftest/difftest-def.h b/difftest/difftest-def.h index ea8597f24d..68aff5f9d0 100644 --- a/difftest/difftest-def.h +++ b/difftest/difftest-def.h @@ -80,7 +80,8 @@ "_zfa_zfh_zvfh" \ "_svinval_sscofpmf" \ "_svpbmt" \ - "_zicbom_zicboz" + "_zicbom_zicboz" \ + "_smrnmi_smdbltrp_ssdbltrp" \ #define CONFIG_MEMORY_SIZE (16 * 1024 * 1024 * 1024UL) #define CONFIG_FLASH_BASE 0x10000000UL diff --git a/difftest/difftest.cc b/difftest/difftest.cc index 9185eb9831..939fe49d60 100644 --- a/difftest/difftest.cc +++ b/difftest/difftest.cc @@ -394,6 +394,10 @@ void DifftestRef::raise_intr(uint64_t no) { } } +bool DifftestRef::raise_critical_error() { + return state->critical_error; +} + void DifftestRef::update_mip(void *non_reg_interrupt_pending) { auto n = (DifftestNonRegInterruptPending *) non_reg_interrupt_pending; state->mip->backdoor_write_with_mask(MIP_MTIP, n->platform_irp_mtip ? MIP_MTIP : 0); @@ -568,6 +572,10 @@ void difftest_raise_intr(uint64_t NO) { ref->raise_intr(NO); } +bool difftest_raise_critical_error() { + return ref->raise_critical_error(); +} + void isa_reg_display() { ref->display(); } diff --git a/difftest/difftest.h b/difftest/difftest.h index 978c383afb..22ec17493f 100644 --- a/difftest/difftest.h +++ b/difftest/difftest.h @@ -142,6 +142,7 @@ class DifftestRef { void debug_memcpy_from_dut(reg_t dest, void* src, size_t n); int store_commit(uint64_t *addr, uint64_t *data, uint8_t *mask); void raise_intr(uint64_t no); + bool raise_critical_error(); void display(); void update_mip(void *non_reg_interrupt_pending); void update_dynamic_config(void* config) { diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index e124130fb1..22e2c99c1e 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -339,7 +339,7 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) if (proc->extension_enabled_const(EXT_SMRNMI)) { add_csr(CSR_MNSCRATCH, std::make_shared(proc, CSR_MNSCRATCH, 0)); add_csr(CSR_MNEPC, mnepc = std::make_shared(proc, CSR_MNEPC)); - add_csr(CSR_MNCAUSE, std::make_shared(proc, CSR_MNCAUSE, (reg_t)1 << (xlen - 1))); + add_csr(CSR_MNCAUSE, mncause = std::make_shared(proc, CSR_MNCAUSE)); add_csr(CSR_MNSTATUS, mnstatus = std::make_shared(proc, CSR_MNSTATUS)); } diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 8a9337290c..7d0600b279 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -598,18 +598,31 @@ reg_t mstatus_csr_t::compute_mstatus_initial_value() const noexcept { | (proc->extension_enabled_const('U') && (proc->get_const_xlen() != 32) ? set_field((reg_t)0, MSTATUS_UXL, xlen_to_uxl(proc->get_const_xlen())) : 0) | (proc->extension_enabled_const('S') && (proc->get_const_xlen() != 32) ? set_field((reg_t)0, MSTATUS_SXL, xlen_to_uxl(proc->get_const_xlen())) : 0) | (proc->get_mmu()->is_target_big_endian() ? big_endian_bits : 0) +#if defined(DIFFTEST) && defined(CPU_XIANGSHAN) + | 0 +#else | (proc->extension_enabled(EXT_SMDBLTRP) ? MSTATUS_MDT : 0) +#endif | 0; // initial value for mstatus } // implement class mnstatus_csr_t mnstatus_csr_t::mnstatus_csr_t(processor_t* const proc, const reg_t addr): - basic_csr_t(proc, addr, 0) { +#if defined(DIFFTEST) && defined(CPU_XIANGSHAN) + basic_csr_t(proc, addr, MNSTATUS_NMIE) +#else + basic_csr_t(proc, addr, 0) +#endif + { } bool mnstatus_csr_t::unlogged_write(const reg_t val) noexcept { // NMIE can be set but not cleared +#if defined(DIFFTEST) && defined(CPU_XIANGSHAN) + const reg_t mask = MNSTATUS_NMIE +#else const reg_t mask = (~read() & MNSTATUS_NMIE) +#endif | (proc->extension_enabled('H') ? MNSTATUS_MNPV : 0) | MNSTATUS_MNPP; @@ -620,6 +633,10 @@ bool mnstatus_csr_t::unlogged_write(const reg_t val) noexcept { return basic_csr_t::unlogged_write(new_mnstatus); } +bool mnstatus_csr_t::bare_write(const reg_t val) noexcept { + return basic_csr_t::unlogged_write(val); +} + // implement class rv32_low_csr_t rv32_low_csr_t::rv32_low_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig): csr_t(proc, addr), diff --git a/riscv/csrs.h b/riscv/csrs.h index 0a6629b56c..b46a52cfaa 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -271,6 +271,7 @@ typedef std::shared_ptr mstatus_csr_t_p; class mnstatus_csr_t final: public basic_csr_t { public: mnstatus_csr_t(processor_t* const proc, const reg_t addr); + bool bare_write(const reg_t val) noexcept; protected: virtual bool unlogged_write(const reg_t val) noexcept override; }; @@ -551,6 +552,8 @@ class wide_counter_csr_t: public csr_t { typedef std::shared_ptr wide_counter_csr_t_p; +typedef std::shared_ptr mnstatus_csr_t_p; + class time_counter_csr_t: public csr_t { public: time_counter_csr_t(processor_t* const proc, const reg_t addr); diff --git a/riscv/processor.cc b/riscv/processor.cc index 32c7c567de..7b42e50026 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -463,7 +463,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc) // An unexpected trap - a trap when SDT is 1 - traps to M-mode if ((state.prv <= PRV_S && bit < max_xlen) && (((vsdeleg >> bit) & 1) || ((hsdeleg >> bit) & 1))) { - reg_t s = curr_virt ? state.nonvirtual_sstatus->read() : state.sstatus->read(); + reg_t s = state.sstatus->read(); supv_double_trap = get_field(s, MSTATUS_SDT); if (supv_double_trap) vsdeleg = hsdeleg = 0; @@ -534,17 +534,38 @@ void processor_t::take_trap(trap_t& t, reg_t epc) reg_t s = state.mstatus->read(); if ( extension_enabled(EXT_SMDBLTRP)) { - if (get_field(s, MSTATUS_MDT) || !nmie) { + bool m_double_trap = get_field(s, MSTATUS_MDT); + if (!nmie) { // Critical error - Double trap in M-mode or trap when nmie is 0 // RNMI is not modeled else double trap in M-mode would trap to // RNMI handler instead of leading to a critical error state.critical_error = 1; return; } - s = set_field(s, MSTATUS_MDT, 1); + if (m_double_trap) { + state.pc = trap_handler_address; + reg_t mnstatus_val = state.mnstatus->read(); + mnstatus_val = set_field(mnstatus_val, MNSTATUS_MNPP, state.prv); + mnstatus_val = set_field(mnstatus_val, MNSTATUS_MNPV, curr_virt); + mnstatus_val = set_field(mnstatus_val, MNSTATUS_NMIE, 0);\ + state.mnstatus->bare_write(mnstatus_val); +#ifdef CPU_ROCKET_CHIP + state.mnepc->write(encode_vaddr(epc)); +#else + state.mnepc->write(epc); +#endif + state.mncause->write(t.cause()); + set_privilege(PRV_M, false); + return; + } else { + s = set_field(s, MSTATUS_MDT, 1); + } } - +#if defined(DIFFTEST) && defined(CPU_XIANGSHAN) + state.pc = trap_handler_address; +#else state.pc = !nmie ? rnmi_trap_handler_address : trap_handler_address; +#endif #ifdef CPU_ROCKET_CHIP state.mepc->write(encode_vaddr(epc)); #else diff --git a/riscv/processor.h b/riscv/processor.h index 7869f6e3b1..9f0cee0827 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -101,8 +101,9 @@ struct state_t csr_t_p mideleg; csr_t_p mcounteren; csr_t_p mevent[N_HPMCOUNTERS]; - csr_t_p mnstatus; + mnstatus_csr_t_p mnstatus; csr_t_p mnepc; + csr_t_p mncause; csr_t_p scounteren; csr_t_p sepc; csr_t_p stval;