aboutsummaryrefslogtreecommitdiff
path: root/riscv/execute.cc
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2016-08-22 09:49:20 -0700
committerTim Newsome <tim@sifive.com>2016-08-22 09:49:20 -0700
commitd6dae451821656d7676fec3ec515691d4c66e065 (patch)
treeab8d1a8129710b380147cefc44e97c4dad28425b /riscv/execute.cc
parent5e1d0059353a4756740df709f85c35ee86138ad6 (diff)
downloadspike-d6dae451821656d7676fec3ec515691d4c66e065.zip
spike-d6dae451821656d7676fec3ec515691d4c66e065.tar.gz
spike-d6dae451821656d7676fec3ec515691d4c66e065.tar.bz2
Implement address and data triggers.
So far I only have testcases for instruction and data address. Not implemented is the mechanism that lets the debugger prevent a user program from using triggers at all. I'll be adding that soonish. The critical path is unchanged, but my experimenting shows the simulation is slowed down about 8% by this code. Reducing the size of trigger_match() (which is never called during my benchmark) fixes that, but making it not be inlined has no effect. I suspect the slowdown comes from cache alignment or something similar, and on a different CPU or after more code changes the speed will come back.
Diffstat (limited to 'riscv/execute.cc')
-rw-r--r--riscv/execute.cc34
1 files changed, 32 insertions, 2 deletions
diff --git a/riscv/execute.cc b/riscv/execute.cc
index 20567af..3d5625f 100644
--- a/riscv/execute.cc
+++ b/riscv/execute.cc
@@ -51,6 +51,13 @@ static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch)
return npc;
}
+void processor_t::update_slow_path()
+{
+ slow_path = debug || state.single_step != state.STEP_NONE || state.dcsr.cause;
+ if (slow_path)
+ return;
+}
+
// fetch/decode/execute loop
void processor_t::step(size_t n)
{
@@ -90,8 +97,7 @@ void processor_t::step(size_t n)
{
take_interrupt();
- // When we might single step, use the slow loop instead of the fast one.
- if (unlikely(debug || state.single_step != state.STEP_NONE || state.dcsr.cause))
+ if (unlikely(slow_path))
{
while (instret < n)
{
@@ -150,6 +156,30 @@ miss:
take_trap(t, pc);
n = instret;
}
+ catch (trigger_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;
+ }
+ assert(state.mcontrol[t.index].action != ACTION_NONE);
+ switch (state.mcontrol[t.index].action) {
+ case ACTION_DEBUG_MODE:
+ enter_debug_mode(DCSR_CAUSE_HWBP);
+ break;
+ default:
+ assert(0);
+ }
+ }
state.minstret += instret;
n -= instret;