Reset awareness when using 'sequence.triggered' in assertion - system-verilog

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

Related

What is the best way to check an event occurred in the past in SVA?

I want to check in my design that when signal b get asserted, then signal a should have gotten asserted 3 to 5 cycles before.
I'm looking for the different ways to check that.
Currently I'm using the following logic
sequence s_test();
##1 $rose(a) ##[3:5] 1;
endsequence
property p_test();
##1 $rose(b) |-> s_test.triggered();
Is there a way to check that property without using the sequence triggered mechanism ? I guess I could also use something like $past(a, 3) || ... || $past(a, 5), but that's cumbersome.
Also what's the difference between the sequence triggered and matched mechanism ?
We can have two approaches here: cause then effect or effect because of cause.
Cause then effect approach:
You can use a forward-time-based assertion stating that when s_test is triggered, then b should go high in 1-5 clock period of time window:
s_test.triggered |-> ##[1:5] $rose(b);
Effect then cause approach:
Alternatively, if s_test is a signal, then you can use a glue logic which monitors past 5 values of s_test. Thereafter, the assertion checks that the earlier values of s_test must have atleast 1'b1 when b rises from 0 to 1.
bit[1:5] earlier;
always #(posedge clk) begin
earlier <= {s_test, earlier[1:5]}; // shift for 5 clocks
end
p1_past20: assert property(#(posedge clk)
$rose(b) |-> $countones(earlier) >= 1);
A similar discussion is available here and a reference is over here.
You can use $past something like below.
property test_past;
#(posedge clk)
$rose(b) |-> ##[3:5] $past(a);
endproperty
triggered & matched methods differ for single clock & multi clock sequences.
Both methods show end point of a sequence, but triggered method evaluates to true if the operand sequence has reached it's end point at that particular time and false otherwise.
Whereas matched method detects endpoint of sequence, referenced in multiclocked sequence. So it provides synchronization between 2 sequences and evaluates to true after match, untill arrival of 1st clock tick of destination sequence.
triggered status of a sequence is set in observed region and is persisted through the remainder of the timestep. Whereas matched status of a sequence is set in observed region and is persisted untill the observed region of the arrival of first clock tick of destination sequence after match.

System Verilog: I am confused about the $stable statement

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?

How to check if a signal does not change using Immediate Assertions in SystemVerilog Assertions

I'm new to SystemVerilog Assertions and I know that I can check if a signal doesn't change between clock ticks using Concurrent Assertions:
assert property (#(posedge clk) enable == 0 |=> $stable(data));
But how would I do so continuously using Immediate Assertions? This is an example that I found online but I'm not sure if it's what I need and how it works:
assign not_a = !a;
always_comb begin : b1
a1: assert (not_a != a);
a2: assert #0 (not_a!= a); // Should pass once values have settled
end
What you are asking for does not make any sense. If it a signal never can change, then it must be a constant. With the example you show, a1 might fail - there is a race condition between a and not_a. a2 is deferred assertion - it takes care of the race and will never fail. But the problem with both these assertions is that if a changes at some time, a2 never fails and you may are may not see a failure with a1

Usage of $past in System Verilog Assertions

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 |=>

SVA Repetition Non-Consecutive Operation Qualifying Event

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.