aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2024-08-18 18:43:57 -0500
committerGitHub <noreply@github.com>2024-08-18 18:43:57 -0500
commitf09b02460ee17f8d09c84d2752dc006e32700223 (patch)
treec692e3e436569b7bbd6d8721732eef67c049203d
parent33d80b40d68f7c5c7dd0ea4f6f54ab83848db8da (diff)
parentc302e8bd16f5c05faff4e2ecfdeebcb502a55578 (diff)
downloadriscv-isa-sim-f09b02460ee17f8d09c84d2752dc006e32700223.zip
riscv-isa-sim-f09b02460ee17f8d09c84d2752dc006e32700223.tar.gz
riscv-isa-sim-f09b02460ee17f8d09c84d2752dc006e32700223.tar.bz2
Merge pull request #1722 from ved-rivos/smdbltrp
Add Smdbltrp
-rw-r--r--README.md1
-rw-r--r--disasm/isa_parser.cc2
-rw-r--r--riscv/csrs.cc16
-rw-r--r--riscv/csrs.h4
-rw-r--r--riscv/encoding.h7
-rw-r--r--riscv/execute.cc36
-rw-r--r--riscv/insns/dret.h10
-rw-r--r--riscv/insns/mret.h1
-rw-r--r--riscv/insns/sret.h9
-rw-r--r--riscv/isa_parser.h1
-rw-r--r--riscv/processor.cc24
-rw-r--r--riscv/processor.h4
12 files changed, 95 insertions, 20 deletions
diff --git a/README.md b/README.md
index bdb81bb..de1ac5f 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,7 @@ Spike supports the following RISC-V ISA features:
- Sdtrig extension, v1.0-STABLE
- Smepmp extension v1.0
- Smstateen extension, v1.0
+ - Smdbltrp extension, v1.0
- Sscofpmf v0.5.2
- Ssdbltrp extension, v1.0
- Ssqosid extension, v1.0
diff --git a/disasm/isa_parser.cc b/disasm/isa_parser.cc
index 54dbf65..95ef8fb 100644
--- a/disasm/isa_parser.cc
+++ b/disasm/isa_parser.cc
@@ -355,6 +355,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
elen = std::max(elen, new_elen);
} else if (ext_str == "ssdbltrp") {
extension_table[EXT_SSDBLTRP] = true;
+ } else if (ext_str == "smdbltrp") {
+ extension_table[EXT_SMDBLTRP] = true;
} else if (ext_str[0] == 'x') {
extension_table['X'] = true;
if (ext_str.size() == 1) {
diff --git a/riscv/csrs.cc b/riscv/csrs.cc
index 6fdd6a3..7ea1e4f 100644
--- a/riscv/csrs.cc
+++ b/riscv/csrs.cc
@@ -548,13 +548,17 @@ bool mstatus_csr_t::unlogged_write(const reg_t val) noexcept {
| (has_page ? MSTATUS_TVM : 0)
| (has_gva ? MSTATUS_GVA : 0)
| (has_mpv ? MSTATUS_MPV : 0)
+ | (proc->extension_enabled(EXT_SMDBLTRP) ? MSTATUS_MDT : 0)
| (proc->extension_enabled(EXT_ZICFILP) ? (MSTATUS_SPELP | MSTATUS_MPELP) : 0)
| (proc->extension_enabled(EXT_SSDBLTRP) ? SSTATUS_SDT : 0)
;
const reg_t requested_mpp = proc->legalize_privilege(get_field(val, MSTATUS_MPP));
const reg_t adjusted_val = set_field(val, MSTATUS_MPP, requested_mpp);
- const reg_t new_mstatus = (read() & ~mask) | (adjusted_val & mask);
+ reg_t new_mstatus = (read() & ~mask) | (adjusted_val & mask);
+ if (new_mstatus & MSTATUS_MDT) {
+ new_mstatus = new_mstatus & ~MSTATUS_MIE;
+ }
maybe_flush_tlb(new_mstatus);
this->val = adjust_sd(new_mstatus);
return true;
@@ -569,6 +573,7 @@ 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)
+ | (proc->extension_enabled(EXT_SMDBLTRP) ? MSTATUS_MDT : 0)
| 0; // initial value for mstatus
}
@@ -1343,6 +1348,8 @@ dcsr_csr_t::dcsr_csr_t(processor_t* const proc, const reg_t addr):
halt(false),
v(false),
cause(0),
+ ext_cause(0),
+ cetrig(0),
pelp(elp_t::NO_LP_EXPECTED) {
}
@@ -1363,6 +1370,9 @@ reg_t dcsr_csr_t::read() const noexcept {
result = set_field(result, DCSR_STOPCOUNT, 0);
result = set_field(result, DCSR_STOPTIME, 0);
result = set_field(result, DCSR_CAUSE, cause);
+ result = set_field(result, DCSR_EXTCAUSE, ext_cause);
+ if (proc->extension_enabled(EXT_SMDBLTRP))
+ result = set_field(result, DCSR_CETRIG, cetrig);
result = set_field(result, DCSR_STEP, step);
result = set_field(result, DCSR_PRV, prv);
result = set_field(result, CSR_DCSR_V, v);
@@ -1382,12 +1392,14 @@ bool dcsr_csr_t::unlogged_write(const reg_t val) noexcept {
v = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_V) : false;
pelp = proc->extension_enabled(EXT_ZICFILP) ?
static_cast<elp_t>(get_field(val, DCSR_PELP)) : elp_t::NO_LP_EXPECTED;
+ cetrig = proc->extension_enabled(EXT_SMDBLTRP) ? get_field(val, DCSR_CETRIG) : false;
return true;
}
-void dcsr_csr_t::update_fields(const uint8_t cause, const reg_t prv,
+void dcsr_csr_t::update_fields(const uint8_t cause, uint8_t ext_cause, const reg_t prv,
const bool v, const elp_t pelp) noexcept {
this->cause = cause;
+ this->ext_cause = ext_cause;
this->prv = prv;
this->v = v;
this->pelp = pelp;
diff --git a/riscv/csrs.h b/riscv/csrs.h
index db61fba..4055d86 100644
--- a/riscv/csrs.h
+++ b/riscv/csrs.h
@@ -684,7 +684,7 @@ class dcsr_csr_t: public csr_t {
dcsr_csr_t(processor_t* const proc, const reg_t addr);
virtual void verify_permissions(insn_t insn, bool write) const override;
virtual reg_t read() const noexcept override;
- void update_fields(const uint8_t cause, const reg_t prv,
+ void update_fields(const uint8_t cause, const uint8_t ext_cause, const reg_t prv,
const bool v, const elp_t pelp) noexcept;
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
@@ -699,6 +699,8 @@ class dcsr_csr_t: public csr_t {
bool halt;
bool v;
uint8_t cause;
+ uint8_t ext_cause;
+ bool cetrig;
elp_t pelp;
};
diff --git a/riscv/encoding.h b/riscv/encoding.h
index 675b4f6..5f8eb7a 100644
--- a/riscv/encoding.h
+++ b/riscv/encoding.h
@@ -4,7 +4,7 @@
/*
* This file is auto-generated by running 'make' in
- * https://github.com/riscv/riscv-opcodes (c55d30f)
+ * https://github.com/riscv/riscv-opcodes (048218e)
*/
#ifndef RISCV_CSR_ENCODING_H
@@ -110,6 +110,9 @@
#define DCSR_CAUSE_STEP 4
#define DCSR_CAUSE_HALT 5
#define DCSR_CAUSE_GROUP 6
+#define DCSR_CAUSE_EXTCAUSE 7
+
+#define DCSR_EXTCAUSE_CRITERR 0
#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
@@ -117,7 +120,7 @@
#define MCONTROL_SELECT (1<<19)
#define MCONTROL_TIMING (1<<18)
-#define MCONTROL_ACTION (0x3f<<12)
+#define MCONTROL_ACTION (0xf<<12)
#define MCONTROL_CHAIN (1<<11)
#define MCONTROL_MATCH (0xf<<7)
#define MCONTROL_M (1<<6)
diff --git a/riscv/execute.cc b/riscv/execute.cc
index cc77d88..f4c88ca 100644
--- a/riscv/execute.cc
+++ b/riscv/execute.cc
@@ -213,12 +213,11 @@ void processor_t::step(size_t n)
{
if (!state.debug_mode) {
if (halt_request == HR_REGULAR) {
- enter_debug_mode(DCSR_CAUSE_DEBUGINT);
+ enter_debug_mode(DCSR_CAUSE_DEBUGINT, 0);
} else if (halt_request == HR_GROUP) {
- enter_debug_mode(DCSR_CAUSE_GROUP);
- }
- else if (state.dcsr->halt) {
- enter_debug_mode(DCSR_CAUSE_HALT);
+ enter_debug_mode(DCSR_CAUSE_GROUP, 0);
+ } else if (state.dcsr->halt) {
+ enter_debug_mode(DCSR_CAUSE_HALT, 0);
}
}
@@ -257,7 +256,7 @@ void processor_t::step(size_t n)
if (unlikely(!state.serialized && state.single_step == state.STEP_STEPPED)) {
state.single_step = state.STEP_NONE;
if (!state.debug_mode) {
- enter_debug_mode(DCSR_CAUSE_STEP);
+ enter_debug_mode(DCSR_CAUSE_STEP, 0);
// enter_debug_mode changed state.pc, so we can't just continue.
break;
}
@@ -286,6 +285,17 @@ void processor_t::step(size_t n)
disasm(fetch.insn);
pc = execute_insn_logged(this, pc, fetch);
advance_pc();
+
+ // Resume from debug mode in critical error
+ if (state.critical_error && !state.debug_mode) {
+ if (state.dcsr->read() & DCSR_CETRIG) {
+ enter_debug_mode(DCSR_CAUSE_EXTCAUSE, DCSR_EXTCAUSE_CRITERR);
+ } else {
+ // Handling of critical error is implementation defined
+ // For now just enter debug mode
+ enter_debug_mode(DCSR_CAUSE_HALT, 0);
+ }
+ }
}
}
else while (instret < n)
@@ -311,13 +321,23 @@ void processor_t::step(size_t n)
take_trap(t, pc);
n = instret;
+ // If critical error then enter debug mode critical error trigger enabled
+ if (state.critical_error) {
+ if (state.dcsr->read() & DCSR_CETRIG) {
+ enter_debug_mode(DCSR_CAUSE_EXTCAUSE, DCSR_EXTCAUSE_CRITERR);
+ } else {
+ // Handling of critical error is implementation defined
+ // For now just enter debug mode
+ enter_debug_mode(DCSR_CAUSE_HALT, 0);
+ }
+ }
// Trigger action takes priority over single step
auto match = TM.detect_trap_match(t);
if (match.has_value())
take_trigger_action(match->action, 0, state.pc, 0);
else if (unlikely(state.single_step == state.STEP_STEPPED)) {
state.single_step = state.STEP_NONE;
- enter_debug_mode(DCSR_CAUSE_STEP);
+ enter_debug_mode(DCSR_CAUSE_STEP, 0);
}
}
catch (triggers::matched_t& t)
@@ -330,7 +350,7 @@ void processor_t::step(size_t n)
}
catch(trap_debug_mode&)
{
- enter_debug_mode(DCSR_CAUSE_SWBP);
+ enter_debug_mode(DCSR_CAUSE_SWBP, 0);
}
catch (wait_for_interrupt_t &t)
{
diff --git a/riscv/insns/dret.h b/riscv/insns/dret.h
index 60aaf21..0f94f88 100644
--- a/riscv/insns/dret.h
+++ b/riscv/insns/dret.h
@@ -4,8 +4,16 @@ if (ZICFILP_xLPE(STATE.dcsr->v, STATE.dcsr->prv)) {
STATE.elp = STATE.dcsr->pelp;
}
p->set_privilege(STATE.dcsr->prv, STATE.dcsr->v);
-if (STATE.prv < PRV_M)
+if (STATE.prv < PRV_M) {
STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_MPRV);
+ STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_MDT);
+}
+
+if (STATE.dcsr->prv == PRV_U || STATE.dcsr->v)
+ STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_SDT);
+
+if (STATE.dcsr->v && STATE.dcsr->prv == PRV_U)
+ STATE.vsstatus->write(STATE.vsstatus->read() & ~SSTATUS_SDT);
if (STATE.dcsr->prv == PRV_U || STATE.dcsr->v)
STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_SDT);
diff --git a/riscv/insns/mret.h b/riscv/insns/mret.h
index 140ebde..4172b75 100644
--- a/riscv/insns/mret.h
+++ b/riscv/insns/mret.h
@@ -13,6 +13,7 @@ if (ZICFILP_xLPE(prev_virt, prev_prv)) {
STATE.elp = static_cast<elp_t>(get_field(s, MSTATUS_MPELP));
}
s = set_field(s, MSTATUS_MPELP, elp_t::NO_LP_EXPECTED);
+s = set_field(s, MSTATUS_MDT, 0);
if (prev_prv == PRV_U || prev_virt)
s = set_field(s, MSTATUS_SDT, 0);
if (prev_virt && prev_prv == PRV_U)
diff --git a/riscv/insns/sret.h b/riscv/insns/sret.h
index fe007d3..efb4fa6 100644
--- a/riscv/insns/sret.h
+++ b/riscv/insns/sret.h
@@ -26,6 +26,15 @@ if (!STATE.v) {
if (ZICFILP_xLPE(prev_virt, prev_prv)) {
STATE.elp = static_cast<elp_t>(get_field(s, SSTATUS_SPELP));
}
+
+if (STATE.prv == PRV_M) {
+ STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_MDT);
+ if (prev_prv == PRV_U || prev_virt)
+ STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_SDT);
+ if (prev_virt && prev_prv == PRV_U)
+ STATE.vsstatus->write(STATE.vsstatus->read() & ~SSTATUS_SDT);
+}
+
s = set_field(s, SSTATUS_SPELP, elp_t::NO_LP_EXPECTED);
if (STATE.prv == PRV_S) {
diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h
index 45f637c..12cc52e 100644
--- a/riscv/isa_parser.h
+++ b/riscv/isa_parser.h
@@ -82,6 +82,7 @@ typedef enum {
EXT_ZICFILP,
EXT_ZICFISS,
EXT_SSDBLTRP,
+ EXT_SMDBLTRP,
EXT_SMMPM,
EXT_SMNPM,
EXT_SSNPM,
diff --git a/riscv/processor.cc b/riscv/processor.cc
index d480f8f..0b318f5 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -159,6 +159,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
elp = elp_t::NO_LP_EXPECTED;
+ critical_error = false;
+
csr_init(proc, max_isa);
}
@@ -379,11 +381,11 @@ const char* processor_t::get_privilege_string()
abort();
}
-void processor_t::enter_debug_mode(uint8_t cause)
+void processor_t::enter_debug_mode(uint8_t cause, uint8_t extcause)
{
const bool has_zicfilp = extension_enabled(EXT_ZICFILP);
state.debug_mode = true;
- state.dcsr->update_fields(cause, state.prv, state.v, state.elp);
+ state.dcsr->update_fields(cause, extcause, state.prv, state.v, state.elp);
state.elp = elp_t::NO_LP_EXPECTED;
set_privilege(PRV_M, false);
state.dpc->write(state.pc);
@@ -500,10 +502,23 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
// Handle the trap in M-mode
const reg_t vector = (state.mtvec->read() & 1) && interrupt ? 4 * bit : 0;
const reg_t trap_handler_address = (state.mtvec->read() & ~(reg_t)1) + vector;
- // RNMI exception vector is implementation-defined. Since we don't model
// RNMI sources, the feature isn't very useful, so pick an invalid address.
+ // RNMI exception vector is implementation-defined. Since we don't model
const reg_t rnmi_trap_handler_address = 0;
const bool nmie = !(state.mnstatus && !get_field(state.mnstatus->read(), MNSTATUS_NMIE));
+
+ reg_t s = state.mstatus->read();
+ if ( extension_enabled(EXT_SMDBLTRP)) {
+ if (get_field(s, MSTATUS_MDT) || !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);
+ }
+
state.pc = !nmie ? rnmi_trap_handler_address : trap_handler_address;
state.mepc->write(epc);
state.mcause->write(supv_double_trap ? CAUSE_DOUBLE_TRAP : t.cause());
@@ -511,7 +526,6 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
state.mtval2->write(supv_double_trap ? t.cause() : t.get_tval2());
state.mtinst->write(t.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);
@@ -537,7 +551,7 @@ void processor_t::take_trigger_action(triggers::action_t action, reg_t breakpoin
switch (action) {
case triggers::ACTION_DEBUG_MODE:
- enter_debug_mode(DCSR_CAUSE_HWBP);
+ enter_debug_mode(DCSR_CAUSE_HWBP, 0);
break;
case triggers::ACTION_DEBUG_EXCEPTION: {
trap_breakpoint trap(virt, breakpoint_tval);
diff --git a/riscv/processor.h b/riscv/processor.h
index df77fc6..7744e86 100644
--- a/riscv/processor.h
+++ b/riscv/processor.h
@@ -190,6 +190,8 @@ struct state_t
elp_t elp;
+ bool critical_error;
+
private:
void csr_init(processor_t* const proc, reg_t max_isa);
};
@@ -405,7 +407,7 @@ private:
void register_insn(insn_desc_t, bool);
int paddr_bits();
- void enter_debug_mode(uint8_t cause);
+ void enter_debug_mode(uint8_t cause, uint8_t ext_cause);
void debug_output_log(std::stringstream *s); // either output to interactive user or write to log file