diff options
| author | Prashanth Mundkur | 2018-04-18 16:58:21 -0700 |
|---|---|---|
| committer | Prashanth Mundkur | 2018-04-18 16:58:21 -0700 |
| commit | ae7fbb4ce5f5e52ec39ca17b152db63bbd0cfc69 (patch) | |
| tree | 29821a7fc0c8113f8efacfc4696e8644cf34bb7a | |
| parent | 2bf408e37eabfa0dfb7cee5165a4208de5846b9e (diff) | |
Add interrupt prioritization and delegation.
| -rw-r--r-- | riscv/riscv_sys.sail | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/riscv/riscv_sys.sail b/riscv/riscv_sys.sail index 37c487cf..fc58d72e 100644 --- a/riscv/riscv_sys.sail +++ b/riscv/riscv_sys.sail @@ -461,7 +461,7 @@ function check_CSR(csr : csreg, p : Privilege, isWrite : bool) -> bool = & check_CSR_access(csrAccess(csr), csrPriv(csr), p, isWrite) & check_TVM_SATP(csr, p) -/* exception delegation: given an exception and the privilege at which +/* Exception delegation: given an exception and the privilege at which * it occured, returns the privilege at which it should be handled. */ function exception_delegatee(e : ExceptionType, p : Privilege) -> Privilege = { @@ -477,6 +477,48 @@ function exception_delegatee(e : ExceptionType, p : Privilege) -> Privilege = { then p else deleg } +/* Interrupts are prioritized in privilege order, and for each + * privilege, in the order: external, software, timers. + */ +function findPendingInterrupt(ip : xlenbits) -> option(InterruptType) = { + let ip = Mk_Minterrupts(ip); + if ip.MEI() == true then Some(I_M_External) + else if ip.MSI() == true then Some(I_M_Software) + else if ip.MTI() == true then Some(I_M_Timer) + else if ip.SEI() == true then Some(I_S_External) + else if ip.SSI() == true then Some(I_S_Software) + else if ip.STI() == true then Some(I_S_Timer) + else if ip.UEI() == true then Some(I_U_External) + else if ip.USI() == true then Some(I_U_Software) + else if ip.UTI() == true then Some(I_U_Timer) + else None() +} + +/* Examines current M-mode interrupt state and returns an interrupt to be + * handled, and the privilege it should be handled at. + * For now, it assumes 'S' and no 'N' extension, which is the common case. + */ +function curInterrupt(pend : Minterrupts, enbl : Minterrupts, delg : Minterrupts) + -> option((InterruptType, Privilege)) = { + let en_mip : xlenbits = pend.bits() & enbl.bits(); + if en_mip == EXTZ(0b0) then None() /* fast path */ + else { + let eff_mip = en_mip & (~ (delg.bits())); /* retained at M-mode */ + let eff_sip = en_mip & delg.bits(); /* delegated to S-mode */ + if (mstatus.MIE() == true) & (eff_mip != EXTZ(0b0)) + then match findPendingInterrupt(eff_mip) { + Some(i) => let r = (i, Machine) in Some(r), + None() => None() + } + else if (mstatus.SIE() == true) & (eff_sip != EXTZ(0b0)) + then match findPendingInterrupt(eff_sip) { + Some(i) => let r = (i, Supervisor) in Some(r), + None() => None() + } + else None() + } +} + /* instruction control flow */ struct sync_exception = { |
