Recently I ran into a problem when I try to use SVA to check duty cycle of a clock in interface. Please refer to codes below :
time rise, fall, low, high, duty_diff_abs, tolerance;
initial begin
tolerance = 1000 ps;
always @(clk) begin
if (clk) begin
rise <= $time;
low = rise - fall;
end else begin
fall <= $time;
high = fall - rise;
end
duty_diff_abs = (high - low >= 0)? (high - low) : (low - high);
end
duty_cycle_check : assert property ( (@posedge clk) duty_diff_abs <= tolerance) )
else $error($psprintf("rise = %0t, fall = %0t, low = %0t, high = %0t, duty_diff_abs = %0t, tolerance = %0t", rise, fall, low, high, duty_diff_abs, tolerance));
Two questions :
I just got error as "ncsim : *E, ASRTST [ERROR] xxxx : (time 918262377532 FS) Assertion duty_cycle_check has failed
rise = 918274351839, fall = 918274245043, low = -107016, high = 106796, duty_diff_abs = 220, tolerance = 1000
"
220 <= 1000, so seems to me that the assertion should pass, why it executed the $error action block ?
Assume the assertion just failed, the assertion only report once when error occurred ? Or it should report the error in every rise edge of the clk ?
Your code is confusing. You have an always within an initial, that is illegal.
Since it compiled OK, you must have shown a snippet. In that case, your assertion will fire at every posedge. Below is code that compiles OK, but I did not simulate. It should work.
That code fires once, but the testing of the clock is done after the clock settles for a while. I gave it 2 cycles, but you may want to increase that number. I also used an immediate assertion.
module mtime;
timeunit 1ns; timeprecision 100ps;
bit clk;
time t_now, low, high, duty_diff_abs, tolerance;
initial begin
repeat(2) @(posedge clk) t_now=$time; // let clock work for a while
tolerance = 1000ps;
@(negedge clk) high=$time - t_now;
t_now=$time;
@(posedge clk) low =$time - t_now;
duty_diff_abs = (high - low >= 0)? (high - low) : (low - high);
duty_cycle_check : assert(duty_diff_abs <= tolerance)
else $error($psprintf("rise = %0t, fall = %0t, low = %0t, high = %0t, duty_diff_abs = %0t, tolerance = %0t", rise, fall, low, high, duty_diff_abs, tolerance));
end
endmodule
The following code includes a concurrent assertion; I also maintained the original model within the initial. You could also instantiate the concurrent assertion within an initial statement.