diff --git a/dv/cosim/spike_cosim.cc b/dv/cosim/spike_cosim.cc index fed838d5..bdf2af02 100644 --- a/dv/cosim/spike_cosim.cc +++ b/dv/cosim/spike_cosim.cc @@ -105,10 +105,6 @@ bool SpikeCosim::step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc, bool sync_trap) { assert(write_reg < 32); - if (pc_is_mret(pc)) { - nmi_mode = false; - } - uint32_t initial_pc = (processor->get_state()->pc & 0xffffffff); bool initial_pc_match = initial_pc == pc; @@ -172,6 +168,11 @@ bool SpikeCosim::step(uint32_t write_reg, uint32_t write_reg_data, uint32_t pc, return false; } + if (!sync_trap && pc_is_mret(pc) && nmi_mode) { + // Do handling for recoverable NMI + leave_nmi_mode(); + } + // Check register writes from executed instruction match what is expected auto ®_changes = processor->get_state()->log_reg_write; @@ -288,6 +289,19 @@ void SpikeCosim::on_csr_write(const commit_log_reg_t::value_type ®_change) { fixup_csr(cosim_write_csr, cosim_write_csr_data); } +void SpikeCosim::leave_nmi_mode() { + nmi_mode = false; + + // Restore CSR status from mstack + uint32_t mstatus = processor->get_csr(CSR_MSTATUS); + mstatus = set_field(mstatus, MSTATUS_MPP, mstack.mpp); + mstatus = set_field(mstatus, MSTATUS_MPIE, mstack.mpie); + processor->set_csr(CSR_MSTATUS, mstatus); + + processor->set_csr(CSR_MEPC, mstack.epc); + processor->set_csr(CSR_MCAUSE, mstack.cause); +} + void SpikeCosim::set_mip(uint32_t mip) { processor->get_state()->mip->write_with_mask(0xffffffff, mip); } @@ -296,6 +310,13 @@ void SpikeCosim::set_nmi(bool nmi) { if (nmi && !nmi_mode && !processor->get_state()->debug_mode) { processor->get_state()->nmi = true; nmi_mode = true; + + // When NMI is set it is guaranteed NMI trap will be taken at the next step + // so save CSR state for recoverable NMI to mstack now. + mstack.mpp = get_field(processor->get_csr(CSR_MSTATUS), MSTATUS_MPP); + mstack.mpie = get_field(processor->get_csr(CSR_MSTATUS), MSTATUS_MPIE); + mstack.epc = processor->get_csr(CSR_MEPC); + mstack.cause = processor->get_csr(CSR_MCAUSE); } } diff --git a/dv/cosim/spike_cosim.h b/dv/cosim/spike_cosim.h index ee811085..dea247e2 100644 --- a/dv/cosim/spike_cosim.h +++ b/dv/cosim/spike_cosim.h @@ -26,6 +26,15 @@ class SpikeCosim : public simif_t, public Cosim { std::vector errors; bool nmi_mode; + typedef struct { + uint8_t mpp; + bool mpie; + uint32_t epc; + uint32_t cause; + } mstack_t; + + mstack_t mstack; + void fixup_csr(int csr_num, uint32_t csr_val); struct PendingMemAccess { @@ -54,6 +63,8 @@ class SpikeCosim : public simif_t, public Cosim { void on_csr_write(const commit_log_reg_t::value_type ®_change); + void leave_nmi_mode(); + int insn_cnt; public: