<<< :sectnums: ==== External Interrupt Controller (XIRQ) [cols="<3,<3,<4"] [frame="topbot",grid="none"] |======================= | Hardware source file(s): | neorv32_xirq.vhd | | Software driver file(s): | neorv32_xirq.c | | | neorv32_xirq.h | | Top entity port: | `xirq_i` | IRQ input (32-bit, fixed) | Configuration generics: | _XIRQ_NUM_CH_ | Number of IRQs to implement (0..32) | | _XIRQ_TRIGGER_TYPE_ | IRQ trigger type configuration | | _XIRQ_TRIGGER_POLARITY_ | IRQ trigger polarity configuration | CPU interrupts: | fast IRQ channel 8 | XIRQ (see <<_processor_interrupts>>) |======================= The eXternal interrupt controller provides a simple mechanism to implement up to 32 processor-external interrupt request signals. The external IRQ requests are prioritized, queued and signaled to the CPU via a single _CPU fast interrupt request_. **Theory of Operation** The XIRQ provides up to 32 interrupt _channels_ (configured via the _XIRQ_NUM_CH_ generic). Each bit in the `xirq_i` input signal vector represents one interrupt channel. If less than 32 channels are configure, only the LSB-aligned channels are used while the remaining bits are left unconnected. An interrupt channel is enabled by setting the according bit in the interrupt enable register `IER`. If the configured trigger (see below) of an enabled channel fires, the request is stored into an internal buffer. This buffer is available via the interrupt pending register `IPR`. A `1` in this register indicates that the corresponding interrupt channel has fired but has not yet been serviced (so it is pending). An interrupt channel can become pending if the according `IER` bit is set. Pending IRQs can be cleared by writing `0` to the according `IPR` bit. As soon as there is a least one pending interrupt in the buffer, an interrupt request is send to the CPU. [NOTE] A disabled interrupt channel can still be pending if it has been triggered before clearing the according `IER` bit. The CPU can determine active external interrupt request either by checking the bits in the `IPR` register, which show all pending interrupt channels, or by reading the interrupt source register `SCR`. This register provides a 5-bit wide ID (0..31) that shows the interrupt request with _highest priority_. Interrupt channel `xirq_i(0)` has highest priority and `xirq_i(_XIRQ_NUM_CH_-1)` has lowest priority. This priority assignment is fixed and cannot be altered by software. The CPU can use the ID from `SCR` to service IRQ according to their priority. To acknowledge the according interrupt the CPU can write `1 << SCR` to `IPR`. In order to clear a pending FIRQ interrupt from the external interrupt controller again, the according <<_mip>> CSR bit has to be cleared. Additionally, the XIRQ interrupt has to be acknowledged by writing _any_ value to the interrupt source register `SRC`. [NOTE] An interrupt handler should clear the interrupt pending bit that caused the interrupt first before acknowledging the interrupt by writing the `SCR` register. **IRQ Trigger Configuration** The controller does not provide a configuration option to define the IRQ triggers _during runtime_. Instead, two generics are provided to configure the trigger of each interrupt channel before synthesis: the _XIRQ_TRIGGER_TYPE_ and _XIRQ_TRIGGER_POLARITY_ generic. Both generics are 32 bit wide representing one bit per interrupt channel. If less than 32 interrupt channels are implemented the remaining configuration bits are ignored. _XIRQ_TRIGGER_TYPE_ is used to define the general trigger type. This can be either _level-triggered_ (`0`) or _edge-triggered_ (`1`). _XIRQ_TRIGGER_POLARITY_ is used to configure the polarity of the trigger: a `0` defines low-level or falling-edge and a `1` defines high-level or rising-edge. .Example trigger configuration: channel 0 for rising-edge, IRQ channels 1 to 31 for high-level [source, vhdl] ---- XIRQ_TRIGGER_TYPE => x"00000001"; XIRQ_TRIGGER_POLARITY => x"ffffffff"; ---- **Register Map** .XIRQ register map (`struct NEORV32_XIRQ`) [cols="^4,<5,^2,^2,<14"] [options="header",grid="all"] |======================= | Address | Name [C] | Bit(s) | R/W | Function | `0xffffff80` | `NEORV32_XIRQ.IER` | `31:0` | r/w | Interrupt enable register (one bit per channel, LSB-aligned) | `0xffffff84` | `NEORV32_XIRQ.IPR` | `31:0` | r/w | Interrupt pending register (one bit per channel, LSB-aligned); writing 0 to a bit clears according pending interrupt | `0xffffff88` | `NEORV32_XIRQ.SCR` | `4:0` | r/w | Channel id (0..31) of firing IRQ (prioritized!); writing _any_ value will acknowledge the current interrupt | `0xffffff8c` | - | `31:0` | r/- | _reserved_, read as zero |=======================