Showing posts with label system verilog assertions. Show all posts
Showing posts with label system verilog assertions. Show all posts

Tuesday, September 17, 2024

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;
  parameter int M = 5;
  parameter int N = 100;
  rand bit[31:0] arr[M];
  
  constraint c_arr { arr.sum() == N; foreach(arr[i]) { arr[i] inside {[0:N-1]}; } unique {arr}; }
  
  function void post_randomize();
    foreach(arr[i])
    $display("Array[%01d]:%02d\n",i,arr[i]);
  endfunction
  
endclass

module top;
  test t;
  
  initial begin
    t = new;
    void'(t.randomize());
  end
endmodule

RESULT:

Compiler version U-2023.03-SP2_Full64; Runtime version U-2023.03-SP2_Full64; Sep 17 10:38 2024
Array[0]:23

Array[1]:01

Array[2]:10

Array[3]:11

Array[4]:15

Array[5]:21

Array[6]:14

Array[7]:03

Array[8]:02

Array[9]:00

V C S S i m u l a t i o n R e p o r t
Time: 0 ns
CPU Time: 0.430 seconds; Data structure size: 0.0Mb
Tue Sep 17 10:38:13 2024

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

Saturday, July 25, 2020

Pipeline driver logic in System Verilog

 For pipeline protocols such as AHB, the driver should support the parallel access of Address and Data.

In the example below, I tried to show one of the ways to achieve this.

In the following code, there are 3 possible burst traffic supported.
1. Single   - only 1 cycle of data for a given address
2. Double - 2 back-to-back cycles of data for a given address
3. Quad    - 4 cycles of data for a given address.

Let us take a scenario

You have the following sequence of burst traffic generated from your sequence.
SINGLE - DOUBLE - QUAD
@100ns Burst - Signle   Addr - 'h1 Data - 'h100
@200ns Burst - Double Addr - 'h2 Data - 'h200, 'h400
@400ns Burst - Quad    Addr - 'h3 Data - 'h600, 'h800,'hA00,'hC00

What should be driven to the interface is as follows
@100ns Addr: 'h1 Data: 'h100

@200ns Addr: 'h2 Data: 'h200
@300ns Addr: 'h2 Data: 'h400

@400ns Addr: 'h3 Data: 'h600
@500ns Addr: 'h3 Data: 'h800
@600ns Addr: 'h3 Data: 'hA00
@700ns Addr: 'h3 Data: 'hC00

There are only 2 things to take care of.
1. Whenever you get the seq_item, fork 2 process using join_any
    a.    process -1 will drive address
    b.    process -2 will drive data
    Why join-any?, reason is, when we get the sequence item, address ( process - 1) will be consumed in a single cycle, whereas the data (process - 2) can take multiple cycles. Since we may need to wait for multiple cycles for the process 2 to complete, we can unblock the wait state on process and proceed to receive to another sequence item.
2. We need to to make sure that the process-2 generated early ( say on 100ns ) should be completed first before driving the later version of the task (200ns). To achieve this we need to lock down the process , therefore we used semaphore to hold on to the process until it is done.

I highlighted the code in RED and GREEN.

Note: If you are using UVM, make sure you use seq_item_port.get(seq_item) instead of get_next_item(seq_item). This is required to return the control back to the sequencer once the cycle is completed.

CODE

typedef enum { SINGLE, DOUBLE, QUAD } BURST_TYPE;
class seq_item;
  static int trans_id;
  rand bit [31:0] addr;
  rand bit [31:0] data[];
  rand BURST_TYPE burst;

  constraint c_burst {
    if( burst == SINGLE ) { data.size() == 1; }
    if( burst == DOUBLE ) { data.size() == 2; }
    if( burst == QUAD   ) { data.size() == 4; }
  }

  constraint c_addr { addr inside { [1:100] }; }
 
  function void print();
    $display("@%0t - SEQ_ITEM :%0d ADDR:%0h BURST:%0s DATA:%p",$time,trans_id,addr,burst,data);
  endfunction

endclass


