Skip to content

Commit

Permalink
Introduce pre_val MIP concept.
Browse files Browse the repository at this point in the history
When Ibex is executing an instruction it is possible for MIP to change
whilst that instruction is stalled in the ID/EX stage. This results in
the MIP observed by a CSR instruction differing from the MIP that
decides whether or not that instruction may be interrupted which leads
to model mis-matches.

This adds a new MIP 'pre_val' which is the MIP value used to determine
whether or not an interrupt is taken. The existing value is the one
observed by CSR instructions. Employing this mechanism avoids the
mis-matches described above.
  • Loading branch information
GregAC committed Jul 2, 2024
1 parent 1f89c52 commit 39612f9
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 1 deletion.
8 changes: 8 additions & 0 deletions riscv/csrs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,14 @@ void mip_csr_t::backdoor_write_with_mask(const reg_t mask, const reg_t val) noex
this->val = (this->val & ~mask) | (val & mask);
}

reg_t mip_csr_t::read_pre_val() const noexcept {
return pre_val;
}

void mip_csr_t::write_pre_val(const reg_t val) noexcept {
pre_val = val;
}

reg_t mip_csr_t::write_mask() const noexcept {
const reg_t supervisor_ints = proc->extension_enabled('S') ? MIP_SSIP | MIP_STIP | MIP_SEIP : 0;
const reg_t vssip_int = proc->extension_enabled('H') ? MIP_VSSIP : 0;
Expand Down
11 changes: 11 additions & 0 deletions riscv/csrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,9 +341,20 @@ class mip_or_mie_csr_t: public csr_t {
class mip_csr_t: public mip_or_mie_csr_t {
public:
mip_csr_t(processor_t* const proc, const reg_t addr);
virtual reg_t read_pre_val() const noexcept;
// The pre_val of MIP is used to determine if an interrupt will be taken at
// the beginning of an instruction step. Whilst the actual CSR value is the
// one accessed by any CSR instruction that may be executed.
//
// Nothing updates the value to become the pre_val. This is designed for use
// with co-simulation where the co-simulation environment is expected to do
// suitable value and pre_val updates before every step.
virtual void write_pre_val(const reg_t val) noexcept;

// Does not log. Used by external things (clint) that wiggle bits in mip.
void backdoor_write_with_mask(const reg_t mask, const reg_t val) noexcept;
protected:
reg_t pre_val;
private:
virtual reg_t write_mask() const noexcept override;
};
Expand Down
6 changes: 5 additions & 1 deletion riscv/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,11 @@ class processor_t : public abstract_device_t
throw trap_t(((reg_t)1 << get_isa().get_max_xlen()) - 1 - NMI_INTERRUPT_NUM);
}

take_interrupt(state.mip->read() & state.mie->read());
// Interrupt is based on the 'pre_val' of MIP which is set by the
// co-simulation environment. This can differ from the actual value which is
// what is observed by CSR instructions. This models the case where the MIP
// changes whilst an instruction is stalled in the ID/EX stage.
take_interrupt(state.mip->read_pre_val() & state.mie->read());
}
void take_interrupt(reg_t mask); // take first enabled interrupt in mask
void take_trap(trap_t& t, reg_t epc); // take an exception
Expand Down

0 comments on commit 39612f9

Please sign in to comment.