Data Mux SVA compare - system-verilog-assertions

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

Related

SystemVerilog 2-bit register decoding problem

I have two 2-bit inputs and an output of 1-bit. So what I'm trying to do is code a next state value with taking AND of the two inputs, then use non-blocking <= to assign that value into register xy_r, which is now two D-flipflops. So I am seeking to get always the XOR-value of the xy_r previous clock edge as my output xor_out. I suppose that the way below is not the right one?
It worked in the simulation but then again in RTL Synthesis I didn't end up with an XOR gate but a third flip-flop so it seems like xor_out is treated as a register.
I suppose I can't use assign outside of the if-else-statements because in that case the output wouldn't follow the xy_r previous state but the present.
Can you please assist me how to solve this issue, if there is a somewhat simple way.
module 2ffsxor
(input logic clk,
input logic rst_n,
input logic [1:0] x_in,
input logic [1:0] y_in,
output logic xor_out
);
logic [1:0] xy;
logic [1:0] xy_r;
always # (posedge clk or negedge rst_n)
begin
if (rst_n == '0)
xy_r <= '0;
else
begin
xy = x_in & y_in;
xy_r <= xy;
xor_out = xy_r[0] ^ xy_r[1];
end
end
endmodule
And here's a schematic what it should be:
Schematic 2ffsxor
Synthesis treats this code as if you had wrote
begin
xy_r <= x_in & y_in;
xor_out <= xy_r[0] ^ xy_r[1];
end
That's two stages of registers. But since you assigned xor_out with a blocking assignment, you have a simulation race condition for any process that tries to read xor_out. The race would be from the result from the previous values of xy_r and the result before that!
If you use an continuous assign statement outside this always block, any process reading xor_out on the clock edge will see the result from the previous state of xy_r.
But why not write this as on register:
always # (posedge clk or negedge rst_n)
begin
if (rst_n == '0)
xor_out <= '0;
else
begin
xy = x_in & y_in;
xor_out <= xy[0] ^ xy[1];
end
end

when are assertion "disable iff" values evaluated?

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.

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.

$past with an input signal

I want to verify that if an event occurrs, then at “num_ticks” in the past, some signal should have been asserted.
As an example, the property I wrote is:
property test_past;
#(posedge clk)
$rose(gnt) |-> $past(req, num_ticks);
endproperty
The problem here is with num_ticks. If num_ticks is an input signal to the module in which the property is written, then the assertion fails. If I declare num_ticks as an int, and assign it to a constant, it passes.
Does $past only work for constant values? This is not mentioned in the LRM.
I am using Questasim 10.3
You might use multiple assertions for this purpose.
Suppose num_ticks is 4 bits wide, then you can do like this.
genvar x;
generate
for (x=0; x<16; x++)
begin
property test_past;
#(posedge clk)
(num_ticks == x) && $rose(gnt) |-> $past(req, x);
endproperty
end
endgenerate

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.