when are assertion "disable iff" values evaluated? - system-verilog

For this code, I see both assertions fail. It seems that disable iff (value) is evaluated later than the expression itself. Can someone explain this.
module tb();
reg clk = 1;
always #5 clk = !clk;
reg rst = 1;
always # (posedge clk)
rst <= 0;
initial #11ns $finish();
assert property (# (posedge clk) disable iff (rst) 1 |-> 0);
assert property (# (posedge clk) rst |-> 0);
endmodule
Followup, how would one test this:
always_ff # (posedge clk or posedge rst) begin
if (rst) q <= 0;
else q <= d;
end
where rst is deasserted based on a delay:
always_ff # (posedge clk)
rst <= rst_a;
Seems like disable iff would no longer work. as it evaluates rst late.

The expression within disable iff (expr) is asynchronous and uses unsampled values. The property gets evaluated as part of the observed region, which comes after the NBA region.
For the first assertion, rst is already low by the time of the first attempt to evaluate the property at time 10 in the observed region. So the disable iff does not prevent an attempt to evaluate the property, which always fails.
For the second property, the sampled value of rst is still 1 at the time of the first attempt to evaluate the property, so it must fail too.
Followup,
I think you may be worrying about an impractical case. How likely will the antecedent be true after reset? And if it were true, then the assertion should be still be valid. For example, suppose you had a counter with an assertion to check that it rolls over when hitting the maximum value
assert property (# (posedge clk) disable iff (rst) (counter==maxval) |=> (counter ==0) );
If the reset value of the counter was the maximum value, you would not want the assertion disabled.

Related

system verilog expect behavior

I tried using expect with the following property
module tb;
logic a;
logic clk=0;
default clocking #(posedge clk); endclocking
always
#5ns clk = ~clk;
initial begin
$dumpfile("dump.vcd"); $dumpvars;
$display("START");
a = 0;
#100ns;
a = 1;
#100ns;
$finish;
end
initial begin
#10ns;
expect(#(posedge clk) 1 ##1 $changed(a) |-> 1) $display("SUCCESS"); else
$display("FAIL");
end
endmodule
Is the expect going to block until a change from 0 to 1 at 100ns ?
No, it will block until the second (posedge clk), regardless of the value of a, and will always pass.
The expect statement does not start evaluating the property until the first clk edge. The antecedent takes two cycle to either match or not match. Since the consequent is always true, the property passes on match. If there is no match, the property also passes, vacuously.

SV assertion based on event trigger

Assume SV interface contains a concurrent assertion property.
Is it possible to enable this assertion only when an event is triggered? I tried writing property inside a task in interface file, but I ended up with error: near "property": syntax error, unexpected property.
Interface intf;
task e1();
-> e1;
endtask
wait(e1.triggered); // something like this, where property waits for trigger
property prop1;
#(posedge clk) a ##1 b;
endproperty
endinterface
Thank you.
I think you need to consider that properties are best written synchronously and are evaluated on every clock cycle. You property says that one cycle after every clock cycle where a occurs b occurs. I guess what you're after is something like:
if e1 occurs, then a should be true (on the next rising edge of
clk?) and then b should be true on the rising edge of clk after
that
So, one way of doing that would be to create an always block that generates a pulse one clock wide should e1 occur, eg:
always begin
#(e1);
#(posedge clk) e = 1'b1;
#(posedge clk) e = 1'b0;
end
property prop1;
#(posedge clk) e |-> a ##1 b;
endproperty
or some variation of that. I feel like I should be worried about races, however.

Data Mux SVA compare

I've trouble designing assertions(SVA) for this scenario.
When a mux sel is asserted, the data_in is expected to be stable for 2 clocks ; clock prior to mux sel being asserted, and the current clock when mux sel is asserted.
Now the data_in is a wide vector/bus signal, whereby some bits of the bus are Z and X during functional mode (this is expected), while this bits may carry value during non-functional mode.
This then implies, the approach to design the SVA would be to compare bit by bit of data bus when mux sel is asserted.
This is my approach, but SVA fails and am not sure why.
generate
for( genvar i=1 ; i<BUS_WIDTH ; i++ ) begin
always # (posedge clk) begin
if(!$isunknown(data_in[i]) && reset) begin
data_in_temp_prev[i] <= data_in[i];
if (mux_sel==1 && reset==1 && i>0) begin
SVA_TEST: assert property (data_in[i] == data_in_temp_prev[i-1]) else `uvm_error("TRIAL_SVA",$sformatf("datain expected to be stable for 2 clks prior to mux sel"));
end //if
end //if isunknown
else begin
din0_temp_prev[i] <= 0;
end
end //always
end // for genvar
endgenerate
Any suggestions on how to approach designing this SVA ?
Thanks.
If I understood correctly your problem, you don't need all this structure for this kind of problem, look at my example below and tell me if helps or not.
property mux_compare;
disable iff(!reset)
#(posedge mux_sel)
!$isunknown(data_in)
|->
#(posedge clk)
$stable(data_in) [*2];
endproperty: mux_compare
My approach to SVA checkers is to use a standard structure to properties to avoid all kinds of problems. the structure is to always use clocked properties with "disable iff" and always use an implication operator, where the left hand side is the trigger and the right hand side is what we want to verify.
Here's an example from the LRM:
property abc(a, b, c);
disable iff (c) #(posedge clk) a |=> b;
endproperty
similarly to the answer above, I would do this:
property mux_compare;
disable iff(!reset) #(posedge clk)
mux_sel===1 |->
!$isunknown(data_in[i]) || $stable(data_in) && data_in[i] == $past(data_in[i],2);
endproperty: mux_compare

Avoiding support code for SVA sequence to handle pipelined transaction

Let's say we have a protocol that says the following. Once the master sets req to fill, the slave will signal 4 transfers via rsp:
An SVA sequence for this entire transaction would be (assuming that the slave can insert idle cycles between the trans cycles):
req == fill ##1 (trans [->1]) [*4];
Now, assume that the master is allowed to pipeline requests. This would mean that the next fill is allowed to start before the 4 trans cycles are done:
The SVA sequence from above won't help, because for the second fill it's going to wrongly match 4 trans cycles, leaving the last trans "floating". It would need to start matching trans cycles only after the ones for the previous fill have been matched.
The sequence needs global information not available in a single evaluation. Basically it needs to know that another instance of it is running. The only way I can think of implementing this is using some RTL support code:
int num_trans_seen;
bit trans_ongoing;
bit trans_done;
bit trans_queued;
always #(posedge clk or negedge rst_n)
if (!rst_n) begin
num_trans_seen;
trans_ongoing <= 0;
trans_done <= 0;
trans_queued <= 0;
end
else begin
if (trans_ongoing)
if (num_trans_seen == 3 && req == trans) begin
trans_done <= 1;
if (req == fill || trans_queued)
trans_queued <= 0;
else
trans_ongoing <= 0;
num_trans_seen == 0;
end
else
if (trans_queued) begin
trans_queued <= 0;
trans_ongoing <= 1;
end
if (trans_done)
trans_done <= 0;
end
The code above should raise the trans_ongoing bit while a transaction is ongoing and pulse trans_done in the clock cycle when the last trans for a fill is sent. (I say should because I didn't test it, but this isn't the point. Let's assume that it works.)
Having something like this, one could rewrite the sequence to be:
req == fill ##0 (trans_ongoing ##0 trans_done [->1]) [*0:1]
##1 (trans [->1]) [*4];
This should work, but I'm not particularly thrilled about the fact that I need the support code. There is a lot of redundancy in it, because I basically re-described a good chunk of what a transaction is and how pipelining works. It's also not as easily reusable. A sequence can be placed in a package and imported somewhere else. The support code can only be placed in some module and reused, but it's a different logical entity than the package that would store the sequence.
The question here is: is there any way to write the pipelined version of the sequence while avoiding the need for support code?
It looks like rsp is always idle before the trans starts. If rsp's idle is a constant value and it is a value that trans will never be, then you could use:
req == fill ##0 (rsp==idle)[->1] ##1 trans[*4];
The above should work when the pipeline supports 1 to 3 stages.
For a 4+ deep pipeline, I think you need some auxiliary code. The success/fail blocks of the assertion can be used to incompetent the count of completed trans; this saves you from having write additional RTL. A local variable in the property can be used to sample the fill's count value. The sampled value will be used as a criteria to start sampling the expected trans pattern.
int fill_req;
int trans_rsp;
always #(posedge clk, negedge rst_n) begin
if(!rst_n) begin
fill_req <= '0;
trans_rsp <= '0;
end
else begin
if(req == fill) begin
fill_req <= fill_req + 1; // Non-blocking to prevent risk of race condition
end
end
end
property fill_trans();
int id;
#(posedge clk) disable iff(!rst_n)
(req == fill, id = fill_req) |-> (rsp==idle && id==trans_rsp)[->1] ##1 trans[*4];
endproperty
assert property (fill_trans()) begin
// SUCCESS
trans_rsp <= trans_rsp + 1; // Non-blocking to prevent risk of race condition
end
else begin
// FAIL
// trans_rsp <= trans_rsp + 1; // Optional for supporting pass after fail
$error("...");
end
FYI: I haven't had time to fully test this. It should at least get you in the right direction.
I experimented a bit more and found a solution that might be more to your liking; no support code.
The equivalent of trans[->4] is (!trans[*] ##1 trans)[*4] per IEEE Std 1800-2012 § 16.9.2 Repetition in sequences. Therefore we can use the local variables to detect new fill requests with the expanded form. For example the following sequence
sequence fill_trans;
int cnt; // local variable
#(posedge clk)
(req==FILL,cnt=4) ##1 ( // initial request set to 4
(rsp!=TRANS,cnt+=4*(req==FILL))[*] // add 4 if new request
##1 (rsp==TRANS,cnt+=4*(req==FILL)-1) // add 4 if new request, always minus 1
)[*] ##1 (cnt==0); // sequence ends when cnt is zero
endsequence
Unless there is another qualifier not mentioned, you cannot use a typical assert property(); because it will start new assertion threads each time there is a fill request. Instead use an expect statement, which allows waiting on property evaluations (IEEE Std 1800-2012 § 16.17 Expect statement).
always #(posedge clk) begin
if(req==FILL) begin
expect(fill_trans);
end
end
I tried recreating your describe behavior for testing https://www.edaplayground.com/x/5QLs
One possible solution can be achieved with 2 assertions as below.
For 1st image -
(req == fill) && (rsp == idle) |=> ((rsp == trans)[->1])[*4]
For 2nd image -
(req == fill) && (rsp == trans) |=> ((rsp == trans)[->1])[*0:4] ##1 (rsp == idle) ##1 ((rsp == trans)[->1])[*4]
One issue is that if there are continuous "fill" requests on each cycle (consecutive 4 "fill" requests, without any intermediate "idle"), then the 2nd assertion will not calculate "trans" cycles for each "fill" requests (instead it'll only be completed on the 2nd set of "trans" cycles itself).
I could not modify the assertion for the given bug, as of now.

system verilog assertions: Using a reg value in a repition operator

I am trying to do something like this:
assert property (#(posedge clk) disable iff (!rst) a[*c] -> $rose(b))
Here c is not a 'constant' but a value coming from some bits of a register. eg: reg[4:0] which is written only once. The check is to see if b is asserted only when a is high for "c" number of cycles.
However, SVAs do not accept a variable like this : [*reg[4:0]]. Any ideas??
Introduce a local variable ctr. At every posedge a new assertion with a new instance of ctr will be created. Set ctr equal to the value in reg1. Check that a is true throughout the down count. Decrement the counter as long as it is larger than zero. The (ctr>0, ctr--)[*0:$] statement will count down until ctr == 0 is true.
You might want to change (ctr>0, ctr--)[*0:$] to (ctr>0, ctr--)[*1:$], depending on what results you expect if reg == 0.
property pr_aRegTimes;
integer ctr;
disable iff (!rst)
#(posedge clk)
(1, ctr = reg1) ##0 a throughout ((ctr>0, ctr--)[*0:$] ##1 (ctr == 0)) |-> $rose(b);
endproperty
as_aRegTimes: assert property (pr_aRegTimes)
else $error("aRegTimes failed");
Working example:
http://www.edaplayground.com/x/Xh9
Sources:
https://www.doulos.com/knowhow/sysverilog/tutorial/assertions/
http://www.win.tue.nl/~jschmalt/teaching/2IMF20/SvaFvTutorialHVC2013.pdf
property pr_aRegTimes;
integer ctr;
disable iff (!rst)
#(posedge clk)
($rose(a), ctr = reg1) ##0 (a&&ctr>0,ctr--)[*] |-> $rose(b);
endproperty