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
Ben Cohen http://www.systemverilog.us/
- SystemVerilog Assertions Handbook, 3rd Edition, 2013
- A Pragmatic Approach to VMM Adoption
- Using PSL/SUGAR … 2nd Edition
- Real Chip Design and Verification
- Cmpt Design by Example
- VHDL books