Hi @Ted usually mie
is the last thing to enable, certainly after setting up everything else and, most importantly, mtvec
. It’s good you remember to keep the handler on an 64-byte boundary. The first two bits determine absolute or vectored mode, you might check with gdb
to make sure PC is going where you think.
Here is a discussion and picture of the PLIC interrupt flow and some tips I put together to initialize and set up GPIO pins for PLIC; they are from an assembly code perspective, which I think is clearer to work with.
You may also find my github repo Demonstrating MTVEC helpful: look at the start.s
file.
When an interrupt occurs, you should first determine whether it’s a synchronous exception or asynchronous interrupt. Then, in latter case, you should determine whether the source of interrupt is software, timer, or external/PLIC. In that latter case you claim
and acknowledge (complete
) the interrupt, and jump as directed to the appropriate source ID.
Make sure the jump tables are on 2-byte or four-byte boundaries, depending whether you use compressed or long form versions of the j
instruction.
Lastly, don’t forget the mret
at the end, which automatically clears the mip
flag.
It is easy to mix up the interrupt enable bits of CSR_MIE_MxIE
(where x
is S
, T
, or E
for Software, Timer, or External, respectively) with CSR_MSTATUS_MIE
which is the main on/off switch for the entire interrupt process. It looks like your C-code already does this correctly, though.