IRQMP — Multi-processor interrupt controller¶
GRLIB IRQMP (GR712RC §8 / GRLIB IP §31): the cross-bar that turns external interrupt assertions into per-CPU pending bitmaps.
| Property | Value |
|---|---|
| Default MMIO base | 0x80000200 |
| MMIO window size | 0x100 |
| CPUs supported | 2 (GR712RC) |
| IRQ lines | 1–31 (line 0 is reserved as "no interrupt") |
| Source file | src/peripherals/src/irqmp.cpp |
Register map¶
All registers are 32-bit, word-aligned. Byte and half-word accesses
return AlignmentError.
| Offset | Name | Access | Description |
|---|---|---|---|
0x000 |
ILR | R/W | Interrupt level register (priority bit per line) |
0x004 |
IPR | R | Interrupt pending register (current asserted lines) |
0x008 |
IFR0 | R/W | Force register, CPU 0 |
0x00C |
ICR | W | Interrupt clear register (write-1-clear) |
0x010 |
MPSTAT | partial R | Multiprocessor status |
0x014 |
BROADCAST | R/W | Broadcast mask (which lines go to all CPUs) |
0x040 |
IMASK0 | R/W | CPU 0 interrupt mask |
0x044 |
IMASK1 | R/W | CPU 1 interrupt mask |
0x080 |
IFORCE0 | R/W (high half W1C) | CPU 0 force register |
0x084 |
IFORCE1 | R/W (high half W1C) | CPU 1 force register |
0x0C0 |
EID0 | R | Extended interrupt ID for CPU 0 |
0x0C4 |
EID1 | R | Extended interrupt ID for CPU 1 |
MPSTAT layout¶
MPSTAT is read-mostly with a few writable bits (CPU power-down release
in particular):
| Bits | Field | Meaning | Reset value |
|---|---|---|---|
| 31:28 | NCPU | Number of CPUs minus 1 | 0 (single-core default) |
| 27 | BA | Broadcast available | 1 |
| 19:16 | EIRQ | Extended IRQ number | 12 |
| 15:0 | STATUS | Per-CPU power status (1 = halted) | depends on cores |
Writing the lower 16 bits releases the corresponding CPU from power-down mode; this is how RTEMS releases secondary cores during SMP boot.
IFORCE / IFR write semantics (Decision 13)¶
IFORCE0, IFORCE1 and IFR0 use a clear-then-set protocol:
- The upper 16 bits of the written value are W1C: any bit set in the upper half clears the corresponding force bit.
- The lower 16 bits are W1S: any bit set in the lower half sets the corresponding force bit.
This matches GRLIB hardware where software can atomically toggle force state in one MMIO write. In code:
uint32_t cleared_then_set =
(current_force & ~(value >> 16)) // clear bits indicated by hi half
| (value & 0xFFFF); // set bits indicated by lo half
pending_mask(cpu) — what the core sees¶
The runtime's sample_interrupts calls
IrqMP::pending_mask(cpu) once per quantum to find out which lines
are pending for that CPU:
…with two refinements (Decision 14):
- For CPU 0,
IFR_for(0)isIFR0. - For CPU N > 0,
IFR_for(N)isIFORCE[N].
The highest set bit ≥ 1 in the resulting mask is the interrupt level;
the runtime then compares it to PSR.PIL and injects a hardware trap
with tt = 0x10 + level if needed.
external_assert / external_clear¶
The C++ API used by other peripherals (and by tests) to drive lines into the IRQMP:
void external_assert(uint32_t bits) noexcept;
void external_clear (uint32_t bits) noexcept;
uint32_t pending_mask(uint32_t cpu) const noexcept;
external_assert(bits) sets the bits in the shared pending vector
(IPR). Bits in BROADCAST propagate to all per-CPU force registers.
This is the behaviour the runtime's IrqBridge adapter wraps when a
peripheral calls IInterruptSource::raise().
Reset state¶
IPR = 0,IFR0 = 0,IFORCE[*] = 0.IMASK[*] = 0(everything masked).BROADCAST = 0.MPSTAT = (1 << 28) | (1 << 27) | (12 << 16).
Tests¶
tests/unit/test_irqmp.cpp— register-by-register coverage of the IFORCE write semantics,pending_mask,external_assert, broadcast propagation, ICR W1C, and MPSTAT writes that release a CPU.- The integration tests under
tests/integration/test_rtems_*exercise the IRQMP through the full RTEMS BSP boot.