class driver;
  mailbox #(seq_item) drv;
  semaphore sem = new(1);


  task run_phase();
    seq_item item;

    $display("%0t DRIVER::RUN_PHASE",$time);
    forever begin
      drv.get(item);
      fork
        drv_addr(item);
        drv_data(item);
      join_any

    end
  endtask

  task drv_addr( seq_item s);
    $display("@%0t - DRV_ADDR :%0d ADDR:%0h BURST:%0s DATA:%p",$time,s.trans_id,s.addr,s.burst,s.data);
    #100;
  endtask

  task drv_data( seq_item s);
    sem.get(1);
    foreach(s.data[i]) begin
      $display("@%0t - DRV_DATA :%0d ADDR:%0h BURST:%0s DATA:%0h",$time,s.trans_id,s.addr,s.burst,s.data[i]);
      #100;
    end
    sem.put(1);
  endtask

endclass: driver


class generator;
  seq_item s;
  mailbox #(seq_item) gen;

  task run_phase ();
    $display("%0t GENERATOR::RUN_PHASE",$time);
    repeat(5) begin
      s = new;
      void'(s.randomize());
      #100;
      s.print();
      gen.put(s);
    end
  endtask
endclass: generator

module top;
  driver    d;
  generator g;
  mailbox #(seq_item) gen2drv;

  initial begin
    d = new;
    g = new;
    gen2drv = new(1);

    d.drv = gen2drv;
    g.gen = gen2drv;

    fork
      d.run_phase();
      g.run_phase();
    join
  end
endmodule: top

Command to run : vcs -sverilog -R <filename.sv>

Result:
Chronologic VCS simulator copyright 1991-2016
Contains Synopsys proprietary information.
Compiler version L-2016.06; Runtime version L-2016.06;  Jul 25 08:18 2020
0 DRIVER::RUN_PHASE
0 GENERATOR::RUN_PHASE
@100 - SEQ_ITEM :0 ADDR:59 BURST:SINGLE DATA:'{'h79b40674}
@100 - DRV_ADDR :0 ADDR:59 BURST:SINGLE DATA:'{'h79b40674}
@100 - DRV_DATA :0 ADDR:59 BURST:SINGLE DATA:79b40674
@200 - SEQ_ITEM :0 ADDR:42 BURST:DOUBLE DATA:'{'h51c5e838, 'ha3239b2d}
@200 - DRV_ADDR :0 ADDR:42 BURST:DOUBLE DATA:'{'h51c5e838, 'ha3239b2d}
@200 - DRV_DATA :0 ADDR:42 BURST:DOUBLE DATA:51c5e838
@300 - SEQ_ITEM :0 ADDR:18 BURST:QUAD DATA:'{'hf160aa62, 'h40498f74, 'h2446ea44, 'h4c0e692b}
@300 - DRV_DATA :0 ADDR:42 BURST:DOUBLE DATA:a3239b2d
@300 - DRV_ADDR :0 ADDR:18 BURST:QUAD DATA:'{'hf160aa62, 'h40498f74, 'h2446ea44, 'h4c0e692b}
@400 - SEQ_ITEM :0 ADDR:9 BURST:QUAD DATA:'{'h1e8bda74, 'h651da1c0, 'h477d65b1, 'hbf79aff8}
@400 - DRV_DATA :0 ADDR:18 BURST:QUAD DATA:f160aa62
@400 - DRV_ADDR :0 ADDR:9 BURST:QUAD DATA:'{'h1e8bda74, 'h651da1c0, 'h477d65b1, 'hbf79aff8}
@500 - SEQ_ITEM :0 ADDR:1f BURST:DOUBLE DATA:'{'ha4d5d480, 'h7aa3e09}
@500 - DRV_DATA :0 ADDR:18 BURST:QUAD DATA:40498f74
@500 - DRV_ADDR :0 ADDR:1f BURST:DOUBLE DATA:'{'ha4d5d480, 'h7aa3e09}
@600 - DRV_DATA :0 ADDR:18 BURST:QUAD DATA:2446ea44
@700 - DRV_DATA :0 ADDR:18 BURST:QUAD DATA:4c0e692b
@800 - DRV_DATA :0 ADDR:9 BURST:QUAD DATA:1e8bda74
@900 - DRV_DATA :0 ADDR:9 BURST:QUAD DATA:651da1c0
@1000 - DRV_DATA :0 ADDR:9 BURST:QUAD DATA:477d65b1
@1100 - DRV_DATA :0 ADDR:9 BURST:QUAD DATA:bf79aff8
@1200 - DRV_DATA :0 ADDR:1f BURST:DOUBLE DATA:a4d5d480
@1300 - DRV_DATA :0 ADDR:1f BURST:DOUBLE DATA:7aa3e09
           V C S   S i m u l a t i o n   R e p o r t

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

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