I’m reading a section of a book on timing of testbench signal driving (Chris Spear’s System Verilog for Verification) and ran across something I don’t quite understand.
Here we have a simple example test that drives a arbiter request signal:
The book’s premise in this example is that because the change to request at 250ns occurs precisely at the same time as the posedge of the design clock, the DUT takes the value of the new signal (1) instead of what it was being sent from the testbench just prior to the posedge (2). So the 2 never gets picked up.
Can someone explain to me why that is the case? From my understanding, RTL changes occur in the Active region before the testbench code executes (in the Reactive region). So my understanding is that at 250ns, first the DUT should clock in the 2, then the testbench changes the request signal to 1 which wouldn’t get picked up until the next clock cycle.
Am not totatlly clear as to why #100 a <=1; is different than @ (cb1) a <= 1; when the 2 time occurrences are at the same identical time (e.g., 250ns).
After more thoughts, it looks like the #100 a <=1; behaves in a blocking type of fashion and the transaction completes. However, for the @ (cb1) a <= 1; the “a” get assigned in the NBA region. This results in different values being assigned to “b”. See from my book the various regions.
In reply to ben@SystemVerilog.us:
Thanks for the detailed reply Ben! I also find it strange that the non-blocking assignment is evaluated as a blocking one.
Does anybody know why the following line would behave as blocking?
#250ns arbif.cb.request <= 1;
It is puzzlng. The following works though
initial begin
repeat (2) begin
@ (cb1) a <= 3;
@ (cb1) a <= 2;
//@ (cb1) a <= 1; // NONBLOCKING assignment
#100 -> e;
@e a <=1; // WITH TH @e
#200;
end
end
t= 153, a= 2, b= 3
t= 250, a= 2, b= 3 // <**** a==2 here
t= 251, a= 2, b= 2
t= 253, a= 2, b= 2
//------------ BUT without the @e
@ (cb1) a <= 2;
//@ (cb1) a <= 1; // NONBLOCKING assignment
#100 -> e;
a <=1; // NO @e !!!!!
#200;
...
t= 153, a= 2, b= 3
t= 250, a= 1, b= 3 // <**** a==1 here ????
t= 251, a= 1, b= 1
t= 253, a= 1, b= 1
The answer is somewhat related to 1800:4.7 Nondeterminism, but I don’t see the explanation.
Particularly, 4.7 Nondeterminism states One source of nondeterminism is the fact that active events can be taken off the Active or Reactive event region and processed in any order. Another source of nondeterminism is that statements without time control constructs in procedural blocks do not have to be executed as one event. Time control statements are
the # expression and @ expression constructs (see 9.4)
That last line states that with time control (the @ and the #) it is deterministic.
It appears that though they are “deterministic”, they are treated as separate time control; meaning that the (Delay statements) are executed first, and the **(@ event statements)**is executed next. At least that is how simulators seem to work. I don’t believe 1800 addresses that specifically. Maybe the key lies in the fact that the # and the @ are different things, and the # tends to be blocking, whereas the @ is nonblocking.
I’ll seek an answer from people in the 1800 language committee (I am in the assertions committee).
Ben Cohen http://www.systemverilog.us/ben@systemverilog.us
In reply to ben@SystemVerilog.us:
A follow up with assertions. The issue:
With the #100 “a” does not appear to be updated in the NBA Region.
It appears (or behaves) as update in the Active Region.
Assertion samples the “a” in the Preponed, thus flags the error as expected.
Attached files show the simulation results. http://systemverilog.us/test_blk_ok.sv http://systemverilog.us/test_blk_err.sv
I get the same results in 3 different simulators.
@ (cb1) a <= 2;
#100 a <=1; // occurs at 250ns
//------
@ cb1; // occurs at 250ns
b <= a;
----------
ap_ab: assert property(@ cb1 a==2 |=> b==2);
** Error: Assertion error.
# Time: 350 ns Started: 250 ns Scope: top.ap_ab File: test_blk_err.sv Line: 19 Expr: b==2
In reply to ben@SystemVerilog.us: The answer:
The LRM specifies that “@(cb1)” trigger in the Observed region (see “14.13 Input sampling” explanation and example). This is guaranteed to happen later (in a later state of the stratified event queue) then “#100”, “@(posedge clk)”, or an NBA update triggered by either of these.
Thus, at time 250 in your example, the variable “a” must have been updated by the time “b <= a” (or the immediately subsequent $display) is executed.
-randy.
My original question
The issue I am raising is demonstrated at clocking block - EDA Playground
Basically you have 2 NBA updates that occur at the same time (250ns in the example).
One is in an initial with the #100 a <=1; // a was 2
The other in another initial statement with
@ (cb1) b <=a;
What I see is b==1 and not 2.
Thus, it looks like though 2 NBA updates occur @t==250, the one with the #100 a <=1 finishes first in a blocking fashion.
I am addressing a language issue not a coding style issue.
Ben
@ (cb1) a <= 2;
@ (cb1) a <= 1; // a gets assigned in the NBA at sim time 250ns
// a==2 at time 250
also @ cb1;
b <= a; // b is assigned 2
However, with
@ (cb1) a <= 2; #100 a <=1; // a gets assigned in the Active region at sim time 250ns
// a==1 at time 250
also @ cb1;
b <= a; // b is assigned 1