I met Gary Stringham, an embedded systems consultant, at the 45th DAC SPIRIT Consortium meeting in Anaheim where we demonstrated the SpectaReg web-app using IP-XACT. Since then, I’ve been subscribing to Gary’s excellent Embedded Bridge monthly newsletter, which provides best practices for the hardware/firmware divide. Gary is a big proponent for register module generation tools like SpectaReg and he recommends such tools as one of his best practices.
Issue #26, of the Embedded Bridge newsletter discusses level-triggered vs. edge-triggered interrupts and makes a good case for using edge-triggered interrupts. Why? Well, because level-triggered interrupts are painful for the firmware engineer. Level-triggered interrupts cause extra complexity, extra CPU cycles, and create a possibility for missed interrupts.
Consider the following example…
Imagine you are creating a packet receiver (PR) hardware component. When the PR processes an errored packet, it asserts a status signal (pkt_err_stat) until the next packet comes in. The following table shows the PR’s register bits, which are mapped into addressable registers and are all one bit wide.
| Bit Name | Access | Bit Description |
|---|---|---|
| has_int | Read Only | The PR component has an outstanding interrupt. Read all of the PR component’s interrupt bits to determine the source. |
| pkt_err_stat | Read Only | When 1, the PR’s current packet is in error, when 0, the current packet does not have an error. For each new packet this will always be 0 for at least one cycle. |
| pkt_err_int_en | Read/Write | Write 1 to enable the packet error interrupt (pkt_err_int), write 0 to disable/mask the said interrupt. |
| pkt_err_int | Read/Write | When 1 an errored packet has been observed. Write 1 to clear this interrupt event. [Also, describe here whether this is edge or level sensitive.] |
When pkt_err_stat is asserted, an interrupt is generated (if enabled). The interrupt causes firmware to vector to it’s interrupt handler, where it identifies that PR has an interrupt (since has_int for PR is asserted). Firmware then reads PR’s interrupts to discover that pkt_err_int is asserted.
Level-triggered case: In the case where pkt_err_int is level-triggered and the next packet has yet to be received, then pkt_err_stat will still be asserted. To exit the interrupt handler, the firmware must disable then clear the interrupt by writing one to it. The issue now is… when does firmware re-enable the interrupt? With the interrupt disabled, how does firmware know if the next packet is errored? Answering these questions from firmware creates un-needed complexity.
Edge-triggered case: If pkt_err_int is an edge-triggered interrupt, then the firmware is simpler and less prone to missing back-to-back errored packets. To exit the interrupt handler, the firmware simply clears the interrupt. When the next packet comes in, if it’s errored another interrupt is generated and there is less risk of missing this event.
One objection to edge triggered interrupts, as Gary points out, is that they take up more logic gates. When I read Gary’s level vs. edge triggered Embedded Bridge issue, I decided to look at SpectaReg’s generated VHDL and Verilog to see how we did our interrupts. It turns out that we originally only had level-triggered interrupts. To add support for positive edge-triggered interrupts, the RTL was pretty much identical to the level-triggered, it just required sampling the last value of the status (pkt_err_stat in the example) and using that to determine when to generate the interrupt. If the current value is 1 and the last value was 0 then the interrupt is generated. This results in one additional flop per edge-triggered interrupt and a little more combinational logic. The cost is insignificant compared to the benefit.
So…. all you Verilog and VHDL RTL developers, next time you go to create an interrupt bit do the firmware developer a favor and make it edge triggered.

