Difficulty: Medium · Puzzle 3 of 6 · Topic: Debugging Riddles
Find the functional bug in this combinational block, which sometimes shows a stale value. Explain the stale symptom.
always_comb begin
if (en)
y <= a & b;
endTwo independent issues exist.
1) Missing else: when en=0 y is not assigned, so y holds its previous value. That is a latch in code that was meant to be combinational. Simulation: set en=1,a=1,b=1 (y=1), then en=0,a=0: y stays 1 instead of 0. Icarus warned about the NBA in always_comb as well.
2) Nonblocking assignment in a combinational block: the new value is committed in the NBA region. Anything that reads y in the same time step right after a, b or en changed sees the old value; in simulation y printed x in the same step and 1 only after the NBA update. That is the 'stale value' symptom.
3) Both effects are timing-dependent for the reader, which is why the failure looks random.
4) Correct form assigns y in all paths with blocking assignment: always_comb begin if (en) y = a & b; else y = 1'b0; end. (Or a default assignment first.)Answer: Bug is inferred latch plus NBA misuse in combinational logic; assign all paths with blocking assignment.
Checked by running the code in Icarus Verilog 13; the printed output supports the answer above. Icarus: the NBA version shows x in the same time step, then 1, and keeps 1 when en=0 (latch); the corrected block gives 0.
Blaming the simulator or the testbench for the stale read. A reader that samples in the same time step as the input change reads the pre-NBA value of y, and a missing else holds the old value forever; both are in the code.
Would `always_latch` be appropriate if latch was actually intended? Model answer: yes. always_latch documents the intent and tools check that it really infers a latch (always_comb with a missing else is flagged instead). A nonblocking assignment is acceptable there because a latch is a storage element.
There are two bugs in that block. First, the else is missing, so when enable is low y is not assigned and holds its old value, which is an inferred latch in code meant to be combinational. Second, the nonblocking assignment commits in the NBA region, so a reader in the same time step sees the old value, and that is the stale symptom. The fix is to assign y on every path with blocking assignments inside always_comb. The trap is blaming the simulator or the testbench when both effects are in the code.