aboutsummaryrefslogtreecommitdiff
path: root/riscv
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2022-10-06 17:40:41 -0700
committerAndrew Waterman <andrew@sifive.com>2022-10-06 19:30:40 -0700
commit7b8114f707a7b2de9fd2d393b9d019180de83025 (patch)
treedc4c83a2ab0e7050758214025c15991f9e78a5eb /riscv
parentfd50768df9ec4d9f80c6a37d89734d9e27443f6b (diff)
downloadspike-7b8114f707a7b2de9fd2d393b9d019180de83025.zip
spike-7b8114f707a7b2de9fd2d393b9d019180de83025.tar.gz
spike-7b8114f707a7b2de9fd2d393b9d019180de83025.tar.bz2
Don't use reexecution as the means to implement trigger-after
The scheme was based on the notion that memory accesses are idempotent up until the point the trigger would've been hit, which isn't true in the case of side-effecting loads and data-value triggers. Instead, check the trigger on the next instruction fetch. To keep the perf overhead minimal, perform this check on the I$ refill path, and ensure that path is taken by flushing the I$.
Diffstat (limited to 'riscv')
-rw-r--r--riscv/execute.cc9
-rw-r--r--riscv/mmu.cc5
-rw-r--r--riscv/mmu.h3
3 files changed, 7 insertions, 10 deletions
diff --git a/riscv/execute.cc b/riscv/execute.cc
index 5d24ce8..f0bb946 100644
--- a/riscv/execute.cc
+++ b/riscv/execute.cc
@@ -309,15 +309,6 @@ void processor_t::step(size_t n)
catch (triggers::matched_t& t)
{
if (mmu->matched_trigger) {
- // This exception came from the MMU. That means the instruction hasn't
- // fully executed yet. We start it again, but this time it won't throw
- // an exception because matched_trigger is already set. (All memory
- // instructions are idempotent so restarting is safe.)
-
- insn_fetch_t fetch = mmu->load_insn(pc);
- pc = execute_insn(this, pc, fetch);
- advance_pc();
-
delete mmu->matched_trigger;
mmu->matched_trigger = NULL;
}
diff --git a/riscv/mmu.cc b/riscv/mmu.cc
index b8690ec..fdad05f 100644
--- a/riscv/mmu.cc
+++ b/riscv/mmu.cc
@@ -165,8 +165,11 @@ void mmu_t::check_triggers(triggers::operation_t operation, reg_t address, bool
throw triggers::matched_t(operation, address, data, action);
case triggers::MATCH_FIRE_AFTER:
+ // We want to take this exception on the next instruction. We check
+ // whether to do so in the I$ refill path, so flush the I$.
+ flush_icache();
matched_trigger = new triggers::matched_t(operation, address, data, action);
- throw *matched_trigger;
+ return;
}
}
diff --git a/riscv/mmu.h b/riscv/mmu.h
index 8eeea31..01e74ef 100644
--- a/riscv/mmu.h
+++ b/riscv/mmu.h
@@ -247,6 +247,9 @@ public:
inline icache_entry_t* refill_icache(reg_t addr, icache_entry_t* entry)
{
+ if (matched_trigger)
+ throw *matched_trigger;
+
auto tlb_entry = translate_insn_addr(addr);
insn_bits_t insn = from_le(*(uint16_t*)(tlb_entry.host_offset + addr));
int length = insn_length(insn);