Showing posts with label SVA. Show all posts
Showing posts with label SVA. Show all posts

Monday, May 31, 2021

System verilog Assertion for back to back requests

Scenario :

A system generates request at random intervals in time.

Each request must be answered  by an acknowledgement after 1 to 10 cycles from request.

Following is the code to achieve the same.



bit clk,req,ack; 
int v_req,v_ack;
 
function void inc_req(); 
  req_cnt = req_cnt + 1'b1
endfunction
 
property reqack_unique;
  int v_req;
  @(posedge clk)
  $rose(req),  v_req=req_cnt, inc_req()) |-> ##[1:10] v_req ==v_ack ##0 ack; 
endproperty
 
ap_reqack_unique: assert property(reqack_unique) v_ack = v_ack+1; 
else v_ack=v_ack+1;

Saturday, April 24, 2021

System Verilog Assertions - dynamic delays

Ben cohen provided the code for dynamic delays in verification academy forum.

I have just pasted it here...

Link :

https://verificationacademy.com/forums/systemverilog/sva-package-dynamic-and-range-delays-and-repeats

 Code :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Ben Cohen  December 13, 2018  
package sva_delay_repeat_range_pkg;
    // int d1, d2; 
    // bit a, b, c=1'b1; 
    // sequence q_s; a ##1 c; endsequence  
    // sequence my_sequence; e ##1 d[->1]; endsequence 
    //----------------------------------------------------------------
    // ******       DYNAMIC DELAY ##d1 **********
    // Application:  $rose(a)  |-> q_dynamic_delay(d1) ##0 my_sequence;
    sequence q_dynamic_delay(count);
        int v;
        (1, v=count) ##0 first_match((1, v=v-1'b1) [*0:$] ##1 v<=0);
    endsequence 
    //----------------------------------------------------------------
    // ******       DYNAMIC DELAY RANGE ##[d1:d2] **********
    //##[d1:d2] ##0 b; // NO sequence  followng the "b"
    // $rose(a)  |-> q_dynamic_delay_range(d1, d2, b)) 
    //                and b[->1] ##1 my_sequence;
    // $rose(a) ##0  q_dynamic_delay_range(d1, d2, b) |-> my_sequence;
    sequence q_dynamic_delay_range(int d1, d2, bit b);
        int v1, vdiff;
        (1, v1=d1, vdiff=d2-d1) ##0 q_dynamic_delay(v1)   ##0  
        first_match((1, vdiff=vdiff - 1)[*0:$] ##1 (b || vdiff<=0)) ##0 b; 
    endsequence 
    //----------------------------------------------------------------
    // ******       DYNAMIC REPEAT q_s[*d1] **********
    // Application:  $rose(a)  |-> q_dynamic_repeat(q_s, d1) ##1 my_sequence;
    sequence q_dynamic_repeat(q_s, count);
        int v=count;
        (1, v=count) ##0 first_match((q_s, v=v-1'b1) [*1:$] ##0 v<=0);
    endsequence
    //----------------------------------------------------------------
    // ******       DYNAMIC REPEAT RANGE q_s[*d1:d2] **********
    // Application:  $rose(a)  |-> (q_dynamic_repeat_range(q_s, d1, d2, b) 
    //                             and  b[->1] ##1 my_sequence // use the same "b"
    //  $rose(a)  ##1 q_dynamic_repeat_range(q_s, d1, d2, b) |->   my_sequence;
    sequence q_dynamic_repeat_range(sequence q_s, int r1, r2, bit b);
        int v, diff;
        (1, v=r1, diff=r2-r1) ##0   
        q_dynamic_repeat(q_s, v)  ##1 // repeat to r1
        first_match((q_s, diff=diff-1'b1) [*0:$] ##1 (b || diff<=0 )) ##0 b; 
    endsequence     
endpackage
 
 
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;  
    sequence q_s;
        a ##1 c; 
    endsequence   
    sequence my_sequence; 
        a ##1 w[->1]; 
    endsequence 
    default clocking @(posedge clk); 
    endclocking
    initial forever #10 clk=!clk;  
 
    // ******       DYNAMIC DELAY ##d1 **********
    // Application:  $rose(a)  |-> q_dynamic_delay(d1) ##0 my_sequence;
    ap_dyn_delay: assert property(@ (posedge clk) 
       $rose(a) |-> q_dynamic_delay(d1) ##0 my_sequence);  
 
    ap_fix_delay: assert property(@ (posedge clk)   
       $rose(a) |-> ##2 my_sequence); 
 
    // ******       DYNAMIC DELAY RANGE ##[d1:d2] **********
    //##[d1:d2] ##0 b; // NO sequence  followng the "b"
    // $rose(a)  |-> q_dynamic_delay_range(d1, d2, b)) 
    //                and b[->1] ##1 my_sequence;
    // $rose(a) ##0 q_dynamic_delay_range(d1, d2, b) |-> my_sequence;
    ap_dly_rng: assert property(@ (posedge clk) 
      $rose(a) |-> q_dynamic_delay_range(d1, d2, b) and b[->1] ##1 my_sequence);  
 
    ap_2to5: assert property(@ (posedge clk) 
      $rose(a) |->(##[2:5] b) and  b[->1] ##1 my_sequence);   
 
    ap_dly_rng_antc: assert property(@ (posedge clk) 
     $rose(a) ##0 q_dynamic_delay_range(d1, d2, b) |-> my_sequence);  
 
    ap_2to5_antc: assert property(@ (posedge clk) 
      $rose(a) ##0 first_match(##[2:5] b) |-> my_sequence); 
    //------------------------------------------------------------------
    // ******       DYNAMIC REPEAT q_s[*d1] **********
    // Application:  $rose(a)  |-> q_dynamic_repeat(q_s, d1) ##1 my_sequence;
    ap_rpt: assert property(@ (posedge clk) 
      $rose(a)|-> q_dynamic_repeat(q_s, d1)  ##1 my_sequence);  
 
    ap_rpt2: assert property(@ (posedge clk)  
    $rose(a)|-> q_s[*2] ##1 my_sequence);   
 
    // ******       DYNAMIC REPEAT RANGE q_s[*d1:d2] **********
    // Application:  $rose(a)  |-> (q_dynamic_repeat_range(q_s, d1, d2, b) 
    //                             and  b[->1] ##1 my_sequence // use the same "b"
    //  $rose(a)  ##1 (q_dynamic_repeat_range(q_s, d1, d2, b) |->   my_sequence;
    ap_rpt_rng: assert property(@ (posedge clk) 
      $rose(a)  |-> q_dynamic_repeat_range(q_s, d1, d2, b) 
                    and  b[->1] ##1 my_sequence);  
 
    ap_rpt_2to5: assert property(@ (posedge clk) 
      $rose(a)  |-> first_match(q_s[*2:5] ##1 b) and  b[->1] ##1 my_sequence);  
 
    ap_rpt_rng_antc: assert property(@ (posedge clk) 
      $rose(a)  ##1 q_dynamic_repeat_range(q_s, d1, d2, b) |->   my_sequence);  
 
    ap_rpt_2to5_antc: assert property(@ (posedge clk) 
      $rose(a)  ##1 first_match(q_s[*2:5] ##1 b) |->   my_sequence);
 
    initial begin 
        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 
        $stop; 
    end 
endmodule   

 

Wednesday, July 29, 2020

System verilog assertion - If b is asserted in the current cycle, a must have been present anywhere between 1 - 3 cycles earlier than b.

Problem Statement:
1. A and B are 2 pulses.
If B is asserted, A must have been asserted anywhere between 1 and 3 cycles in the past.

Solution :
We cannot use $past, as the problem requires the check to be range bound.

One way around is to use an intermediate signal ( vector).

Let us try using an vector to accommodate the length of duration to be under check.
In our case, it is between 1 and 3.
Therefore , let us take an intermediate signal arr, ranging from 3:0.
Each bit position corresponds to 1 cycle.

Code snippet will be something like this:

always @(posedge clk) arr = {[arr[2:0],a};

Code for assertion :

  property check;
    @(posedge clk) (b==1) |-> $countones(arr[3:1])>=1; // omit arr[0] as this is represents the time at which 'b' is set to 1
  endproperty: check

  a_check: assert property (check);

One more way to do it is the use of sequence.triggered.
As per LRM, triggered is a method, which checks if the operand sequence has reached its end point at that point in time.

Using this, we can write a sequence and check whether it reached its endpoint before $rose(b).

sequence s_1;
  @(posedge clk) $rose(a) ##[1:3]  1;
endsequence: s_1

property test_1;
  @(posedge clk) $rose(b) |-> s_1.triggered;
endproperty: test_1

Notes:
Now the sequence s_1, checks for $rose(a) between 1 and 3 cycles.
property test_1 checks if the s_1.triggered is reached to its endpoint at $rose(a).

Code with stimulus :
module top;
  bit a;
  bit b;
  bit [3:0] arr;

  bit clk;

  initial  begin
    $timeformat(-9,3,"ns",8);
    clk <= 0;
    forever #5 clk = !clk;
  end

  initial
    $monitor("%0t - A -%0d B -%0d Arr:%0b",$time,a,b,arr);

  initial begin
    repeat(1) @(posedge clk);
    a = 1;
    repeat(1) @(posedge clk);
    a = 0;

    repeat(2) @(posedge clk); // Check should pass, as 'a' is asserted 3 cycles before 'b'.
    b = 1;
    repeat(1) @(posedge clk);
    b = 0;
  
    repeat(3) @(posedge clk); // Check should fail, as 'a' is not present in the previous 3 cycles
    b = 1;
    repeat(1) @(posedge clk);
    b = 0;
   
    repeat(1) @(posedge clk); // Check should fail, as 'a' and 'b' are asserted in the same cycle.
    a = 1; b = 1;
    repeat(1) @(posedge clk);
    a = 0; b = 0;
    repeat(4) @(posedge clk);
    $finish;
  end

  always @(posedge clk) begin
    arr <= { arr[2:0], a };
  end

  property check;
    @(posedge clk) (b==1) |-> $countones(arr[3:1])>=1; // omit arr[0] as this is represents the time at which 'b' is set to 1
  endproperty: check

  a_check: assert property (check);
endmodule

Result :

Compiler version L-2016.06; Runtime version L-2016.06;  Jul 29 04:18 2020
0ns - A -0 B -0 Arr:0
5ns - A -1 B -0 Arr:1
15ns - A -0 B -0 Arr:10
25ns - A -0 B -0 Arr:100
35ns - A -0 B -1 Arr:1000
45ns - A -0 B -0 Arr:0
75ns - A -0 B -1 Arr:0
"assertion_past_value.sv", 51: top.a_check: started at 85000ps failed at 85000ps
        Offending '($countones(arr[3:1]) >= 1)'
85ns - A -0 B -0 Arr:0
95ns - A -1 B -1 Arr:1
"assertion_past_value.sv", 51: top.a_check: started at 105000ps failed at 105000ps
        Offending '($countones(arr[3:1]) >= 1)'
105ns - A -0 B -0 Arr:10
115ns - A -0 B -0 Arr:100
125ns - A -0 B -0 Arr:1000
135ns - A -0 B -0 Arr:0
$finish called from file "assertion_past_value.sv", line 40.
$finish at simulation time    145ns

Wednesday, July 22, 2020

Write a system verilog assertion to check for lock when '110' is observed on the input bit stream and lock is de-asserted when '111' is observed.

`timescale 1ns / 100ps
module top;
 bit a;
 bit [2:0] bin;
 bit lock;

 bit clk;

 initial begin
   $timeformat(-9,0,"ns",8);
   clk <= 0;
   forever #5 clk = !clk;
 end

 initial begin
   repeat(100) begin
     @(posedge clk);
     std::randomize(a);
   end
   $finish;
 end
  

 always @ (posedge clk) begin
   bin <= { bin[1:0], a };
   if(bin == 'b110) lock <= 1;
   if(bin == 'b111) lock <= 0;
 end


 property check_lock;
   @(posedge clk) (bin == 'b110) |=> lock throughout (bin == 'b111)[->1];
 endproperty

 property check_lock_deassertion;
   @(posedge clk) (bin == 'b111) && lock |=> $fell(lock);
 endproperty


 check_lock_assertion    : assert property (check_lock);
 check_lock_de_assertion : assert property (check_lock_deassertion);



 initial
   $monitor("%0t - Lock:%0d A:%0d B:%0b",$time,lock,a,bin);

  endmodule: top

Monday, July 20, 2020

System Verilog Assertion to check if no more than 3 ACK are generated in a 10 cycle window

The above problem statement gives us 2 conditions.
  1. Window of check should be 10 cycles
  2. Number of ACK should be no more than 3.
Since the both end at the same time we will use INTERSECT operator.

Assertion :
  property check_ack;
    @(posedge clk) ack[->3] intersect 1[*10];
  endproperty

ack[->3] or ack[=3] satisfies point 2.
Since we need to check it in 10 cycles (i.e., 10 posedge clk's) we used 1[*10] --> 10 consecutive clock edges.


Code :

// Generate whatever pattern you want in the test class
class test;
   rand bit ack_b;
endclass: test

module top;
  test t;
 
  bit clk;
  bit ack;
 
  initial begin
    $timeformat(-9,0,"ns",8);
    clk <= 0;
    forever #5 clk = !clk;
   
  end
 
  initial begin
    t = new;
    repeat(20) begin //{
      @(posedge clk);
      void'(t.randomize());
      ack = t.ack_b;  
    end //}
    $finish;
  end
 
  property check_ack;
    @(posedge clk) ack[->3] intersect 1[*10];
  endproperty

 

  abc: assert property (check_ack) $display("@%0t ACK is through",$time); else
      $error("Check failed at %0t",$time);


 
  initial
    begin //{
    forever begin //{
      @(posedge clk);
      $display("Time:%0t ACK:%0d",$time,ack);
    end //}
    end //}
endmodule: top


Result :
# //
# Loading sv_std.std
# Loading work.testbench_sv_unit(fast)
# Loading work.top(fast)
#
# vsim -voptargs=+acc=npr
# run -all
# Time:5ns ACK:0
# Time:15ns ACK:1
# Time:25ns ACK:1
# Time:35ns ACK:0
# Time:45ns ACK:1
# Time:55ns ACK:0
# ** Error: Check failed at 55ns
# Time: 55 ns Started: 25 ns Scope: top.abc File: testbench.sv Line: 54
# ** Error: Check failed at 55ns
# Time: 55 ns Started: 15 ns Scope: top.abc File: testbench.sv Line: 54
# ** Error: Check failed at 55ns
# Time: 55 ns Started: 5 ns Scope: top.abc File: testbench.sv Line: 54
# Time:65ns ACK:1
# Time:75ns ACK:1
# ** Error: Check failed at 75ns
# Time: 75 ns Started: 35 ns Scope: top.abc File: testbench.sv Line: 54
# Time:85ns ACK:0
# ** Error: Check failed at 85ns
# Time: 85 ns Started: 55 ns Scope: top.abc File: testbench.sv Line: 54
# ** Error: Check failed at 85ns
# Time: 85 ns Started: 45 ns Scope: top.abc File: testbench.sv Line: 54
# Time:95ns ACK:0
# Time:105ns ACK:1
# Time:115ns ACK:0
# ** Error: Check failed at 115ns
# Time: 115 ns Started: 75 ns Scope: top.abc File: testbench.sv Line: 54
# ** Error: Check failed at 115ns
# Time: 115 ns Started: 65 ns Scope: top.abc File: testbench.sv Line: 54
# Time:125ns ACK:1
# Time:135ns ACK:0
# ** Error: Check failed at 135ns
# Time: 135 ns Started: 85 ns Scope: top.abc File: testbench.sv Line: 54
# Time:145ns ACK:0
# Time:155ns ACK:0
# Time:165ns ACK:0
# Time:175ns ACK:0
# Time:185ns ACK:0
# ** Error: Check failed at 185ns
# Time: 185 ns Started: 95 ns Scope: top.abc File: testbench.sv Line: 54
# ** Note: $finish : testbench.sv(45)
# Time: 195 ns Iteration: 1 Instance: /top
# End time: 11:23:36 on Jul 20,2020, Elapsed time: 0:00:00
# Errors: 20, Warnings: 1

Constraint to have N elements distributed in M bins

Code to distribute N elements into M bins, you add unique keyword to have each bin will have unique number of elements. class test; param...