You can write simple C interrupt handlers by using the __irq function declaration keyword. You can use the __irq keyword both for simple one-level interrupt handlers, and interrupt handlers that call subroutines. However, you cannot use the __irq keyword for reentrant interrupt handlers, because it does not cause the SPSR to be saved or restored. In this context, reentrant means that the handler re-enables interrupts, and may itself be interrupted. See Reentrant interrupt handlers on page 5-26 for more information.
The __irq keyword:
• preserves all ATPCS corruptible registers
• preserves all other registers (excluding the floating-point registers) used by the function
• exits the function by setting the program counter to (lr – 4) and restoring the CPSR to its original value.
If the function calls a subroutine, __irq preserves the link register for the interrupt mode in addition to preserving the other corruptible registers. See Calling subroutines from interrupt handlers for more information.
Note
C interrupt handlers cannot be produced in this way using tcc. The __irq keyword is faulted by tcc because tcc can only produce Thumb code, and the processor is always switched to ARM state when an interrupt, or any other exception, occurs.
However, the subroutine called by an __irq function can be compiled for Thumb, with interworking enabled. See Chapter 3 Interworking ARM and Thumb for more information on interworking.
Calling subroutines from interrupt handlers
If you call subroutines from your top-level interrupt handler, the __irq keyword also restores the value of lr_IRQ from the stack so that it can be used by a SUBS instruction to return to the correct address after the interrupt has been handled.
Example 5-13 on page 5-25 shows how this works. The top level interrupt handler reads the value of a memory-mapped interrupt controller base address at 0x80000000. If the value of the address is 1, the top-level handler branches to a handler written in C.