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.