What is the subtle difference between following statements
a -> b vs a ##0 b
in SVA (SystemVerilog Assertions)?
First thing that you have to check is syntax of single implication operator that is a |-> b.
In SystemVerilog assertion there are two expressions.
a ##0 b
a |-> b
Actually, it looks like a similar in expressions. First of this expression is checking a is asserted(1) and after 0 clock cycle b is asserted(1) or not. Second expression is checking b is (on)asserted when a is asserted(1) then on same posedge b is asserted(1) or not.
Now, practically when verification engineers wrote this kind of assertions they take care of following things.
a ##0 b: In this expression if a is not asserted then it shows failure.
When a is asserted(1) and on same time stamp b is not asserted then also shows failure.
a |-> b: In this expression if a is asserted and b is not asserted then it will show a failure.
If a is not asserted then it is not going to check whether b is asserted or not. This behavior is different than a ##0 b.
If you apply different inputs data then you can see that expression a ##0 b will give you more failure than a |-> b. Reason for same is already explained above.
One more thing to note down is "The implication construct can be used only with property definitions. It cannot be used in sequences."
Thanks,
Ashutosh
Your question illustrates the importance of the implication operator (|->). This example uses an implication operator and is useful:
a -> b means "if a is true then b should be true" (useful).
This does not and is usually not very useful:
a ##0 b means "a and b should be both true at all times" (not very useful).
https://www.edaplayground.com/x/47iN
Related
I understand that the $stable(expression) statement returns 'True', if the expression being evaluated has the same value as in the previous clock cycle. However, I don't understand why the following is being said in most learning materials:
assert property(#(posedge clk) enable == 0 |=> $stable(data));
states that data shouldn’t change whilst enable is 0.
As I have proved it, because |=> is being used, this will not work for the following example:
enable 1110000111
data__ ABCAAAABB
assert ______X___
(where A, B and C are some values of the data bus, and X is the point where the assertion would fail)
As you can see, the data has the value A while enable = 0, so it remains stable. But the assertion would not work as desired, because the data changes from A to B at the same time that enable changes from 0 to 1.
So my question is, how would you really implement or code the expression the data shouldn't change while enable is 0.?
Thanks in advance.
Maybe you are thinking of
assert property(#(posedge clk) (enable == 0)[*2] |-> $stable(data));
This means for two consecutive cycles when enable==0, data should not change.
I think "the desired behavior" of the original assertion is not very clear. The state of enable is one clock cycle and $stable is a condition evaluated over 2 clock cycles. There is a similar argument if overlapping implication |->was used. So the question becomes what happens if (enable==0) is true for only one clock cycle? How do you want stability of data defined?
I have a few assertions that use the triggered property of sequences. This is useful for checking properties of the form "when X happens, Y must have happened sometime in the past".
Let's take a simple example:
Given three signals, a, b and c, c is only allowed to go high if a was high 3 cycles ago and b was high 2 cycles ago. This is a trace that satisfies this property:
To be able to check this, we'd need a helper (clocked) sequence that should match at the point where a c is legal:
sequence two_cycles_after_a_and_b;
#(posedge clk)
a ##1 b ##2 1;
endsequence
We could then use this sequence in an assertion:
c_two_cycles_after_a_then_b : assert property (
c |-> two_cycles_after_a_and_b.triggered )
$info("Passed");
This assertion works fine in most cases, but it's going to go haywire when dealing with resets.
Let's say that we also have a reset signal that becomes active exactly in the clock cycle between b and c:
The naive approach in this case would be to implement reset awareness outside of the assertion, inside a default disable iff clause:
default disable iff !rst_n;
The expectation would be that, since reset was active before c, the a ##1 b that happened before doesn't count and that the assertion fails. This isn't what happens, though, as the evaluation of the sequence is independent of reset.
To achieve this behavior, the sequence must be made reset aware:
sequence two_cycles_after_a_and_b__reset_aware;
#(posedge clk)
rst_n throughout two_cycles_after_a_and_b;
endsequence
and the assertion needs to use the reset aware version:
c_two_cycles_after_a_then_b__reset_aware : assert property (
c |-> two_cycles_after_a_and_b__reset_aware.triggered )
$info("Passed");
The second assertion will indeed fail, because the two_cycles... sequence won't match due to the occurrence of reset.
This obviously works, but it requires a lot more effort and it requires reset to become an integral part of the sequences/properties instead of being controlled on a per-scope basis. Is there any other way to achieve reset awareness in this case that is closer to using a disable iff?
Best solution I can come up with is to add a little auxiliary code to sample rst_n and keep it low long enough for it to be sampled by the clock.
always #(posedge clk, negedge rst_n) begin
if(!rst_n) smpl_rst_n <= 1'b0;
else smpl_rst_n <= 1'b1;
end
Then use a generic sequence for the reset aware that uses smpl_rst_n and a a reference to a target sequence.
sequence reset_aware(sequence seq);
#(posedge clk)
smpl_rst_n throughout seq;
endsequence
Final assertion would work as follows:
a_two_cycles_after_a_then_b__reset_aware : assert property (
c |-> reset_aware(two_cycles_after_a_and_b).triggered )
$info("Passed");
Proof of concept: https://www.edaplayground.com/x/6Luf
I want to check if the current value of variable is '1' then the previous value of the variable should be '0'. I am using $past in System Verilog Assertions. Here I am checking if cal_frame_mode=1, then it's previous value of cal_frame_mode=0. My code is below. However, I am seeing assertion failure. When I check in the waveform it's behaving correctly. Assertion flags 2 clock after the the first check. How to stop this assertion after checking just one clock cycle?.
property p_NOP_2_RX_CAL;
#(posedge clk)
(cal_frame_mode==3'b001) |-> ##2 $past(cal_frame_mode)==3'b000;
endproperty
assert_nop2cal : assert property(p_NOP_2_RX_CAL);
##2 means wait two clocks. The default of $past looks at the value of the expression one clock back from the current clock (by default this is the clock defined in the property). Therefore:
(cal_frame_mode==3'b001) |-> ##2 $past(cal_frame_mode)==3'b000;
Is equivalent to:
(cal_frame_mode==3'b001) |-> ##1 cal_frame_mode==3'b000;
What you want is: (cal_frame_mode==3'b001) |-> $past(cal_frame_mode)==3'b000; but I'm guessing the reason you had the ##2 is to filter out cal_frame_mode equaling one for two clocks. If so, then the better solution is to add $change or !$stable to the antecedent, this what the check is only performed when the cal_frame_mode changed and the current value is one.
$changed(cal_frame_mode) && (cal_frame_mode==3'b001) |-> $past(cal_frame_mode)==3'b000;
Assertions are documented in IEEE Std 1800-2012 § 16 Assertions
§ 16.9.3 Sampled value functions describes $sample, $rose, $fell, $stable, $changed, and $past in detail
§ 16.12.6 Implication describes |-> and |=>
I have the following property:
property p;
#(posedge clk) a |=> b[=2] ##1 c;
endproperty
It tell us that if a is asserted, then start from the next clk, b should be asserted non-consecutively two times followed by c is asserted anytime after the last b.
My question is what if c is asserted in between the first b and the second b. Should the assertion fail immediately or continue on?
Some reference book says that it should fail, but I doubt it. What is the expected behavior?
The [= or non-consecutive repetition operator is similar to goto repetition, but the expression need not be true in the clock cycle before c is true.
Let's say a is asserted. The implication condition is satisfied and assertion is further evaluated.
Thereafter, b is checked two times, no matter what c is. Once b is found to be asserted for two non-consecutive clock edges, thereafter c is checked after 1-clock cycle (due to ##1).
If c is asserted and de-asserted when b is being checked for 2 times, then that toggling is not considered. What of c is considered is after 2 assertions of b.
Following snaps shall give a clear idea:
Passing snap:
Fail snap:
Here, even though there was a glitch in c, the assertion didn't went through.
Refer to A Practical Guide for SystemVerilog Assertions pdf for more details.
Doulos tutorial is also a good one.
In short, yes it will pass. Regardless of where c is asserted, after two "b"s are observed, it will wait until c==1. So, if c was 1 from the beginning and never goes to zero, it will pass too.
One more point to make is when this assertion will actually fail. It will pass when c is asserted, but if not, it will keep running until the end of the test! You will see the failure only at the end of simulation.
Recently the question came up what the difference is between the usual implication operator (|->) and the implies operator in SystemVerilog. Unfortunately I couldn't find a clear answer yet. However, I collected the following information:
From SystemVerilog LRM 1800-2012:
§ 16.12.7 Implies and iff properties:
property_expr1 implies property_expr2
A property of this form evaluates to true if, and only if, either property_expr1 evaluates to false or property_expr2 evaluates to true.
§ F.3.4.3.2 Derived Boolean operators:
p1 implies p2 ≡ (not p1 or p2)
§ F.3.4.3.4 Derived conditional operators:
(if(b) P) ≡ (b |-> P)
However, the LRM does not really point out what the actual difference is. I assume that they differ in the evaluation in case of a false antecedent (success vs. vacuous success), but I could not find any source or evidence for this assumption. Moreover, I know that the implies operator is very common in combination with formal verification tools like OneSpin.
Could anyone help me out?
P.S.: It seems there is an answer to this question in the following book: SystemVerilog Assertions Handbook, 3rd Edition. But $155 is a bit too much for me just for getting the answer to this question :)
I think there is even a more significant difference. Assume that we have the following example:
property p1;
# (posedge clk)
a ##1 b |-> c;
endproperty
property p2;
# (posedge clk)
a ##1 b implies c;
endproperty
assert property (p1);
assert property (p2);
Both implication operators simply have different proving behavior. Property p1 will be triggered through a match of a ##1 b and will look for a matching c during the same clock tick as b. However, property p2 is triggered by a ##1 b and will check for a match of c during the clock cycle of a. This means the properties would pass for the following scenarios:
Property p1 passes and p2 fails:
Property p2 passes and p1 fails:
A hint for this behavior can be found in the SystemVerilog LRM. The defined substitutions are:
(if(b) P) = (b |-> P)
p1 implies p2 = (not p1 or p2)
So all in all, if one uses the implies operator it becomes easier to define multi-cycle operations since antecedent and consequence have the same starting point for the evaluation.
I tried it out and apparently the |-> is not allowed for properties (only for sequences and boolean expressions). Here's what I tried:
property a_and_b;
#(posedge clk)
a && b;
endproperty
property a_and_c;
#(posedge clk)
a && c;
endproperty
First form using |-> doesn't compile:
// this doesn't compile
assert property(a_and_b |-> a_and_c);
Second form using implies does compile:
// this does compile
assert property(a_and_b implies a_and_c);
Semantic-wise, it's as it is for the |-> operator. When a_and_b fails, the assertion vacuously passes. If a_and_b succeeds but b_and_c doesn't, then a fail is issued.