[libre-riscv-dev] Handling Interrupts

Luke Kenneth Casson Leighton lkcl at lkcl.net
Sat May 9 20:42:24 BST 2020

On Sat, May 9, 2020 at 6:24 PM Yehowshua <yimmanuel3 at gatech.edu> wrote:
> One thing I just realized that I’ve never done in any of the RTL CPUs I’ve worked with is enable interrupts.
> How are interrupts done in RTL? As soon as the CPU controller sees that EINT
> is high, does it(upon the next clock boundary), flush the pipeline and
> immediately jump to the handler?

there's 2 or 3 ways it can be done, ultimately though they're as
simple as "change the Program Counter but also automatically store
current state when the INT hardware flag gets raised".  that state is
usually the Program Counter and the current "mode" -

it then becomes (in software) the responsibility of the trap handler
to save further context because in hardware, to save things like "the
entire register file" is far too many cycles.  plus, many fast
interrupt handlers don't *need* to save the entire regfile, because
they only use a subset of the registers.

so, in hardware, when any kind of "interrupt" condition occurs (an INT
line somewhere goes HI):

technique 1) further instruction issue is prevented and prohibited.
outstanding in-flight operations continue, until they are complete.
once complete, the interrupt "activates" (by changing the PC, and
changing the mode, and saving the require minimal state into

technique 2) pipelines are permitted to be "cancelled" (flushed).
this means that there must exist a global "cancellation" combinatorial
signal that propagates throughout every single pipeline stage.

technique 3) an augmented version of (2) where certain operations
(particularly those that might do "damage" i.e. once in progress can
in no way be "rolled back" such as memory operations that have already
initiated the process of committing a ST to memory) have a "mask"
which absolutely prevents and prohibits the interrupt - any interrupt
- including NMIs - from taking place.

technique 4) a much more subtle version of (3) where operations are
"shadowed", i.e. only the *write* portion of the operation is
prevented and prohibited from committing (whilst the execution itself
- the computation of the result - is allowed to proceed and be stored
in a latch).  if there is no exception - at all - and the "write"
portion is ABSOLUTELY GUARANTEED TO SUCCEED, then and only then is the
"shadow" lifted, and any interrupt that occurs past that point must
wait its turn.

technique 1 *and* 2 comes into effect at that point: anything that is
currently "shadowed" has its global "cancel" pulled (GO_DIE), whilst
anything that can *not* be cancelled must be waited for.

(4) is what we will implement - all the infrastructure is in place:
global mask cancellation bitmaps, shadowing, it's all there.

> I’m aware that there can be external hardware such as a PLIC to arbitrate interrupts,

yes.  that's another thing that needs to go on the list.

> I’m just not certain about the actual CPU RTL - what it would do. That is, if the CPU immediately
> jumps to the handler address - or if it bothers to save a few register first

CSRs/SPRs yes.   typically the current PC is stored into a CSR/SPR of
its own.  this will be used as the "return from trap" address, where
the hardware will, on exit from the trap, restore the current PC from
that CSR/SPR.  and restore the current "mode" (user/hypervisor/kernel
mode) from the corresponding SPR/CSR as well.

> ( this might depend on the actual ISA itself too).

yes it depends on the ISA, however the "good" ones minimise the amount
of state that gets "swapped" into CSRs and lets the software (trap
handler) sort it out.


More information about the libre-riscv-dev mailing list