79 lines
4.4 KiB
Plaintext
79 lines
4.4 KiB
Plaintext
<<<
|
|
: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` | External interrupts input (32-bit)
|
|
| Configuration generics: | `XIRQ_NUM_CH` | Number of external IRQ channels 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>>)
|
|
|=======================
|
|
|
|
|
|
**Overview**
|
|
|
|
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 external 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 configured, only the LSB-aligned channels
|
|
are used while the remaining ones are left unconnected internally. The actual interrupt trigger type is configured before
|
|
synthesis using the `XIRQ_TRIGGER_TYPE` and `XIRQ_TRIGGER_POLARITY` generics (see table below).
|
|
|
|
.XIRQ Trigger Configuration
|
|
[cols="^2,^2,<3"]
|
|
[options="header",grid="all"]
|
|
|=======================
|
|
| `XIRQ_TRIGGER_TYPE(i)` | `XIRQ_TRIGGER_POLARITY(i)` | Resulting Trigger of `xirq_i(i)`
|
|
| `0` | `0` | low-level
|
|
| `0` | `1` | high-level
|
|
| `1` | `0` | falling-edge
|
|
| `1` | `1` | rising-edge
|
|
|=======================
|
|
|
|
The interrupt controller features three interface registers: external interrupt channel enable (`EIE`), external interrupt
|
|
channel pending (`EIP`) and external interrupt source (`ESC`). From a functional point of view, the functionality of these
|
|
registers follow the one of the RISC-V <<_mie>>, <<_mip>> and <<_mcause>> CSRs.
|
|
|
|
If the configured trigger of an interrupt channel fires (e.g. a rising edge) the according interrupt channel becomes _pending_,
|
|
which is indicated by the according channel bit being set in the `EIP` register. This pending interrupt can be cleared at any time
|
|
by writing zero to the according `EIP` bit.
|
|
|
|
A pending interrupt can only trigger a CPU interrupt if the according is enabled via the `EIE` register. Once triggered, disabled
|
|
channels that were triggered remain pending until explicitly cleared. The channels are prioritized in a static order, i.e. channel 0
|
|
(`xirq_i(0)`) has the highest priority and channel 31 (`xirq_i(31)`) has the lowest priority. If any pending interrupt channel is
|
|
actually enabled, an interrupt request is sent to the CPU.
|
|
|
|
The CPU can determine the most prioritized external interrupt request either by checking the bits in the `IPR` register or by reading
|
|
the interrupt source register `ESC`. This register provides a 5-bit wide ID (0..31) identifying the currently firing external interrupt.
|
|
Writing _any_ value to this register will acknowledge the _current_ XIRQ interrupt (so the XIRQ controller can issue a new CPU interrupt).
|
|
|
|
In order to acknowledge an XIRQ interrupt, the interrupt handler has to...
|
|
* clear the pending CPU FIRQ by clearing the according <<_mip>> CSR bit
|
|
* clear the pending XIRQ channel by clearing the according `EIP` bit
|
|
* writing _any_ value to `ESC` to acknowledge the XIRQ interrupt
|
|
|
|
|
|
**Register Map**
|
|
|
|
.XIRQ register map (`struct NEORV32_XIRQ`)
|
|
[cols="^4,<2,^2,^2,<14"]
|
|
[options="header",grid="all"]
|
|
|=======================
|
|
| Address | Name [C] | Bit(s) | R/W | Description
|
|
| `0xfffff300` | `EIE` | `31:0` | r/w | External interrupt enable register (one bit per channel, LSB-aligned)
|
|
| `0xfffff304` | `EIP` | `31:0` | r/w | External interrupt pending register (one bit per channel, LSB-aligned); writing 0 to a bit clears the according pending interrupt
|
|
| `0xfffff308` | `ESC` | `4:0` | r/w | Interrupt source ID (0..31) of firing IRQ (prioritized!); writing _any_ value will acknowledge the current XIRQ interrupt
|
|
| `0xfffff30c` | - | `31:0` | r/- | _reserved_, read as zero
|
|
|=======================
|