I am trying to write an assertion that will fire only if a signal transitions on the rising edge of 'clk'. I wrote below code to test out my ideas
module test();
bit clk, clkb;
int d;
assign clkb = ~clk;
initial begin
clk = 0;
forever #100 clk = ~clk;
end
initial begin
d = 10;
#150 d = 20;
end
sva_d_chgd: assert property (@(posedge clk) $stable(d,@(clkb)))
else $error($psprintf("err: time = %0d, clk = %b, d = %0d", $time, clk, d));
always @ (d or clk) begin
$display("time = %0d, clk = %b, d = %0d", $time, clk, d);
if ($time > 200) $finish;
end
endmodule
Above code returns the following output in VCS:
time = 0, clk = 0, d = 10
time = 100, clk = 1, d = 10
"test.vs", 18: test.sva_d_chgd: started at 100s failed at 100s
Offending '$stable(d, @(clkb))'
Error: "test.vs", 18: test.sva_d_chgd: at time 100
err: time = 100, clk = 1, d = 10
time = 150, clk = 1, d = 20
time = 200, clk = 0, d = 20
time = 300, clk = 1, d = 20
$finish called from file "test.vs", line 23.
$finish at simulation time 300
Why did the assertion fire at time 100 when 'd' remained stable until time 150?
In your code, stable checks at every posedge of clk to see if the value of "d" has changed or not between the previous two edges of clkb. Since at the very first posedge of clk there was no previous clkb edge value of "d", stable returns "unknown" instead of "true" or "false" which causes your assertion to fail.
I've added a reset signal to your code and disabled the assertion until after the first posedge of clk. I also moved when "d" changes.
module test();
bit clk, clkb, rst;
int d;
assign clkb = ~clk;
initial begin
clk = 0;
forever #100 clk = ~clk;
end
initial begin
rst = 1;
#150 rst = 0;
end
initial begin
d = 10;
#250 d = 20;
end
sva_d_chgd: assert property (@(posedge clk)
disable iff (rst)
$stable(d,@(clkb)))
else $error($psprintf("err: time = %0d, clk = %b, d = %0d", $time, clk, d));
always @ (d or clk) begin
$display("time = %0d, clk = %b, d = %0d", $time, clk, d);
if ($time > 400) $finish;
end
endmodule
Here's the output:
# time = 0, clk = 0, d = 10
# time = 100, clk = 1, d = 10
# time = 200, clk = 0, d = 10
# time = 250, clk = 0, d = 20
# time = 300, clk = 1, d = 20
# ** Error: err: time = 300, clk = 1, d = 20
# Time: 300 ns Started: 300 ns Scope: test.sva_d_chgd File: assert_test.sv Line: 26
# time = 400, clk = 0, d = 20
# time = 500, clk = 1, d = 20
# ** Note: $finish : assert_test.sv(30)
# Time: 500 ns Iteration: 1 Instance: /test
This gets around the first unwanted failure of your assertion but I think the way you coded your assertion it is still not actually trapping the condition you're looking for.