SVA: Package for dynamic and range delays and repeats

The package has been updated and is now uploaded here and is also avaliable at
https://systemverilog.us/vf/sva_repeat_delay_thru_pkg_011624.sv
sva_repeat_delay_thru_pkg_011624.pdf (89.0 KB)

Update is based on comment:

New code


// Update 01/16/2024
// PACKAGE UPDATE 12/07/2021
// https://verificationacademy.com/forums/systemverilog/sva-package-dynamic-and-range-delays-and-repeats
/* 1) Attached are the .sv file, and simulation results with Questa. 
2) // The package was verified through analysis of the sequences and through random testing    
// Sequences that use the first_match() function along with a range repeat were reported      
// not compatible with formal verification tools 
 3) It would be great if 1800'2022 adds the dynamic possibilities for the definition of the delays and repeats.    The value of those variables can be captured and saved at the attempt cycle.    I didn't lock them in the package. 

BTW, these are complex sequences, and it took some time to get them to that point. */

/* Ben Cohen Dec 7, 2021 
// This file includes the delay and repeat package along with 
// a testbench to demonstrate its application. 
// The package was verified through analysis of the sequences and through random testing 
// Sequences that use the first_match() function along with a range repeat were reported   
// not compatible with formal verification tools */

 
package sva_delay_repeat_range_pkg;
    //----------------------------------------------------------------
    // ******       DYNAMIC DELAY ##d1 **********
    // Implements     ##[d1] 
    // Application: sq_1 ##0 dynamic_delay(d1) ##0 sq_2;
    sequence dynamic_delay(count);
        int v;
      (count<=0) or ((1, v=count) ##0 (v>0, v=v-1) [*0:$] ##1 v<=0);
    endsequence // dynamic_delay
 
    //----------------------------------------------------------------
    // ******       DYNAMIC DELAY RANGE ##[d1:d2] **********
    // Implements     ##[d1:d2] ##0 a_sequence 
    // for use in consequent 
    // Application:  $rose(a)  |-> dynamic_delay_lohi_sq(d1, d2, q) ;   
    /* sequence dynamic_delay_lohi_sq(d1, d2, sq);   // DO NOT USE
        int v1, vdiff;
          ( (1, v1=d1, vdiff=d2-d1) ##0 dynamic_delay(v1)   ##0     
              (vdiff>=0, vdiff=vdiff - 1)[*1:$] ##0 sq); 
    endsequence */

    sequence dynamic_delay_lohi_sq(d1, d2, sq);
      int v1, vdiff;
        dynamic_delay(d1)##0 
        (sq or     
        (1, vdiff=d2-d1) ##0 (vdiff>0, vdiff=vdiff - 1)[*1:$] ##1 sq); 
    endsequence
 
    sequence dynamic_delay_fm_lohi_sq(d1, d2, sq);
            int v1, vdiff;
             first_match(dynamic_delay_lohi_sq(d1, d2, sq)); 
    endsequence // dynamic_delay_fm_lohi_sq 
 
    //----------------------------------------------------------------
    // ******       DYNAMIC REPEAT q_s[*d1] ********** 
    // Implements   a_sequence[*count]
    // Application:  $rose(a)  |-> sq_rpt_simple_count(sq_1, d1)
    sequence sq_rpt_simple_count(sq, count);
        int v=count;
        (1, v=count) ##0 ( v>0 ##0 sq, v=v-1) [*1:$] ##0 v<=0;
    endsequence // sq_rpt_simple_count
    //Note:  "The sequence_expr of a sequential property shall not admit an empty   match (see 16.12.22)." 
 
    //----------------------------------------------------------------
    // ******       DYNAMIC REPEAT RANGE sq_1[*range] ##1 b] **********
    // Implements   a_sequence[*1:range] b_sequence 
    // Application:  $rose(a) |-> sq1_rpt_simple_range_sq2(sq_1, d1,  sq2_2);
    //NOTE: RANGE MUST BE GREATER THAN ZERO !!!!!!
    sequence sq1_rpt_simple_range_sq2(sq1, range,  sq2);
      int v, diff;
      (range>0,  diff=range)  ##0  
      ((diff>0  ##0 sq1, diff=diff-1'b1) [*1:$] ##1 sq2);
    endsequence
 
 
    sequence sq1_rpt_simple_range_fm_sq2(sq1, range,  sq2);
      int v, diff;  
      (range>0,  diff=range)  ##0  
      first_match((diff>0  ##0 sq1, diff=diff-1'b1) [*1:$] ##1 sq2);
    endsequence
 
 
    //----------------------------------------------------------------
    // ******       DYNAMIC REPEAT LO-HI RANGE  **********
    // Implements  a_sequence[*lo:hi] ##1 b_sequence 
    // Application:  $rose(a)|-> sq1_rpt_lohi_sq2(sq_1, d1, d2, sq_2); 
    sequence  sq1_rpt_lohi_sq2(sq1, d1, d2, sq2); 
        int v, diff;
        (1, v=d1-1, diff=d2-d1+1) ##0 
        sq_rpt_simple_count(sq1, v) ##1
        // TBD Ben Srini q1_rpt_simple_range_q2(sq1, diff, sq2);
        sq1_rpt_simple_range_sq2(sq1, diff, sq2);
    endsequence // sq1_rpt_lohi_sq2 
 
endpackage // sva_delay_repeat_range_pkg
 
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// +++++++++++++++++++ testbench +++++++++++++++++++++
import uvm_pkg::*; `include "uvm_macros.svh" 
import sva_delay_repeat_range_pkg::*;
module top; 
    timeunit 1ns;  timeprecision 100ps;  
    bit clk, a, b, c=1, w;  
    int d1=2, d2=5, range=7;  
    sequence sq_a1_2_b; a ##[1:2] b; endsequence 
    sequence sq_c1_4_b; c ##[1:4] b;        endsequence   
    sequence sq_2w;  ##2 w; endsequence 
    // default clocking @(posedge clk); endclocking
    initial forever #5 clk=!clk;  
 
    // ******       DYNAMIC DELAY ##d1 **********    
    ap_dyn_delay2: assert property(@ (posedge clk) 
       $rose(a) |-> dynamic_delay(d1) ##0 sq_2w);   
 
    ap_fix2_delay2: assert property(@ (posedge clk)   
       $rose(a) |-> ##2 sq_2w); 
 
    ap_dyn_delay0: assert property(@ (posedge clk)   
       $rose(a) |-> dynamic_delay(1'b0) ##0 sq_2w);  
 
    ap_fix_delay0: assert property(@ (posedge clk)   
       $rose(a) |-> ##0 sq_2w); 
//----------------------------------------------------------------
    // ******       DYNAMIC DELAY RANGE ##[d1:d2] **********
    ap_dly_2_5_consequent_rng: assert property(@ (posedge clk) 
      $rose(a) |-> dynamic_delay_lohi_sq(d1, d2, sq_c1_4_b));  
 
    ap_fix_2to5_consequent: assert property(@ (posedge clk) 
      $rose(a) |-> ##[2:5] sq_c1_4_b );   
 
    ap_dly_rng_2_5_antc: assert property(@ (posedge clk)    
     $rose(a) ##0 dynamic_delay_fm_lohi_sq(d1, d2, sq_c1_4_b) |-> sq_2w);  
 
    ap_fix_2to5_antc: assert property(@ (posedge clk) 
      first_match($rose(a) ##0 (##[2:5] sq_c1_4_b)) |-> sq_2w); 
 
    //===
    // The sub-sequence (vdiff>=0, vdiff=vdiff - 1)[*1:$] ##0 sq)
    // causes the display of the failure to occur 1 cycle later 
    // when vdiff==0 and sq is a nomatch.  
    // At next cycle, vdiff==-1 and the term vdiff>0 is false.
    // That's when the error is display (1 cycle laters) 
    // The passes are displayed at the correct cycle. 
    ap_dly_2to2_consequent_rng: assert property(@ (posedge clk) // ** FLAG, but OK 
      $rose(a) |-> dynamic_delay_lohi_sq(d1, 2, sq_c1_4_b));   
 
    ap_fix_2to2_consequent: assert property(@ (posedge clk) 
      $rose(a) |-> ##[2:2] sq_c1_4_b );   
 
    ap_dly_0to0_consequent_rng: assert property(@ (posedge clk)  // ** FLAG, but OK 
      $rose(a) |-> dynamic_delay_lohi_sq(0, 0, sq_c1_4_b));  
 
    ap_fix_0to0_consequent: assert property(@ (posedge clk) 
      $rose(a) |-> ##[0:0] sq_c1_4_b ); 
 
    //------------------------------------------------------------------
    // ******       DYNAMIC REPEAT sq_a1_2_b[*d1] ********** 
    ap_rpt_count_2_cons: assert property(@ (posedge clk)    
      $rose(a)|-> sq_rpt_simple_count(sq_a1_2_b, d1)  ##1 sq_2w);  
 
    ap_rpt_2_fix_cons: assert property(@ (posedge clk)  
       $rose(a)|-> sq_a1_2_b[*2] ##1 sq_2w);            
 
    ap_rpt_count_2_antc: assert property(@ (posedge clk)    
      $rose(a) ##0 sq_rpt_simple_count(sq_a1_2_b, d1) |->  ##1 sq_2w);  
 
    ap_rpt_2_fix_antc: assert property(@ (posedge clk)  
        $rose(a) ##0 sq_a1_2_b[*2] |-> ##1 sq_2w);
 
// ******       DYNAMIC REPEAT RANGE sq_1[*rang] ##1 b] **********
    ap_rpt_rng2_5_antc_all: assert property(@ (posedge clk)     
      $rose(a)  ##1 sq1_rpt_simple_range_sq2(sq_a1_2_b, range, sq_c1_4_b)
                          |->   sq_2w);  
    ap_rpt_fix2_5_antc_all: assert property(@ (posedge clk) 
      $rose(a)  ##1  (sq_a1_2_b[*1:7] ##1 sq_c1_4_b) |->   sq_2w);
 
    ap_rpt_rng2_5_cons: assert property(@ (posedge clk)   
      $rose(a) |-> ##1 sq1_rpt_simple_range_sq2(sq_a1_2_b, range, sq_c1_4_b));
 
    ap_rpt_fix2_5_cons: assert property(@ (posedge clk) 
      $rose(a) |-> ##1  (sq_a1_2_b[*1:7] ##1 sq_c1_4_b));  
 
// first_match() 
    ap_rpt_rng2_5_cons_all_fm: assert property(@ (posedge clk)   
      $rose(a)  |-> sq1_rpt_simple_range_fm_sq2(sq_a1_2_b, range, sq_c1_4_b) ##0   sq_2w);
 
    ap_rpt_range_fix2_5_cons_fm: assert property(@ (posedge clk) 
      $rose(a)  |-> first_match(sq_a1_2_b[*1:7] ##1 sq_c1_4_b)   ##0   sq_2w);    
 
    ap_rpt_rng2_5_antc_fm: assert property(@ (posedge clk)   
      $rose(a)  ##1 sq1_rpt_simple_range_fm_sq2(sq_a1_2_b, range, sq_c1_4_b)); 
 
    ap_rpt_fix2_5_antc_fm: assert property(@ (posedge clk) 
      $rose(a)  ##1 first_match( (sq_a1_2_b[*1:7] ##1 sq_c1_4_b))); 
 
    initial begin 
    
      repeat(2) @(posedge clk);
      a <= 1'b0; b<=1'b0; c<=1'b0; w<=1'b0; 
      @(posedge clk);
      a <= 1'b1; b<=1'b1; c<=1'b1; w<=1'b1; 
      @(posedge clk) d1<=0; d2<=0;  // <------------------ ZERO test 
      repeat(2) @(posedge clk);
      a <= 1'b0; b<=1'b0; c<=1'b0; w<=1'b0; 
      @(posedge clk);
      a <= 1'b1; b<=1'b1; c<=1'b1; w<=1'b1; 
      // Regular test 
      @(posedge clk) d1<=2; d2<=5;  // <-------------------- Range test 
      repeat(20) @(posedge clk);
        repeat(1000) begin 
            @(posedge clk); #2;   
            if (!randomize(a, b, c, w)  with 
            { a dist {1'b1:=1, 1'b0:=1};
            b dist {1'b1:=1, 1'b0:=1}; 
            c dist {1'b1:=1, 1'b0:=1}; 
            w dist {1'b1:=1, 1'b0:=1}; }) `uvm_error("MYERR", "randomize error");
        end 
        #1;
        repeat(1500) begin 
            @(posedge clk); #2;   
            if (!randomize(a, b, c, w)  with 
            { a dist {1'b1:=1, 1'b0:=2};
            b dist {1'b1:=3, 1'b0:=2}; 
            c dist {1'b1:=1, 1'b0:=1}; 
            w dist {1'b1:=3, 1'b0:=1}; }) `uvm_error("MYERR", "randomize error");
        end 
        repeat(1500) begin 
            @(posedge clk); #2;   
            if (!randomize(a, b, c, w)  with 
            { a dist {1'b1:=3, 1'b0:=2};
            b dist {1'b1:=1, 1'b0:=2}; 
            c dist {1'b1:=4, 1'b0:=1}; 
            w dist {1'b1:=2, 1'b0:=1}; }) `uvm_error("MYERR", "randomize error");
        end 
        $stop; 
    end 
endmodule   

Ben Cohen
Ben@systemverilog.us
Link to the list of papers and books that I wrote, many are now donated. https://systemverilog.us/vf/Cohen_Links_to_papers_books.pdf

Complex assertions can also be more easily written answered through the use of an automatic task.
I discuss this approach in my paper:
https://verificationacademy.com/forums/systemverilog/paper-understanding-sva-engine-simple-alternate-solutions
Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us

Move the imports after the module name. For example

 
module top; 
    timeunit 1ns;     timeprecision 100ps;  
    import uvm_pkg::*; `include "uvm_macros.svh" 
    import sva_delay_repeat_range_pkg::*;
    bit clk, a, b, c=1, w;  
.... 


In reply to ben@SystemVerilog.us:

Hi Ben,

Can this be used for formal verification as well? I see questa propcheck throwing some errors on this.

***# Warning : Unsupported variable delay between local variable assign and read or within AND/OR/first_match/within constructs. Outside supported local variable synthesis subset. Local variable q_dynamic_repeat_v[0].

Thanks & Regards
Singhal R

In reply to Singhal R:

“Unsupported” is a tool specific issue.

This Mentor/Siemens EDA sponsored public forum is not for discussing tool specific usage or issues. Please read your tool’s user manual or contact your tool vendor directly for support.

In reply to Singhal R:
Speaking in generalities, we’re talking about 2 things: local variables (LV) as counters and first_match. This is different from LV for data storage and compare at later cycles.
Counters are cycle-based kind of thing, and first match is a thread reduction mechanism. That does not seem a FV thing. For specifics talk to your vendor.

A work around for formal might be to use the generate with static variables for a small range (1 to 32)?

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr
** SVA Handbook 4th Edition, 2016 ISBN 978-1518681448

  1. SVA Package: Dynamic and range delays and repeats SVA: Package for dynamic and range delays and repeats | Verification Academy
  2. Free books: Component Design by Example FREE BOOK: Component Design by Example … A Step-by-Step Process Using VHDL with UART as Vehicle | Verification Academy
    Real Chip Design and Verification Using Verilog and VHDL($3) Amazon.com
  3. Papers:

In reply to ben@SystemVerilog.us:

Here is a workaround for dynamic delays to be used for formal verification:



module top; 
    import uvm_pkg::*; `include "uvm_macros.svh" 
    import sva_delay_repeat_range_pkg::*;
    timeunit 1ns;     timeprecision 100ps;  
    bit clk, a, b, c=1, w;  
    bit[1:0] v=2;  
       
    initial forever #10 clk=!clk;  
    
    // ******       DYNAMIC DELAY ##v **********
    // Application:  $rose(a)  |-> q_dynamic_delay(v) ##0 my_sequence;
    ap_dyn_delay: assert property(@ (posedge clk) 
       $rose(a) |-> q_dynamic_delay(v) ##0 b);  
    
    ap_fix_delay2: assert property(@ (posedge clk)   
       $rose(a) |-> ##2 b); 

    // For formal verification
    generate for (genvar i=0; i<=3; i++)
        begin 
            ap_fvi: assert property(@ (posedge clk) 
               v==i && $rose(a) |-> ##i b);  
        end
    endgenerate 

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
** SVA Handbook 4th Edition, 2016 ISBN 978-1518681448

  1. SVA Package: Dynamic and range delays and repeats SVA: Package for dynamic and range delays and repeats | Verification Academy
  2. Free books: Component Design by Example FREE BOOK: Component Design by Example … A Step-by-Step Process Using VHDL with UART as Vehicle | Verification Academy
    Real Chip Design and Verification Using Verilog and VHDL($3) Amazon.com
  3. Papers:

Udemy courses by Srinivasan Venkataramanan (http://cvcblr.com/home.html)
https://www.udemy.com/course/sva-basic/
https://www.udemy.com/course/sv-pre-uvm/

In reply to ben@SystemVerilog.us:

Thanks Ben. I am aware of use of generate. However I was wondering if there are other methods. In one of the use case range of variable delays and their combinations are two many.

For example, say delay is controlled by three different variables d1, d2 and d3.
d1 inside [10:15]
d2 inside [20:40]
d3 inside [40-240].

So total combinations becomes about 621201 = 25326 possible cases. In such cases as well generate may not be the best method. Any thoughts on this?

Thanks & Regards
Singhal R

In reply to Singhal R:

In reply to ben@SystemVerilog.us:… However I was wondering if there are other methods. In one of the use case range of variable delays and their combinations are two many.
For example, say delay is controlled by three different variables d1, d2 and d3.
d1 inside [10:15]
d2 inside [20:40]
d3 inside [40-240].

Two points, one with the way the tool is used, the other with the RTL architecture.

  1. Way the tool is used: If the formal tool does not support the first_match of a sequence with a repeat (e.g., (first_match((1, v=v-1’b1) [*0:$]) the use of the generate is the only option I see. I can think of dynamic tasks with fork-join but that is not supported in formal.
  2. If you have multiple variables and the number of combinations explodes, you’ll need to add some assume property statements to constraint the ranges to something more manageable. For example, you can constraint the generate to smaller ranges and add assume statements:

am_d3: assume property(@(posedge clk) d3==40 || d3==50 || d3== 100 || d3==200 || d3==240);

  1. RTL architecture: When I built the RTL to implement the assertion
    $rose(a) |-> q_dynamic_delay(v) ##0 b);
    I first approached the problem by using a cycle counter. That worked fine until you get a 2nd rose while the previous thread did not yet complete. Using counter, it seems that every thread would need it’s own set of counters, and you can do that with threaded forked tasks (that’s not synthesizable, as you know). My solution ended up ignoring other threads until a stated “rose” thread completed the count. That was a very complex solution, and honestly, it took a few iterations to get it working.
  1. Complex RTL with a counter for the setting of “b”
    http://SystemVerilog.us/vf/dynamic_dly2.sv
    http://SystemVerilog.us/vf/dynamic_dly2.png
    After some thoughts, I came up with a much simpler, more natural solution piping the rose(a) into a register and using a MUX to select bit in pipe for the “b”
  2. Simpler RTL piping the rose(a) and a MUX to select bit in pipe for the “b”
    http://SystemVerilog.us/vf/pipe_dly.sv
    http://SystemVerilog.us/vf/pipe_design.png

My point on the architecture is that the simpler one is easier to analyze and probably through thorough analysis have a high level of confidence that the design works in all cases. Again, constraints in formal will cut the formal evaluation time.

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
** SVA Handbook 4th Edition, 2016 ISBN 978-1518681448

  1. SVA Package: Dynamic and range delays and repeats SVA: Package for dynamic and range delays and repeats - SystemVerilog - Verification Academy
  2. Free books: Component Design by Example https://rb.gy/9tcbhl
    Real Chip Design and Verification Using Verilog and VHDL($3) Amazon.com
  3. Papers:

Udemy courses by Srinivasan Venkataramanan (http://cvcblr.com/home.html)
https://www.udemy.com/course/sva-basic/
https://www.udemy.com/course/sv-pre-uvm/