Browse Source

triggers: add itrigger_t

add module_t::trap_taking_match and trigger_t::trap_taking_match for
checking itrigger after taking traps
pull/1128/head
YenHaoChen 4 years ago
parent
commit
8ffff21ac6
  1. 2
      README.md
  2. 6
      riscv/execute.cc
  3. 74
      riscv/triggers.cc
  4. 24
      riscv/triggers.h

2
README.md

@ -38,7 +38,7 @@ Spike supports the following RISC-V ISA features:
- Svpbmt extension, v1.0
- Svinval extension, v1.0
- Debug v0.14
- 4 triggers support type=2 (mcontrol) and type=15 (disabled)
- 4 triggers support type=2 (mcontrol), type=4 (itrigger), and type=15 (disabled)
- Smepmp extension v1.0
- Smstateen extension, v1.0
- Sscofpmf v0.5.2

6
riscv/execute.cc

@ -301,7 +301,11 @@ void processor_t::step(size_t n)
take_trap(t, pc);
n = instret;
if (unlikely(state.single_step == state.STEP_STEPPED)) {
// Trigger action takes priority over single step
triggers::match_result_t match = TM.detect_trap_match(t);
if (match.fire)
take_trigger_action(match.action, 0, state.pc);
else if (unlikely(state.single_step == state.STEP_STEPPED)) {
state.single_step = state.STEP_NONE;
enter_debug_mode(DCSR_CAUSE_STEP);
}

74
riscv/triggers.cc

@ -148,6 +148,62 @@ match_result_t mcontrol_t::memory_access_match(processor_t * const proc, operati
return match_result_t(false);
}
reg_t itrigger_t::tdata1_read(const processor_t * const proc) const noexcept
{
auto xlen = proc->get_xlen();
reg_t tdata1 = 0;
tdata1 = set_field(tdata1, CSR_ITRIGGER_TYPE(xlen), CSR_TDATA1_TYPE_ITRIGGER);
tdata1 = set_field(tdata1, CSR_ITRIGGER_DMODE(xlen), dmode);
tdata1 = set_field(tdata1, CSR_ITRIGGER_HIT(xlen), hit);
tdata1 = set_field(tdata1, CSR_ITRIGGER_VS, proc->extension_enabled('H') ? vs : 0);
tdata1 = set_field(tdata1, CSR_ITRIGGER_VU, proc->extension_enabled('H') ? vu : 0);
tdata1 = set_field(tdata1, CSR_ITRIGGER_NMI, nmi);
tdata1 = set_field(tdata1, CSR_ITRIGGER_M, m);
tdata1 = set_field(tdata1, CSR_ITRIGGER_S, s);
tdata1 = set_field(tdata1, CSR_ITRIGGER_U, u);
tdata1 = set_field(tdata1, CSR_ITRIGGER_ACTION, action);
return tdata1;
}
void itrigger_t::tdata1_write(processor_t * const proc, const reg_t val, const bool UNUSED allow_chain) noexcept
{
auto xlen = proc->get_xlen();
assert(get_field(val, CSR_ITRIGGER_TYPE(xlen)) == CSR_TDATA1_TYPE_ITRIGGER);
dmode = get_field(val, CSR_ITRIGGER_DMODE(xlen));
hit = get_field(val, CSR_ITRIGGER_HIT(xlen));
vs = get_field(val, CSR_ITRIGGER_VS);
vu = get_field(val, CSR_ITRIGGER_VU);
nmi = get_field(val, CSR_ITRIGGER_NMI);
m = get_field(val, CSR_ITRIGGER_M);
s = proc->extension_enabled_const('S') ? get_field(val, CSR_ITRIGGER_S) : 0;
u = proc->extension_enabled_const('U') ? get_field(val, CSR_ITRIGGER_U) : 0;
action = (action_t)get_field(val, CSR_ITRIGGER_ACTION);
if (action > ACTION_MAXVAL || (action==ACTION_DEBUG_MODE && dmode==0))
action = ACTION_DEBUG_EXCEPTION;
}
match_result_t itrigger_t::detect_trap_match(processor_t * const proc, const trap_t& t)
{
state_t * const state = proc->get_state();
if ((state->prv == PRV_M && !m) ||
(!state->v && state->prv == PRV_S && !s) ||
(!state->v && state->prv == PRV_U && !u) ||
(state->v && state->prv == PRV_S && !vs) ||
(state->v && state->prv == PRV_U && !vu)) {
return match_result_t(false);
}
auto xlen = proc->get_xlen();
bool interrupt = (t.cause() & ((reg_t)1 << (xlen - 1))) != 0;
reg_t bit = t.cause() & ~((reg_t)1 << (xlen - 1));
assert(bit < xlen);
if (interrupt && ((bit == 0 && nmi) || ((tdata2 >> bit) & 1))) { // Assume NMI's exception code is 0
hit = true;
return match_result_t(true, TIMING_AFTER, action);
}
return match_result_t(false);
}
module_t::module_t(unsigned count) : triggers(count) {
for (unsigned i = 0; i < count; i++) {
triggers[i] = new disabled_trigger_t();
@ -187,12 +243,14 @@ bool module_t::tdata1_write(processor_t * const proc, unsigned index, const reg_
// dmode only writable from debug mode
if (!proc->get_state()->debug_mode) {
assert(CSR_TDATA1_DMODE(xlen) == CSR_MCONTROL_DMODE(xlen));
assert(CSR_TDATA1_DMODE(xlen) == CSR_ITRIGGER_DMODE(xlen));
tdata1 = set_field(tdata1, CSR_TDATA1_DMODE(xlen), 0);
}
delete triggers[index];
switch (type) {
case CSR_TDATA1_TYPE_MCONTROL: triggers[index] = new mcontrol_t(); break;
case CSR_TDATA1_TYPE_ITRIGGER: triggers[index] = new itrigger_t(); break;
default: triggers[index] = new disabled_trigger_t(); break;
}
@ -246,10 +304,24 @@ match_result_t module_t::memory_access_match(operation_t operation, reg_t addres
return match_result_t(false);
}
match_result_t module_t::detect_trap_match(const trap_t& t)
{
state_t * const state = proc->get_state();
if (state->debug_mode)
return match_result_t(false);
for (auto trigger: triggers) {
match_result_t result = trigger->detect_trap_match(proc, t);
if (result.fire)
return result;
}
return match_result_t(false);
}
reg_t module_t::tinfo_read(UNUSED const processor_t * const proc, unsigned UNUSED index) const noexcept
{
/* In spike, every trigger supports the same types. */
return (1 << CSR_TDATA1_TYPE_MCONTROL) | (1 << CSR_TDATA1_TYPE_DISABLED);
return (1 << CSR_TDATA1_TYPE_MCONTROL) | (1 << CSR_TDATA1_TYPE_ITRIGGER) | (1 << CSR_TDATA1_TYPE_DISABLED);
}
};

24
riscv/triggers.h

@ -69,6 +69,7 @@ public:
virtual match_result_t memory_access_match(processor_t UNUSED * const proc,
operation_t UNUSED operation, reg_t UNUSED address, std::optional<reg_t> UNUSED data) { return match_result_t(false); }
virtual match_result_t detect_trap_match(processor_t UNUSED * const proc, const trap_t UNUSED & t) { return match_result_t(false); }
};
class trigger_with_tdata2_t : public trigger_t {
@ -91,6 +92,28 @@ private:
bool dmode;
};
class itrigger_t : public trigger_with_tdata2_t {
public:
virtual reg_t tdata1_read(const processor_t * const proc) const noexcept override;
virtual void tdata1_write(processor_t * const proc, const reg_t val, const bool allow_chain) noexcept override;
bool get_dmode() const override { return dmode; }
virtual action_t get_action() const override { return action; }
virtual match_result_t detect_trap_match(processor_t * const proc, const trap_t& t) override;
private:
bool dmode;
bool hit;
bool vs;
bool vu;
bool nmi;
bool m;
bool s;
bool u;
action_t action;
};
class mcontrol_t : public trigger_with_tdata2_t {
public:
typedef enum
@ -148,6 +171,7 @@ public:
unsigned count() const { return triggers.size(); }
match_result_t memory_access_match(operation_t operation, reg_t address, std::optional<reg_t> data);
match_result_t detect_trap_match(const trap_t& t);
processor_t *proc;
private:

Loading…
Cancel
Save