aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYenHaoChen <howard25336284@gmail.com>2023-04-12 15:35:43 +0800
committerYenHaoChen <howard25336284@gmail.com>2023-04-26 08:01:06 +0800
commit83c19daaf202e101e2a79109de4118a02f9d90a7 (patch)
tree334b80dbeea65d5d3c4a556b7c6bb02690a68032
parent0b52bb625556477865b2a77f47ae3ceacbc2cd5c (diff)
downloadriscv-isa-sim-83c19daaf202e101e2a79109de4118a02f9d90a7.zip
riscv-isa-sim-83c19daaf202e101e2a79109de4118a02f9d90a7.tar.gz
riscv-isa-sim-83c19daaf202e101e2a79109de4118a02f9d90a7.tar.bz2
triggers: native triggers (action=0) should prevent causing a breakpoint exception while already in a trap handler
This commit implements Debug Specification Section 5.4 Native Triggers. The specification allows two solutions for solving the reentrancy problem. This commit chooses the first solution because the second one targets implementations without S-mode.
-rw-r--r--riscv/triggers.cc21
-rw-r--r--riscv/triggers.h1
2 files changed, 19 insertions, 3 deletions
diff --git a/riscv/triggers.cc b/riscv/triggers.cc
index 07cd6bf..86dcc81 100644
--- a/riscv/triggers.cc
+++ b/riscv/triggers.cc
@@ -106,6 +106,21 @@ bool trigger_t::textra_match(processor_t * const proc) const noexcept
return true;
}
+bool trigger_t::allow_action(const state_t * const state) const
+{
+ if (get_action() == ACTION_DEBUG_EXCEPTION) {
+ const bool mstatus_mie = state->mstatus->read() & MSTATUS_MIE;
+ const bool sstatus_sie = state->sstatus->read() & MSTATUS_SIE;
+ const bool vsstatus_sie = state->vsstatus->read() & MSTATUS_SIE;
+ const bool medeleg_breakpoint = (state->medeleg->read() >> CAUSE_BREAKPOINT) & 1;
+ const bool hedeleg_breakpoint = (state->hedeleg->read() >> CAUSE_BREAKPOINT) & 1;
+ return (state->prv != PRV_M || mstatus_mie) &&
+ (state->prv != PRV_S || state->v || !medeleg_breakpoint || sstatus_sie) &&
+ (state->prv != PRV_S || !state->v || !medeleg_breakpoint || !hedeleg_breakpoint || vsstatus_sie);
+ }
+ return true;
+}
+
reg_t disabled_trigger_t::tdata1_read(const processor_t * const proc) const noexcept
{
auto xlen = proc->get_xlen();
@@ -212,7 +227,7 @@ std::optional<match_result_t> mcontrol_common_t::detect_memory_access_match(proc
value &= 0xffffffff;
}
- if (simple_match(xlen, value)) {
+ if (simple_match(xlen, value) && allow_action(proc->get_state())) {
/* This is OK because this function is only called if the trigger was not
* inhibited by the previous trigger in the chain. */
hit = true;
@@ -289,7 +304,7 @@ void mcontrol6_t::tdata1_write(processor_t * const proc, const reg_t val, const
std::optional<match_result_t> icount_t::detect_icount_match(processor_t * const proc) noexcept
{
- if (!common_match(proc))
+ if (!common_match(proc) || !allow_action(proc->get_state()))
return std::nullopt;
std::optional<match_result_t> ret = std::nullopt;
@@ -389,7 +404,7 @@ std::optional<match_result_t> trap_common_t::detect_trap_match(processor_t * con
bool interrupt = (t.cause() & ((reg_t)1 << (xlen - 1))) != 0;
reg_t bit = t.cause() & ~((reg_t)1 << (xlen - 1));
assert(bit < xlen);
- if (simple_match(interrupt, bit)) {
+ if (simple_match(interrupt, bit) && allow_action(proc->get_state())) {
hit = true;
return match_result_t(TIMING_AFTER, action);
}
diff --git a/riscv/triggers.h b/riscv/triggers.h
index 0c9dabc..6e3d74d 100644
--- a/riscv/triggers.h
+++ b/riscv/triggers.h
@@ -90,6 +90,7 @@ public:
protected:
static action_t legalize_action(reg_t val, reg_t action_mask, reg_t dmode_mask) noexcept;
bool common_match(processor_t * const proc) const noexcept;
+ bool allow_action(const state_t * const state) const;
reg_t tdata2;
bool vs = false;