Difficulty: Medium · Puzzle 1 of 6 · Topic: Coverage Closure and Sampling Timing Puzzles
The team expects bins 1,2,3 after three clocks but the report differs. clk starts at 0 and toggles every 5 time units; the covergroup is sampled manually by c.sample(state) from a posedge process. Options: none set (defaults). Compute the actual hits and explain.
module tb;
bit clk;
bit [1:0] state;
covergroup cg with function sample(bit [1:0] s);
cp_state: coverpoint s {
bins s0 = {0};
bins s1 = {1};
bins s2 = {2};
bins s3 = {3};
}
endgroup
cg c = new();
always #5 clk = ~clk;
always_ff @(posedge clk) state <= state + 1;
always @(posedge clk) c.sample(state);
initial begin
repeat (3) @(posedge clk);
#1 $finish;
end
endmoduleThe always_ff update is a nonblocking assignment, so the sampler at the same posedge reads the old value.
1) Posedges are at t = 5, 15, 25. At each one the sampling process runs in the active region and reads state; the nonblocking update from always_ff happens later in the NBA region.
2) Sampled values are therefore 0, 1, 2 (state becomes 3 only after the third edge and is never sampled).
3) Hit bins are s0, s1, s2 -> 3/4 = 75%.
(The same sampling structure was run as plain RTL in Icarus and Verilator 5.048: both sampled 0, 1, 2.)Answer: Actual coverage is 75% because the sampled states are 0,1,2 (not 1,2,3); s3 is never sampled.
Checked by running the code in Icarus Verilog 13 and Verilator 5; the printed output supports the answer above. Plain RTL with the same sampling structure: the sampler reads the pre-update state, so the sampled values are 0, 1, 2. Verilator 5 gives the same sampled values 0, 1, 2 (covergroups are not simulated, so the sample call is a $display).
A waveform cursor just after the edge shows 1,2,3, but the sampler used the value from before the edge. state starts at 0 (bit is 2-state) and is written only by always_ff. A sampler on the negedge would see the post-update values 1 and 2 only, because $finish at t=26 comes before the third negedge at t=30; its coverage would be 2/4 = 50% (s1, s2), with s0 and s3 missing.
What monitor timing change would capture post-update states without modifying DUT logic? Model answer: Sample after the update instead of at the edge: for example in an always @(negedge clk) block or one cycle later, so the monitor reads the value the edge produced. A clocking-block input would not help, since it samples the pre-edge (preponed) value like the current code.
I would first check which value the sampler sees at the edge. Sampling from a posedge process reads the value before the nonblocking update, so the hits are states 0, 1 and 2, not 1, 2 and 3, and coverage is 75 percent. State 3 is never sampled. The trap is trusting a waveform cursor just after the edge. Next I would move the sample to a defined point after the update.