A problem when I use SVA to check duty cycle of a clock

Hi, Dear,

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 :

  1. 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 ?

  2. 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 ?

Thanks,

WangYang

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

In reply to ben@SystemVerilog.us:

Hi, Ben,

Sorry for the confusion, I actually just want to use initial begin as an example.

I didn’t have this initial begin code in my environment, the tolerance variable is passed in sequence.

I am learning how to use the SVA, so try to use concurrent assertion, but it can’t work as I expected, not sure what mistakes I made there …

In reply to caowangyang:

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.


module mtime;
  timeunit 1ns;   timeprecision 10ps;
  bit clk;
  realtime t_now, low, high, duty_diff_abs, tolerance;
  initial forever begin 
  		#10 clk=1'b0; 
  		#9 clk=1'b1;
  	end
  initial begin
  	tolerance = 1.1ns; 
    @(posedge clk) t_now=$time;  // let clock work for a while    
    @(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);
   end
   //   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));
    function realtime ABS (realtime num); 
       ABS = (num <0) ? -num : num; 
    endfunction // ABS 
	
    property p_time; 
      realtime v_thi, v_tlo, v_hi, v_lo, v_diff; 
      @(posedge clk) (1, v_thi=$time) ##0 @(negedge clk) (1, v_tlo=$time, v_hi=v_tlo-v_thi) ##0
      	@(posedge clk) (1, v_lo=$time-v_tlo, v_diff= ABS(v_hi-v_lo)) ##0 v_diff <= tolerance; 
    endproperty 
    ap_time: assert property( p_time); 
    

endmodule 

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us

  • SystemVerilog Assertions Handbook 3rd Edition, 2013 ISBN 878-0-9705394-3-6
  • A Pragmatic Approach to VMM Adoption 2006 ISBN 0-9705394-9-5
  • Using PSL/SUGAR for Formal and Dynamic Verification 2nd Edition, 2004, ISBN 0-9705394-6-0
  • Real Chip Design and Verification Using Verilog and VHDL, 2002 isbn 0-9705394-2-8
  • Component Design by Example ", 2001 ISBN 0-9705394-0-1
  • VHDL Coding Styles and Methodologies, 2nd Edition, 1999 ISBN 0-7923-8474-1
  • VHDL Answers to Frequently Asked Questions, 2nd Edition ISBN 0-7923-8115

In reply to ben@SystemVerilog.us:

Hello Ben,

Can you explain this assertion?
how it works?

property p_time;
realtime v_thi, v_tlo, v_hi, v_lo, v_diff;
@(posedge clk) (1, v_thi=$time) ##0 @(negedge clk) (1, v_tlo=$time, v_hi=v_tlo-v_thi) ##0
@(posedge clk) (1, v_lo=$time-v_tlo, v_diff= ABS(v_hi-v_lo)) ##0 v_diff <= tolerance;
endproperty

ap_time: assert property( p_time);

Thanks & Regards
Lokesh

In reply to lksh:

See