A plan for developing the riscv architectural tests for the Fast Interrupt Extension.
The point of this test plan is to:
-
Explain what the RISC-V architectural tests try to achieve, both generally and for the fast interrupt architecture in particular.
-
Act as a starting point for verification engineers writing verification plans.
Some useful links:
The framework for architectural tests is to load a test (binary) and start a hart, the hart signals finished, results are extraced from memory and verified against a signature. Since interrupts can occur asynchronously it is limiting to create deterministic tests for different implementations with results that can be compared with SAIL model results. For example, with different implementation, a different number of instructions will occur before the pending interrupt bit actually gets set. Depending on the implementation, the execution pc could be a different value than the SAIL model. The following deterministic test sequences are only designed to test understanding and expected behavior of the CLIC spec.
A PR request has been made at riscv-arch-test: riscv-non-isa/riscv-arch-test#436
smclic testcases work for implementations that support m-mode.
generic test pseudo code that is used by most clic tests to stimulate different behavior. anything in ALL_CAPS are defines that can be overwritten with -D or at top of test or in model_test.h
/* to stimulate different test behavior using the same generic test pseudo code, individual tests will #define different default values here */ #include "model_test.h" #include "arch_test.h" current mtvec/mscratch saved (used by arch_test.h so needs to be restored at end of test) RVMODEL_SETUP_CLIC /* hook to allow implementations to setup their setup required for their specific CLIC implementation (num priv modes, num interrupt levels) */ program mintthresh to RVMODEL_MINTTHRESH program interrupt1 CLICINTCTL/CLICINTATTR values (based on RVMODEL_INT1_EXCCODE, RVMODEL_INT1_CLICINTCTL, RVMODEL_INT1_CLICINTATTR defines) program interrupt2 CLICINTCTL/CLICINTATTR values (based on RVMODEL_INT2_EXCCODE, RVMODEL_INT2_CLICINTCTL, RVMODEL_INT2_CLICINTATTR defines) program interrupt1/2 CLICINTIE (based on RVMODEL_INT1_CLICINTIE, RVMODEL_INT2_CLICINTIE) RVMODEL_SET_INT1 fence switch priv_mode to RVMODEL_CLIC_STARTING_PRIV set mstatus.mie to RVMODEL_MSTATUS_MIE RVMODEL_WFI finish /* e.g. if RVMODEL_SET_INT1 is defined to actually not set interrupt1, or interrupt level is 0, or interrupt priv is < current_priv), all signatures would stay default */ m_interrupt_handler1: save signatures /* mcause, mstatus, mepc, mtval, mintstatus, mintthresh, mnxti, mscratch, mscratchcsw, mscratchcswl */ modify mtvec/mtvt to point to interrupt handler2: RVMODEL_CLEAR_INT1 RVMODEL_SET_INT2 csrrsi t0, mnxti RVMODEL_MNXTI_SIMMED set mstatus.mie to RVMODEL_MSTATUS_MIE /* e.g. if RVMODEL_CLEAR_INT1 was defined to actually not clear interrupt1, interrupt1 is still asserted, clint would preempt and jump to interrupt handler2, clic does not */ modify mepc to jump to finsh csrrci t0, mnxti RVMODEL_MNXTI_CIMMED save signatures /* mcause, mstatus, mepc, mtval, mintstatus, mintthresh, mnxti, mscratch, mscratchcsw, mscratchcswl */ mret m_interrupt_handler2: save signatures /* mcause, mstatus, mepc, mtval, mintstatus, mintthresh, mnxti, mscratch, mscratchcsw, mscratchcswl */ RVMODEL_CLEAR_INT2 clear mstatus.mpie (so mstatus.mie is 0 after mret) mret finish: restore mtvec, mscratch for arch_test.h
smclic tests TEST PLAN CASES Defaults:
RVMODEL_INT1_EXCCODE = 0 RVMODEL_INT2_EXCCODE = 3 RVMODEL_INT1_CLICINTIE = 1 RVMODEL_INT2_CLICINTIE = 1 RVMODEL_MSTATUS_MIE = 1 RVMODEL_MNXTI_SIMMED = 0x8 RVMODEL_MNXTI_CIMMED = 0x8 RVMODEL_WFI nop
-
enable clicintie (default)
-
generate interrupt1
-
nop
-
jump to finish
RVMODEL_MSTATUS_MIE = 0 RVMODEL_SET_INT1 = RVMODEL_SET_MSW_INT RVMODEL_SET_INT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_INT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_CLEAR_INT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_WFI = nop
Coverage
mstatus.mie | verify no interrupt occurs in m-mode if mstatus.mie is 0
-
disable clicintie
-
generate interrupt1
-
enable mstatus.mie
-
nop
-
jump to finish
RVMODEL_INT1_CLICINTIE = 0 RVMODEL_INT2_CLICINTIE = 0 RVMODEL_SET_INT1 = RVMODEL_SET_MSW_INT RVMODEL_SET_INT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_INT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_CLEAR_INT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_WFI = nop
Coverage
clicintie[msw] | verify no msw interrupt occurs if clicintie[msw] is 0 clicintie[mtimer] | verify no mtimer interrupt occurs if clicintie[mtimer] is 0
-
enable clicintie (default)
-
generate interrupt1
-
enable mstatus.mie
-
nop
-
jump to finish
RVMODEL_MINTTHRESH = RVMODEL_MINTTHRESH_MAX RVMODEL_SET_INT1 = RVMODEL_SET_MSW_INT RVMODEL_SET_INT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_INT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_CLEAR_INT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_WFI = nop
Coverage
mintthresh | verify no msw interrupt occurs if mintthresh is max
-
enable clicintie (default)
-
generate interrupt1
-
wfi
-
wakeup
-
jump to finish
RVMODEL_MSTATUS_MIE = 0 RVMODEL_SET_INT1 = RVMODEL_SET_MSW_INT RVMODEL_SET_INT2 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_INT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_CLEAR_INT2 = RVMODEL_CLEAR_MSW_INT
Coverage
mstatus.mie | verify no interrupt occurs in m-mode if mstatus.mie is 0 wfi | verify wakeup/nop occurs with mstatus.mie = 0 wfi | verify wakeup/nop occurs with pending interrupt
-
enable clicintie (default)
-
generate interrupt1
-
enable mstatus.mie
-
trigger m-mode handler
-
clear 1st interrupt
-
generate interrupt1 again (ignored)
-
set mepc to finish
-
mret to finish
RVMODEL_SET_INT1 = RVMODEL_SET_MSW_INT RVMODEL_SET_INT2 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_INT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_CLEAR_INT2 = RVMODEL_CLEAR_MSW_INT RVMODEL_MINTTHRESH = RVMODEL_MINTTHRESH_MIN RVMODEL_WFI = jump_to_self
Coverage
mtvec.mode | verify direct mode is used to handle interrupt no msip retrigger | verify after mstatus.mie is enabled in interrupt handler, msip will not retrigger because msip intlevel is not > mintstatus msip trigger | verify RVMODEL_SET_MSW_INT trigger msip clear | verify RVMODEL_CLEAR_MSW_INT clear mcause | verify machine software interrupt signature mstatus | verify mstatus.mie/mpie/mpp signature in interrupt handler and after mret mtvec | verify interrupt uses mtvec to calculate pc of interrupt handler (direct) mepc | verify mepc location is jump_to_self location
-
enable clicintie (default)
-
generate interrupt 1
-
enable mstatus.mie
-
trigger m-mode handler
-
generate interrupt 2 (both interrupts now pending)
-
if clicintctrl represents levels, mnxti csrrsi updates mcause.id for 2nd interrupt
-
if clicintctrl represents priority, no 2nd interrupt occurs.
-
set mepc to finish
-
clear mstatus.mpie
-
mret to finish
RVMODEL_SET_INT1 = RVMODEL_SET_MSW_INT RVMODEL_SET_INT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_INT1 = <EMPTY> RVMODEL_CLEAR_INT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_INT1_CLICINTCTL = RVMODEL_CLICINTCTL_MIN RVMODEL_INT2_CLICINTCTL = RVMODEL_CLICINTCTL_MAX
Coverage
Interrupt ordering - both interrupts asserted in first interrupt handler
-
enable clicintie (default)
-
generate interrupt 1
-
enable mstatus.mie
-
trigger m-mode handler
-
generate interrupt 2 (both interrupts now pending)
-
if clicintctrl represents levels, trigger 2nd m-mode handler
-
if clicintctrl represents priority, no 2nd interrupt occurs.
-
set mepc to finish
-
clear mstatus.mpie
-
mret to finish
RVMODEL_SET_INT1 = RVMODEL_SET_MSW_INT RVMODEL_SET_INT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_INT1 = <EMPTY> RVMODEL_CLEAR_INT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_INT1_CLICINTCTL = RVMODEL_CLICINTCTL_MIN RVMODEL_INT2_CLICINTCTL = RVMODEL_CLICINTCTL_MAX RVMODEL_MNXTI_SIMMED = 0
Coverage
Interrupt ordering - both interrupts asserted in first interrupt handler
-
enable clicintie (default)
-
generate interrupt 1
-
enable mstatus.mie
-
trigger m-mode handler
-
generate interrupt 2 (both interrupts now pending)
-
if clicintctrl represents levels, 2nd interrupt is lower than current interupt level, no 2nd interrupt occurs.
-
if clicintctrl represents priority, 2nd interrupt is same level, no 2nd interrupt occurs.
-
set mepc to finish
-
clear mstatus.mpie
-
mret to finish
RVMODEL_SET_INT1 = RVMODEL_SET_MSW_INT RVMODEL_SET_INT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_INT1 = <EMPTY> RVMODEL_CLEAR_INT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_INT1_CLICINTCTL = RVMODEL_CLICINTCTL_MAX RVMODEL_INT2_CLICINTCTL = RVMODEL_CLICINTCTL_MIN
Coverage
Interrupt ordering - both interrupts asserted in first interrupt handler
-
enable clicintie (default)
-
generate interrupt 1
-
enable mstatus.mie
-
trigger m-mode handler
-
generate interrupt 2 (both interrupts now pending)
-
if clicintctrl represents levels, 2nd interrupt is higher than current interupt level but equal to mintthresh, no 2nd interrupt occurs.
-
if clicintctrl represents priority, 2nd interrupt is same level, no 2nd interrupt occurs.
-
set mepc to finish
-
clear mstatus.mpie
-
mret to finish
RVMODEL_SET_INT1 = RVMODEL_SET_MSW_INT RVMODEL_SET_INT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_INT1 = <EMPTY> RVMODEL_CLEAR_INT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_INT1_CLICINTCTL = RVMODEL_CLICINTCTL_MIN RVMODEL_INT2_CLICINTCTL = RVMODEL_CLICINTCTL_MAX RVMODEL_MINTTHRESH_HNDLR1 = RVMODEL_MINTTHRESH_MAX
Coverage
Interrupt ordering - both interrupts asserted in first interrupt handler
-
generate m-mode interrupt (msw)
-
switch to s-mode (mstatus.mie disabled),
-
trigger (m-mode handler),
-
clear interrupt,
-
return to s-mode,
-
ecall back to m-mode
RVMODEL_MSTATUS_MIE = 0 RVMODEL_SET_MINT1 = RVMODEL_SET_MSW_INT; RVMODEL_CLEAR_MINT1 = RVMODEL_CLEAR_MSW_INT; RVMODEL_MINTTHRESH = RVMODEL_MINTTHRESH_MAX
Coverage
clicintattr[msw].mode == 11 | verify interrupt is handled in m-mode mstatus.mie=0 | verify m-mode interrupt will occur in s-mode when mstatus.mie=0 mcause signature | verify msw cause signature
-
generate s-mode interrupt (sint1),
-
switch to s-mode,
-
trigger (s-mode handler),
-
clear interrupt,
-
ecall back to m-mode
RVMODEL_MSTATUS_MIE = MSTATUS_SIE RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_SINT1_EXCCODE = 0x3
Coverage
clicintattr[sint1].mode == 01 | verify interrupt is handled in s-mode mstatus.sie=1 | verify s-mode interrupt will occur in s-mode when mstatus.sie=1 scause signature | verify msw signature mcause signature | verify ecall signature
-
generate 2 s-mode interrupts (msw, mtimer),
-
switch to s-mode,
-
trigger (s-mode handler),
-
clear interrupts,
-
ecall back to m-mode
RVMODEL_MSTATUS_MIE = MSTATUS_SIE RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_SINT2_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_SINT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_SINT1_CLICINTCTL = RVMODEL_CLICINTCTL_MAX RVMODEL_SINT2_CLICINTCTL = RVMODEL_CLICINTCTL_MIN RVMODEL_SINT1_EXCCODE = 0x3 RVMODEL_SINT2_EXCCODE = 0x7
Coverage
scause signature | verify priority of int1/int2
-
generate 2 s-mode interrupts (msw, mtimer),
-
switch to s-mode,
-
trigger (s-mode handler),
-
only sint1 is cleared,
-
re-enable mstatus.sie
-
trigger (go to stvec_finish, capture cause signature)
-
ecall back to m-mode
RVMODEL_MSTATUS_MIE = MSTATUS_SIE RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_SINT2_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT2 = RVMODEL_SET_MTIMER_INT RVMODEL_SINT1_CLICINTCTL = RVMODEL_CLICINTCTL_MAX RVMODEL_SINT2_CLICINTCTL = RVMODEL_CLICINTCTL_MIN RVMODEL_SINT1_EXCCODE = 0x3 RVMODEL_SINT2_EXCCODE = 0x7 RVMODEL_CLEAR_SSTATUS_SPIE = 0
Coverage - same as order-01.S except
scause 2nd signature | verify sti occurs after ssi cleared and sret
-
generate 2 s-mode interrupts (msw, mtimer),
-
switch to s-mode,
-
trigger (s-mode handler),
-
only sint1 is cleared,
-
set sintthresh
-
re-enable mstatus.sie
-
ecall back to m-mode
RVMODEL_MSTATUS_MIE = MSTATUS_SIE RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_SINT2_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT2 = RVMODEL_SET_MTIMER_INT RVMODEL_SINT1_CLICINTCTL = RVMODEL_CLICINTCTL_MAX RVMODEL_SINT2_CLICINTCTL = RVMODEL_CLICINTCTL_MIN RVMODEL_SINTTHRESH_HNDLR1 = RVMODEL_SINTTHRESH_MAX RVMODEL_SINT1_EXCCODE = 0x3 RVMODEL_SINT2_EXCCODE = 0x7 RVMODEL_CLEAR_SSTATUS_SPIE = 0
Coverage - same as order-01.S except
scause 2nd signature | verify sti only occurs after ssi cleared and sret if sti level > sintthresh
-
generate 2 s-mode interrupts (msw, mtimer),
-
switch to s-mode,
-
trigger (s-mode handler),
-
only sint2 is cleared,
-
re-enable mstatus.sie
-
trigger (go to stvec_finish, capture cause signature)
-
ecall back to m-mode
RVMODEL_MSTATUS_MIE = MSTATUS_SIE RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_SINT2_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_SINT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_SINT1_CLICINTCTL = RVMODEL_CLICINTCTL_MAX RVMODEL_SINT2_CLICINTCTL = RVMODEL_CLICINTCTL_MIN RVMODEL_SINT1_EXCCODE = 0x3 RVMODEL_SINT2_EXCCODE = 0x7 RVMODEL_CLEAR_SSTATUS_SPIE = 0
Coverage - verify uncleared ssi interrupt will retrigger after sret
scause 2nd signature | verify 2nd signature
-
generate 1 m-mode interrupt (mtimer) and 1 s-mode interrupt (msw),
-
switch to s-mode,
-
trigger (m-mode handler),
-
clear m-mode interrupt
-
return to s-mode
-
trigger (s-mode handler)
-
clear s-mode interrupt
-
return to s-mode
-
ecall back to m-mode
RVMODEL_MSTATUS_MIE = MSTATUS_SIE RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_MINT2_CLICINTATTR = RVMODEL_CLICINTATTR_MMODE RVMODEL_SET_MINT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_MINT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_SINT1_CLICINTCTL = RVMODEL_CLICINTCTL_MAX RVMODEL_MINT2_CLICINTCTL = RVMODEL_CLICINTCTL_MIN RVMODEL_SINT1_EXCCODE = 0x3 RVMODEL_MINT2_EXCCODE = 0x7
Coverage - same as order-04.S except
mcause 1st signature | verify m-mode int 1st signature scause 2nd signature | verify s-mode int 2nd signature
-
generate 1 m-mode interrupt (mtimer) and 1 s-mode interrupt (msw),
-
switch to s-mode,
-
trigger (m-mode handler),
-
clear m-mode interrupt
-
return to s-mode
-
trigger (s-mode handler)
-
clear s-mode interrupt
-
return to s-mode
-
ecall back to m-mode
RVMODEL_MSTATUS_MIE = MSTATUS_SIE RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_MINT2_CLICINTATTR = RVMODEL_CLICINTATTR_MMODE RVMODEL_SET_MINT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_MINT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_SINT1_CLICINTCTL = RVMODEL_CLICINTCTL_MAX RVMODEL_MINT2_CLICINTCTL = RVMODEL_CLICINTCTL_MIN RVMODEL_SINTTHRESH_HNDLR1 = RVMODEL_SINTTHRESH_MAX RVMODEL_SINT1_EXCCODE = 0x3 RVMODEL_MINT2_EXCCODE = 0x7
Coverage
mcause 1st signature | verify m-mode int 1st signature scause 2nd signature | verify s-mode int 2nd signature
-
generate 1 m-mode interrupt (mtimer) and 1 s-mode interrupt (msw),
-
switch to s-mode,
-
trigger (m-mode handler),
-
clear m-mode interrupt
-
return to s-mode
-
trigger (s-mode handler)
-
clear s-mode interrupt
-
return to s-mode
-
ecall back to m-mode
RVMODEL_MSTATUS_MIE = MSTATUS_SIE RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_MINT2_CLICINTATTR = RVMODEL_CLICINTATTR_MMODE RVMODEL_SET_MINT2 = RVMODEL_SET_MTIMER_INT RVMODEL_CLEAR_MINT2 = RVMODEL_CLEAR_MTIMER_INT RVMODEL_SINT1_CLICINTCTL = RVMODEL_CLICINTCTL_MAX RVMODEL_MINT2_CLICINTCTL = RVMODEL_CLICINTCTL_MIN RVMODEL_MINTTHRESH_HNDLR1 = RVMODEL_MINTTHRESH_MAX RVMODEL_SINT1_EXCCODE = 0x3 RVMODEL_MINT2_EXCCODE = 0x7
Coverage
mcause 1st signature | verify m-mode int 1st signature scause 2nd signature | verify s-mode int 2nd signature
-
generate m-mode interrupt (msw)
-
stay in m-mode
-
wfi
-
wakeup
-
jump to done
-
ecall
RVMODEL_SWITCH_TO_S_MODE = <EMPTY> RVMODEL_MSTATUS_MIE = 0 RVMODEL_MINT1_CLICINTATTR = RVMODEL_CLICINTATTR_MMODE RVMODEL_SET_MINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_MINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_MINT1_EXCCODE = 0x3
Coverage
mstatus.mie | verify no m-mode interrupt taken when in m-mode and clicintie is 0
-
generate m-mode interrupt (msw)
-
stay in m-mode
-
nop
-
wakeup
-
jump to done
-
ecall
RVMODEL_WFI = nop RVMODEL_SWITCH_TO_S_MODE = <EMPTY> RVMODEL_MSTATUS_MIE = MSTATUS_MIE RVMODEL_MINT1_CLICINTIE = 0x0 RVMODEL_MINT1_CLICINTATTR = RVMODEL_CLICINTATTR_MMODE RVMODEL_SET_MINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_MINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_MINT1_EXCCODE = 0x3
Coverage
clicintie=0 | verify m-mode interrupt not taken when in m-mode and clicintie is 0
-
generate s-mode interrupt (msw)
-
stay in m-mode
-
wfi
-
wakeup
-
jump to done
-
ecall
RVMODEL_SWITCH_TO_S_MODE = <EMPTY> RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_SINT1_EXCCODE = 0x3
Coverage
mstatus.sie=1 | verify s-mode interrupt not taken when in m-mode
-
generate s-mode interrupt (msw)
-
switch to s-mode,
-
wfi
-
wakeup
-
jump to done
-
ecall back to m-mode
RVMODEL_MSTATUS_SIE = 0 RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_SINT1_EXCCODE = 0x3
Coverage
mstatus.mie=1, mstatus.sie=0 | verify s-mode interrupt not taken when in s-mode when mstatus.sie is 0
-
generate s-mode interrupt (msw)
-
switch to s-mode,
-
nop
-
jump to done
-
ecall back to m-mode
RVMODEL_WFI = nop RVMODEL_MSTATUS_MIE = MSTATUS_SIE RVMODEL_SINT1_CLICINTIE = 0x0 RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_SINT1_EXCCODE = 0x3
Coverage
sie=0 | verify s-mode interrupt not taken when in s-mode when clicintie=0
-
generate s-mode interrupt (msw)
-
wfi
-
wakeup
-
jump to done
RVMODEL_SWITCH_TO_S_MODE = <EMPTY> RVMODEL_MSTATUS_MIE = MSTATUS_SIE RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_SINT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_SINT1_EXCCODE = 0x3
Coverage
mstatus.sie=1, mstatus.sie=1 | verify s-mode interrupt not taken when in m-mode when mstatus.sie is 1
-
enable clicintie (default)
-
generate s-mode interrupt (msw)
-
wfi
-
wakeup
-
jump to finish
RVMODEL_MSTATUS_MIE = 0 RVMODEL_SET_SINT1 = RVMODEL_SET_MSW_INT RVMODEL_CLEAR_INT1 = RVMODEL_CLEAR_MSW_INT RVMODEL_SINT1_CLICINTATTR = RVMODEL_CLICINTATTR_SMODE RVMODEL_SINT1_EXCCODE = 0x3
Coverage
mstatus.mie | verify no interrupt occurs in m-mode if mstatus.mie is 0 wfi | verify wakeup/nop occurs with mstatus.mie = 0 wfi | verify wakeup/nop occurs with pending interrupt
TEST PLAN CASES
verify shv auto-clears an edge triggered interrupt verify shv interrupt is handled at the correct index in the xtvt table verify exception is taken when xtvt table is in non-executable region verify scause.sinhv set with mret returning to s-mode treats mepc as addr in xtvt table
Coverage Holes
-
async behavior on pipeline
-
Tests only have interrupts occur after mstatus.mie enabled or mret (which sets mstatus.mie to mstatus.mpie)
-
-
limited interrupt types tested
-
Tests only compare up-to two interrupts at a time.
-
Only msw and mtimer interrupts are used. MSW and Mtimer interrupts are only asserted and cleared by macros so no actual checking of CLINT msw and mtimer behavior is checked. E.g. No mtimer overflow, increment, mtimer/mtimerh rollover is checked. No external interrupts (SEI, MEI) checked by default. can be overridden with define.
-
-
clicintattr.trig is not testied, i.e., edge vs. level interrupts aren’t tested. interrupt positive-edge vs. negative-edge is not tested.
-
xtvec locations
-
Locations aren’t randomized, range of table jumps aren’t randomized
-
Handler address is always in executable memory so no exceptions will occur during interrupt.
-
-
interrupts vs. exceptions
-
Only ecall exceptions are used to verify mcause.interrupt toggling.
-
-
wfi holes
-
wfi only confirmed to continue/wakeup when mstatus.mie is 0. Interrupts occur before wfi but do not occur while executing wfi.
-
situations where wfi is not required to wake up are not tested
-
wfi resume after interrupt is not checked
-
wfi priv-mode traps not checked
-
-
WARL settings of implementation
-
Only legal values are intended to be written to CSRs. WARL behavior is not checked.
-
-
No u-mode interrupts checked