Scheduling Semantics Interview Questions
Master SystemVerilog simulation: blocking vs non-blocking assignments, delta cycles, event regions, and race conditions.
Beginner Level
Fundamentals=) and a non-blocking assignment (<=)?Blocking Assignment (=):
- Executes immediately when encountered.
- The next statement sees the updated value.
- Blocks execution until complete—hence "blocking."
Non-Blocking Assignment (<=):
- Schedules the update for the NBA (Non-Blocking Assignment) region.
- All RHS values are evaluated first (using current values).
- All LHS updates happen together at end of time step.
// Blocking: a becomes 1, then b becomes 1
a = 1; b = a; // b = 1
// Non-blocking: both use OLD values
a <= 1; b <= a; // If a was 0, b becomes 0!
always block should you use =? In
which should you use <=? What is the general rule?General Rules:
| Block Type | Assignment | Logic Type |
|---|---|---|
always_comb
|
= (blocking)
|
Combinational |
always_ff @(posedge clk)
|
<=
(non-blocking) |
Sequential |
always_latch
|
= (blocking)
|
Latch |
Why? Non-blocking in sequential logic prevents race conditions by modeling true hardware parallelism—all flip-flops update simultaneously.
Intermediate Level
Industry Standard$display and $strobe execute?+-----------------------------+
| SIMULATION TIME SLOT |
├-----------------------------┤
| 1. Active Region |
| - Blocking assignments |
| - $display (prints CURRENT values) |
| - Continuous assignments |
├-----------------------------┤
| 2. Inactive Region |
| - #0 delay statements |
├-----------------------------┤
| 3. NBA Region |
| - Non-blocking LHS updates |
├-----------------------------┤
| 4. Observed Region |
| - Concurrent assertion evaluation |
├-----------------------------┤
| 5. Reactive Region |
| - Program block code |
├-----------------------------┤
| 6. Postponed Region |
| - $strobe (prints FINAL values) |
| - $monitor |
+-----------------------------+
Key Insight: $display shows values at execution time (may be
pre-NBA). $strobe shows values after all updates are complete.
module test;
logic a = 0;
initial begin
a <= 1; // Non-blocking - schedules for NBA
$display("a in Active: %0d", a);
#0; // Move to Inactive, then back to Active
$display("a after #0: %0d", a);
end
initial #0 $display("a in Inactive: %0d", a);
endmodule
Output:
a in Active: 0 // NBA not applied yet
a in Inactive: 0 // Still before NBA
a after #0: 1 // After #0, NBA applied, back to Active
Explanation: The NBA update happens AFTER Inactive region. The second initial block runs in Inactive (#0). The first block's #0 causes re-entry to Active AFTER NBA, so it sees the updated value.
Delta Cycle: A zero-time iteration through simulation regions. Used to order events that logically occur at the same simulation time.
// Example: a and b toggle each other
always_comb a = ~b;
always_comb b = ~a; // Infinite delta cycles!
Prevention: Simulators have a maximum delta count (e.g., 200). If exceeded, simulation terminates with an error like "Iteration limit reached."
Real-World Fix: Add a delay or use proper sequential logic to break the combinational loop.
Advanced Level
Experty=0 and sometimes y=1. Explain the race and fix it.module dut(input logic clk, output logic y);
logic a, b;
always @(posedge clk) a = 1; // Blocking
always @(posedge clk) b = a; // Blocking
always @(posedge clk) y = b; // Blocking
endmodule
Problem: All three blocks trigger at the same time. With blocking assignments, the execution order is non-deterministic. Depending on which block runs first:
- If order is 1→2→3: a=1, b=1, y=1
- If order is 3→2→1: y=old_b, b=old_a, a=1 → y=0
Fix: Use non-blocking assignments:
always_ff @(posedge clk) a <= 1;
always_ff @(posedge clk) b <= a;
always_ff @(posedge clk) y <= b;
Now all RHS values are sampled BEFORE any LHS updates. Result is deterministic: takes 3 cycles for 1 to propagate to y.
posedge clk, three always_ff blocks have NBA
updates scheduled for signals x, y, and z. In what order are these updates applied? Is it
deterministic?Answer: The order of NBA updates to different signals is not specified by the LRM. However, this doesn't matter!
Why it's safe: All RHS expressions are evaluated using values from BEFORE any NBA update. So regardless of LHS update order, the result is the same.
// All three sample their RHS simultaneously (before any update)
always_ff @(posedge clk) x <= a;
always_ff @(posedge clk) y <= b;
always_ff @(posedge clk) z <= c;
The "snapshot" of a, b, c is taken first, then x, y, z are updated (order irrelevant).
Reactive Region: Where program block code executes.
Why Separate?
- Design code (modules) runs in Active/NBA regions.
- Testbench code (programs) runs in Reactive region.
- This ensures TB sees stable, post-NBA values from the DUT.
module dut;
logic data;
always_ff @(posedge clk) data <= compute();
endmodule
program tb;
initial begin
@(posedge clk);
// Runs in Reactive - sees stable 'data' value
$display("data = %0d", dut.data);
end
endprogram
Note: In modern UVM, program blocks are less common;
module-based TBs with clocking blocks are preferred.
always @(posedge clk) to drive DUT
inputs. Simulation has intermittent failures. Switching to a clocking block fixes it.
Explain.Root Cause: The TB's always @(posedge clk) block and the DUT's
sequential logic both execute at the same simulation time (both in Active/NBA regions). The
order is non-deterministic.
- Sometimes TB drives before DUT samples → works.
- Sometimes DUT samples before TB drives → sees old value → failure.
Clocking Block Fix:
- Input skew: Samples inputs BEFORE clock edge (stable DUT outputs).
- Output skew: Drives outputs AFTER clock edge (DUT sees stable inputs).
clocking cb @(posedge clk);
default input #1step output #0; // Safe defaults
input dut_out; // Sample before edge
output dut_in; // Drive after edge
endclocking
This explicit timing eliminates race conditions entirely.