Mechanism and evidence
A request is only the beginning.
Compare coalescing and timeout triggers, then follow the request through status capture, source clearing, and resumed traffic.
Checkpoint 1 · Nine events are still waiting.
- EVENT COUNT
- 9
- IRQ LEVEL
- 0
- SERVICE
- wait
- EXPECTED
- 0
Compare all 6 checkpoints
1 · Nine events are still waiting.
- EVENT COUNT
- 9
- IRQ LEVEL
- 0
- SERVICE
- wait
- EXPECTED
- 0
2 · The tenth event sets the request.
- EVENT COUNT
- 10
- IRQ LEVEL
- 1
- SERVICE
- request
- EXPECTED
- 1
3 · Reactive traffic waits at a legal boundary.
- EVENT COUNT
- 10
- IRQ LEVEL
- 1
- SERVICE
- grab
- EXPECTED
- 1
4 · Read the cause before changing it.
- EVENT COUNT
- 10
- IRQ LEVEL
- 1
- SERVICE
- read
- EXPECTED
- 1
5 · Clear the handled source.
- EVENT COUNT
- 0
- IRQ LEVEL
- 0
- SERVICE
- clear
- EXPECTED
- 1
6 · Return access to normal traffic.
- EVENT COUNT
- 0
- IRQ LEVEL
- 0
- SERVICE
- ungrab
- EXPECTED
- 0
Nine events are still waiting.
- Events
- 9 / 10
- IRQ
- 0
- Expired
- No
The coalescer has recorded nine qualifying events. The example threshold is ten, and its safety timer has not expired.
Compare the event ledger to the source status before expecting an interrupt.
Inspect the checker Selected checkpoint pseudocode
expected_irq = (events >= 10) || expired;
assert(!expected_irq);Example contract & limitations
Example contract. A level IRQ is latched when events ≥ 10 OR the safety timer expires at a defined sampling boundary. No new arrivals occur during this short service fixture. Source clear consumes the snapshot and restarts the timer; real register semantics must be checked. Checkpoints show selected state changes, not equally spaced simulation cycles.
Read the complete walkthrough
Event 10
- Nine events are still waiting.. The coalescer has recorded nine qualifying events. The example threshold is ten, and its safety timer has not expired. Evidence: Compare the event ledger to the source status before expecting an interrupt.
- The tenth event sets the request.. Event ten reaches the threshold at the sampled boundary. The source latches one level interrupt. Evidence: Observe a single rising IRQ and preserve all qualifying cause information.
- Reactive traffic waits at a legal boundary.. The service sequence gains access after any already granted driver item reaches its permitted boundary. grab() is not an abort mechanism. Evidence: Keep the in-progress handshake trace and the sequencer ownership transition.
- Read the cause before changing it.. Read the latched event status once. Observation must capture the cause before the service operation clears it. Evidence: Correlate the status snapshot with the event ledger.
- Clear the handled source.. This fixture consumes the recorded events, clears the latch, and restarts the timeout. Clearing unrelated controller state would leave the level request asserted. Evidence: Observe source deassertion and verify that no new event was erased.
- Return access to normal traffic.. Release the sequencer and continue useful traffic. The checker retires exactly one service obligation. Evidence: Confirm ordinary traffic resumes and the expected-IRQ count returns to zero.
Timeout first
- Nine events are still waiting.. The coalescer has recorded nine qualifying events. The example threshold is ten, and its safety timer has not expired. Evidence: Compare the event ledger to the source status before expecting an interrupt.
- The timer supplies the missing trigger.. The safety timer expires with only nine events. The OR condition still requires one interrupt. Evidence: Observe a single rising IRQ and preserve all qualifying cause information.
- Reactive traffic waits at a legal boundary.. The service sequence gains access after any already granted driver item reaches its permitted boundary. grab() is not an abort mechanism. Evidence: Keep the in-progress handshake trace and the sequencer ownership transition.
- Read the cause before changing it.. Read the latched event status once. Observation must capture the cause before the service operation clears it. Evidence: Correlate the status snapshot with the event ledger.
- Clear the handled source.. This fixture consumes the recorded events, clears the latch, and restarts the timeout. Clearing unrelated controller state would leave the level request asserted. Evidence: Observe source deassertion and verify that no new event was erased.
- Return access to normal traffic.. Release the sequencer and continue useful traffic. The checker retires exactly one service obligation. Evidence: Confirm ordinary traffic resumes and the expected-IRQ count returns to zero.
Threshold + timeout
- Nine events are still waiting.. The coalescer has recorded nine qualifying events. The example threshold is ten, and its safety timer has not expired. Evidence: Compare the event ledger to the source status before expecting an interrupt.
- Two causes create one service obligation.. Threshold and timeout become true together. They are two causes of the same latched request, not two independent IRQ completions. Evidence: Observe a single rising IRQ and preserve all qualifying cause information.
- Reactive traffic waits at a legal boundary.. The service sequence gains access after any already granted driver item reaches its permitted boundary. grab() is not an abort mechanism. Evidence: Keep the in-progress handshake trace and the sequencer ownership transition.
- Read the cause before changing it.. Read the latched event status once. Observation must capture the cause before the service operation clears it. Evidence: Correlate the status snapshot with the event ledger.
- Clear the handled source.. This fixture consumes the recorded events, clears the latch, and restarts the timeout. Clearing unrelated controller state would leave the level request asserted. Evidence: Observe source deassertion and verify that no new event was erased.
- Return access to normal traffic.. Release the sequencer and continue useful traffic. The checker retires exactly one service obligation. Evidence: Confirm ordinary traffic resumes and the expected-IRQ count returns to zero.
Related implementation: Reactive traffic and ISR threads
task body();
fork
// Thread 1: Normal Traffic
forever begin
`uvm_do_with(req, {type == DATA_PACKET;})
end
// Thread 2: Interrupt Handler (The ISR)
forever begin
@(posedge vif.irq[0]); // High Priority IRQ
`uvm_info("IRQ", "High-Prio IRQ Detected! Pre-empting...", UVM_LOW)
// Stop current bus traffic to simulate SW reading the status reg
m_sequencer.grab(this);
`uvm_do(read_status_reg_seq);
`uvm_do(clear_irq_seq);
m_sequencer.ungrab(this);
end
join_any
endtaskThe source slide runs normal traffic and an IRQ listener concurrently. The listener takes sequencer ownership, performs the status-read and clear-register flow, and then releases arbitration.
Understand the failure+
The tracker predicts coalescing and priority while the reactive sequence models the software-visible service path.
Event-to-service path
The checker follows each source event through priority and coalescing state, onto an IRQ line, and through the software-visible ISR handshake.
- Event sources
- Asynchronous IP events, including simultaneous and coalesced sources.
- IRQ controller
- Maps Event_ID to IRQ_Line, applies priority, and counts to the threshold or timeout.
- Pulse monitor
- Captures edge, level, width, and timestamp at the output pin.
- Reactive ISR sequence
- Takes sequencer ownership, reads status, and writes the clear control.
- IRQ scoreboard
- Correlates the source, programmed mapping, predicted pulse, and completed service.
- Event source -> priority and coalescing state
- Threshold or safety timeout -> IRQ line
- IRQ edge or level -> reactive ISR sequence
- Status read and clear write -> source retirement
- Source event + pin observation + RAL state -> scoreboard verdict
Why it matters
- Interrupts are the hardware doorbell. A complex SoC interrupt controller may coordinate thousands of events.
- A dropped interrupt can hang the operating system. Incorrect prioritization can make latency-sensitive work, such as audio processing, stutter.
- The verification target includes the pin-level IRQ, the source/status mapping, priority behavior, and the software-visible read-and-clear service flow.
What is difficult
- Interrupts are asynchronous to normal bus traffic, so a linear UVM sequence does not naturally model a high-priority IRQ interrupting a low-priority ISR.
- A coalescing controller may wait for 10 packets before firing one IRQ. The checker must accept an interrupt on the 10th packet or when the safety timeout expires, whichever happens first.
- Level-triggered interrupts persist until software clears them, while a one-clock edge interrupt can disappear before a polling sequence observes it.
- An interrupt storm requires simultaneous source activity plus exact checking against the programmed priority registers.
Failure signatures
- An event is dropped and the expected IRQ never arrives.
- The arbiter services simultaneous sources in an order that disagrees with the priority registers.
- A coalesced IRQ fires before event 10, after event 10, or after the timeout boundary.
- A level IRQ deasserts before its clear write, or a one-cycle edge IRQ is never captured.
- The IRQ pin toggles while the IP status register reports no active source, creating a spurious interrupt.
- The testbench services an IRQ but never reads status or clears the source, hiding an incorrect hardware-software handshake.
Compare approaches+
Two viable approaches—and their cost
Reactive virtual sequences
Use wait-for-interrupt tasks to launch the ISR sequence when the DUT asserts an interrupt.
- Naturally models hardware-software interaction.
- Makes nested-interrupt and pre-emption scenarios direct to express.
- Introduces threading and arbitration complexity in the virtual sequencer.
- Can become difficult to manage when IRQs fire faster than service sequences complete.
IRQ scoreboard and event tracker
Count source events, predict output IRQ pulses, and check event-to-line mapping, coalescing, pulse width, and timing.
- Provides accurate event-to-pulse and threshold checking.
- Separates asynchronous prediction from bus stimulus.
- Does not by itself verify the ISR read-status and clear-register flow.
- Needs state for every source, line, threshold, timer, and pending event.
Explain it in an interview+
Interview answer, built from the mechanism
- I verify interrupt subsystems around pre-emption and coalescing. A reactive virtual sequence listens to the interrupt pins instead of assuming interrupts occur at a convenient point in a linear test.
- When a high-priority IRQ fires, the ISR sequence takes sequencer ownership, reads the status register, clears the interrupt, and then releases normal traffic. This models the software-visible service path as well as the pin.
- A dedicated scoreboard tracks source events, the programmed Event_ID-to-IRQ_Line mapping, pulse width, and the event-to-pulse ratio. It permits a coalesced IRQ only when the threshold is met or the safety timer expires.
- I add assertions for level persistence, a capture queue for one-cycle edges, simultaneous-source storm tests for priority, and a spurious-interrupt check that correlates every IRQ with an active status bit.
Assign responsibilities+
Component responsibility contract
| Component | Responsibility | Required change |
|---|---|---|
| Monitor | Pulse detection | Capture IRQ edge, level, and pulse width, and timestamp the trigger. |
| Sequencer | Pre-emption | Use is_relevant() or an equivalent arbitration policy to pause normal traffic while an IRQ is pending. |
| Scoreboard | Event mapping | Map Event_ID from the IP to the output IRQ_Line and predict coalescing thresholds and timers. |
Build the checker+
Implementation patterns
task body();
fork
// Thread 1: Normal Traffic
forever begin
`uvm_do_with(req, {type == DATA_PACKET;})
end
// Thread 2: Interrupt Handler (The ISR)
forever begin
@(posedge vif.irq[0]); // High Priority IRQ
`uvm_info("IRQ", "High-Prio IRQ Detected! Pre-empting...", UVM_LOW)
// Stop current bus traffic to simulate SW reading the status reg
m_sequencer.grab(this);
`uvm_do(read_status_reg_seq);
`uvm_do(clear_irq_seq);
m_sequencer.ungrab(this);
end
join_any
endtaskThe source slide runs normal traffic and an IRQ listener concurrently. The listener takes sequencer ownership, performs the status-read and clear-register flow, and then releases arbitration.
Stress the design+
Stress recipe
- Program a coalescing threshold of 10 plus a known safety timeout.
- Send nine qualifying packets and prove that no IRQ is emitted.
- Send packet 10 and require the IRQ at the specified threshold boundary.
- Repeat with fewer than 10 packets, stop event arrival, and require the timeout-driven IRQ.
- Begin a low-priority ISR, assert a high-priority IRQ during service, and check pre-emption, status read, clear, and traffic resumption.
- Drive every event source simultaneously and compare service order with the priority-register image.
- Exercise a held level, a one-cycle edge, and an IRQ with no status source.
Follow-up questions
How do you verify level-triggered versus edge-triggered interrupts?
Use SVA to require a level IRQ to remain asserted until its Clear bit is written through RAL. Capture an edge IRQ in a local event queue even when it is only one clock wide.
How do you verify an interrupt storm?
Saturate all event inputs simultaneously and verify that the arbiter services them in the exact order defined by the priority registers.
What is a spurious interrupt, and how do you find it?
It is an IRQ with no active source. Flag an error if an IRQ pin toggles while the IP status register reports no active event.

