Difficulty: Medium · Puzzle 4 of 6 · Topic: Clocking Block Puzzles
Two monitors sample the same grant with different input skews. Which one sees the same-edge NBA-updated grant? All signals are initialised so the answer does not depend on 2-state or 4-state.
`timescale 1ns/1ns
interface ifc(input bit clk);
logic req = 1;
logic grant = 0;
clocking mon0 @(posedge clk);
default input #0;
input grant;
endclocking
clocking mon1 @(posedge clk);
default input #1step;
input grant;
endclocking
always @(posedge clk) grant <= req;
endinterface
program automatic check(ifc vif);
initial begin
@(vif.mon0);
$display("[%0t] mon0.grant=%0b mon1.grant=%0b", $time, vif.mon0.grant, vif.mon1.grant);
$finish;
end
endprogram
module tb;
bit clk = 0;
always #5 clk = ~clk;
ifc vif(clk);
check c(vif);
endmoduleinput #0 samples after the NBAs (Observed region); input #1step samples before the edge (Preponed).
1) At t=5 the interface's always block reads req=1 and queues grant<=1.
2) mon1 (#1step) holds the Preponed value of grant: 0.
3) mon0 (#0) is sampled in the Observed region, after the NBA committed: 1.
4) The reader is a program (Reactive region), so it runs after both samples exist and the result is the same in every tool. Verilator prints mon0.grant=1 mon1.grant=0.Answer: mon0.grant=1 and mon1.grant=0 at t=5. Skew choice changes which side of the NBA you sample.
Checked by running the code in Verilator 5; the printed output supports the answer above. input #0 sees the post-NBA grant (1), input #1step sees the pre-edge value (0).
Using #1step 'for safety' gives the pre-edge value, i.e. one cycle stale for flopped DUT outputs. And do not read these from a module initial and call the result portable: the wake-up region of @(clocking event) is only guaranteed late enough in a program.
Which skew is better for scoreboard checks against flopped DUT outputs and why? Model answer: #1step (Preponed) is the usual default because it is race-free and matches what a synchronous DUT register would have captured at that edge; #0 also reflects NBA results but depends on reading after Observed and is fragile across mixed module/program code.
Mon0 sees the new grant, 1, and mon1 sees the old one, 0. The input skew of #1step takes the Preponed value from before the NBA, while #0 samples in Observed, after the NBA has committed. So the skew choice decides which side of the NBA you sample. The trap is using #1step for safety, which gives a one-cycle-old value for flopped DUT outputs. I would also read it from a program, because a module initial does not guarantee a late enough wake-up.