19.2 IRQPendingState Implementation

<< Click to Display Table of Contents >>

Navigation:  ASA-EMulatR Reference Guide > Introduction > Architecture Overview > Chapter 19 – Interrupt Architecture & IPI >

19.2 IRQPendingState Implementation

19.2.1 Per-CPU Tracking Structure

 

IRQPendingState (coreLib/IRQPendingState.h, ~378 lines) is the per-CPU interrupt tracking structure. It is the central data structure through which all interrupt sources (devices, software, IPIs) communicate pending interrupts to the CPU. Its design is driven by the cross-thread safety requirement: device I/O threads may assert interrupts at any time while the CPU thread checks for deliverable interrupts every cycle.

 


 

19.2.2 Data Structures

 

Field

Purpose

pendingLevelsMask (atomic<quint32>)

Summary bitset: bit L set means at least one pending source at IPL L. Provides a single fast check for "what needs attention."

pendingSourcesByLevel (array of atomic<quint64>)

Per-level source bitmask — up to 64 interrupt sources per level. Identifies which specific device or source triggered the interrupt.

highestPendingLevel (atomic<quint8>)

Cached highest pending IPL for ultra-fast per-instruction checking. 0xFF means "nothing pending." Updated atomically by raise/clear/claim operations.

inServiceMask

CPU-thread-only mask tracking claimed (in-service) level-triggered interrupts. Not atomic — only accessed by the owning CPU thread.

 

Additionally, per-source static configuration records the trigger mode (edge or level), SCB vector index, and IPL assignment for each interrupt source.

 


 

19.2.3 Hot-Path Operations

 

The interrupt check is the second-hottest path in the emulator (after FaultDispatcher::eventPending()). The key operations:

 

hasDeliverable(currentIPL) — tests whether any pending interrupt level exceeds the current IPL. Implementation: single atomic load of highestPendingLevel and comparison against currentIPL. Cost: ~5 cycles (one atomic load, one compare). Returns immediately if nothing pending (0xFF).

 

claimNext() — atomically claims the highest-priority pending interrupt and returns a ClaimedInterrupt containing the source, IPL, and vector. For level-triggered interrupts, the source is added to inServiceMask. For edge-triggered interrupts, the pending bit is cleared atomically.

 

raiseInterrupt(sourceId, ipl) — called by device threads to assert an interrupt. Sets the source bit in pendingSourcesByLevel[ipl], sets the level bit in pendingLevelsMask, and updates highestPendingLevel if the new level is higher. All operations use memory_order_release to ensure device-side data is visible to the CPU thread.

 

clearInterrupt(sourceId, ipl) — called when a device deasserts its interrupt line. Clears the source bit; if no sources remain at that level, clears the level bit and recalculates highestPendingLevel.

 

See Also: coreLib/IRQPendingState.h (~378 lines); 7.10 Interrupt Handling.