Tuesday, August 18, 2020

System Verilog Constraints for non-overlapping memory allocation

 class ex;
 
  parameter MAX = 1024;
 
  rand int unsigned max_val[4];
  rand int unsigned min_val[4];
  rand int unsigned rng_val[4];
 
  constraint c_min_max {
    rng_val.sum() <= 1024;
    foreach(rng_val[i]) {
      max_val[i] inside { [0:MAX-1] };
      min_val[i] inside { [0:MAX-1] };
      rng_val[i] inside { [1:MAX] };
      max_val[i] == min_val[i] + rng_val[i]-1;
      if(i > 0) min_val[i] > max_val[i-1];
    }
  }
 

 
  function void post_randomize();
    foreach(rng_val[i])
    $display("MAX:%0d | MIN:%0d | RNG:%0d",max_val[i],min_val[i],rng_val[i]);
  endfunction  
 
endclass

module top;
  ex e;
 
  initial begin
    e = new;
    void'(e.randomize());
  end
endmodule

 

Simulation:

ompiler version P-2019.06-1; Runtime version P-2019.06-1; Aug 18 06:16 2020
MAX:144 | MIN:20 | RNG:125
MAX:271 | MIN:151 | RNG:121
MAX:457 | MIN:274 | RNG:184
MAX:574 | MIN:459 | RNG:116

Monday, August 17, 2020

Use System verilog constraints to Divide data of N into chunks of M

 Problem Statement:

You need to come up with the system verilog class < sequence item > which can generate or divide a large size of data N into smaller pieces of equal size, these small sized chunks have to be multiple of 4 - M. Maximum size is 64 and minimum is 4.

The left over data if it does not sum up to N, can be added last which need not match M.


Solution:

class chunks;
  int unsigned c[$];
  parameter SIZE = 200;
  rand bit [6:0] s;
 
  constraint c_size {
    s%4 == 0;
  }
 
  function void post_randomize();
    int tmp;
    tmp = SIZE - (SIZE/s * s); // If chunks doesnot add up to SIZE, collect the difference
   
    for(int i=0; i < (SIZE/s);i++) c.push_back(s);
    if(tmp !=0) c.push_back(tmp); // If non zero tmp is observed, simply add to the queue.
     
   
  endfunction
 
  function void display();
    $display("Size selected:%0d",s);
    $display("Queue value:%p",c);
  endfunction: display
endclass
 
 
  module top;
    chunks cs;
   
    initial begin
      cs = new;
      void'(cs.randomize());
      cs.display();
    end
  endmodule

Sunday, August 9, 2020

System verilog constraints interview question involving multiple variables

 

Sequence item is as follows:

rand unique_bit 

rand num_of_reqs;

rand Bit [10:0] x [];

rand Bit[10:0] y[];

rand Bit [10:0] width[];      

rand Bit [10:0] height[];

rand bit [10:0]  frame_width;

rand bit [10:0]  frame_height;

 

Conditions for constraints.....

  1. each request is combination of x,y, width & height

  2. x+width must be less than or equal to frame width

  3. y+height must be less than or equal to  frame height

  4. if unique bit is set , combination of x,y,w,h must not be equal to any of other x,y,w,h

 

Code::

 

class test;

  rand bit unique_bit;

  rand int unsigned num_of_reqs;

  rand bit [10:0] x[];

  rand bit [10:0] y[];

  rand bit [10:0] w[];      

  rand bit [10:0] h[];

  rand bit [10:0] frame_width;

  rand bit [10:0] frame_height;


  constraint c_num_reqs {

    num_of_reqs inside {[1:5]};

    x.size() == num_of_reqs;

    y.size() == num_of_reqs;

    w.size() == num_of_reqs;

    h.size() == num_of_reqs;

  }

 

  constraint c_frame_width {

    frame_width inside {[0:1023]}; // Constraint will fail , if you don't cap your width

    foreach (x[i]) {

      int'(x[i] + w[i])<= frame_width;

      x[i] inside {[0:frame_width]};

      w[i] inside {[0:frame_width]};

     }

  }

      

  constraint  c_frame_height {

    frame_height inside {[0:1023]}; // Constraint will fail , if you don't cap your height

    foreach (y[i]) {

      solve frame_height before x[i],h[i];

      int'(y[i] + h[i]) <= frame_height;

      y[i] inside {[0:frame_height]};

      h[i] inside {[0:frame_height]};

    }

  }

 

 constraint c_unique {

        solve unique_bit before x,y,w,h,frame_height,frame_width;

        if(unique_bit) {

          unique {x};

          unique {y};

          unique {w};

          unique {h};

        }

      }

        

  function void display();

    $display("Unique Bit:%0d",unique_bit);

    $display("Num of Requests:%0d", num_of_reqs);

    $display("Frame Height:%0d Width:%0d",frame_height,frame_width);

    foreach(x[i])

      $display("X:%04d W:%04d || Y:%04d H:%04d",x[i],w[i],y[i],h[i]);

  endfunction

        


endclass


module top;

 

  test t;

 

  initial begin

    t = new;

    if(!t.randomize()) $error("Randomization failed");

    t.display();

  end

endmodule

Saturday, August 8, 2020

Find duplicate element in system verilog array.

 

  1. Array of size 100

You have elements from 100 to 199 randomly shuffled.

One number is replaced with another number in the same range .. Find the replaced number and position. 

One Condition is that you should not use a nested loop

 

 

 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
module top;
  int unsigned arr[100];
  int unsigned change_index;
  int sum;
  int tmp[$];
  
  initial begin
    std::randomize(arr) with { foreach (arr[i]) { arr[i] inside {[100:199]};}
                               unique {arr}; 
                             };
    std::randomize(change_index) with { change_index inside {[10:99]}; };
    $display("Index:%0d Val:%0d",change_index,arr[change_index]);
    sum = arr.sum();
    arr[change_index] = 110;
    
    for( int i=0; i < 100; i++) begin //{
      tmp = arr.find_index with (item == arr[i]);
      if(tmp.size() > 1) begin //{
        $display("Duplicate found: Index:%0d Val:%0d",i,arr[i]);
        if(sum > arr.sum()) $display("Index:%0d Original:%0d Duplicate:%0d",i,arr[i]+(sum-arr.sum()),arr[i]);
        else                $display("Index:%0d Original:%0d Duplicate:%0d",i,arr[i]-(arr.sum()-sum),arr[i]);
        break;
      end //}
      tmp.delete();
    end //}
                                    

  end
endmodule

Sunday, August 2, 2020

To print values based on their decimal places

If you have an integer value, say 234 and you need to get all the values based on their decimal places.
You need to simple divide the integer say 'a', with its decimal position
(a/1 ) % 10 gives you the one's digit
(a/10) %10 gives you the ten's digit and so on.....


CODE:

module top;
  int unsigned a = 234;
 
  initial begin
    $display("A_1  :%0d",(a/1)%10  );
    $display("A_10 :%0d",(a/10)%10 );
    $display("A_100:%0d",(a/100)%10);
  end
 
endmodule:top

RESULT:
A_1 :4
A_10 :3
A_100:2

Saturday, August 1, 2020

Sorting array - descending order using 1 and 2 for loops.

Code
module top;
  int a[5] = {1,2,3,4,5};
  int tmp;
 
  initial begin //{
    // 2 loops
    for(int i=0; i< $size(a)-1;i++) begin //{
      for(int j=i+1;j <$size(a);j++) begin //{
        if(a[i] < a[j]) begin //{
          tmp  = a[i];
          a[i] = a[j];
          a[j] = tmp;
        end //}
      end //}
    end //}
    $display("Array:%p",a);
   
    // 1 loop
    a[5] = {1,2,3,4,5};
    for(int i=0; i<$size(a)-1;i++) begin//{
      if(a[i] < a[i+1]) begin //{
        tmp    = a[i];
        a[i]   = a[i+1];
        a[i+1] = tmp;
        i      = -1;
      end //}
    end //}
    $display("Array:%p",a);

  end //}
endmodule:top

Result
CPU time: .230 seconds to compile + .328 seconds to elab + .297 seconds to link
Chronologic VCS simulator copyright 1991-2019
Contains Synopsys proprietary information.
Compiler version P-2019.06-1; Runtime version P-2019.06-1; Aug 2 01:52 2020
Array:'{5, 4, 3, 2, 1}
Array:'{5, 4, 3, 2, 1}
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.640 seconds; Data structure size: 0.0Mb
Sun Aug 2 01:52:17 2020

Product of arrays except self

Code looks simple after looking at the answer 😆, i copied it from
https://leetcode.com/problems/product-of-array-except-self/solution/

In the first loop, you try to multiply all the array values to your left.
Since for the first entry has no left value, we can enter 1 for array location -0.

In the second loop, all you need to do is repeat the same for right.
However, you have 2 statements here.
1st statement , gives the final product ( except self ) to the location.
For the last entry there is no entry to right, we will replace it with 1 ( R=1).
R which represents the product of values to its Right is multiplied with Z[i].
R is loaded similar to the left product logic as mentioned above.

Code
module top;
  int a[5] = { 5,4,3,2,2 };
  int z[5];
  int R=1;
  initial begin
    z[0] = 1;
    for(int i=1; i< $size(a);i++) z[i] = z[i-1] * a[i-1];
   
    for(int i=$size(a)-1;i >=0;i--) begin //{
      z[i] = z[i] * R;
      R *= a[i];
    end //}
    $display("Array:%p",a);
    $display("Products:%p",z);
  end
endmodule

Answer
# vsim -voptargs=+acc=npr
# run -all
# Array:'{5, 4, 3, 2, 2}
# Products:'{48, 60, 80, 120, 120}

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

Thursday, July 23, 2020

Telephone dialer code in system verilog

Problem Statement :
Write a sequence item for telephone dialer with the following data
1. RECEPTION             - 0
2. EMERGENCY          - 911
3. LOCAL                     - 8 Digit Number
4. INTERNATIONAL  - 11 Digit number starting with 1. < 1-10Digits >

With the above code we can derive the constraints for each dial type.
RECEPTION - Just 0
EMERGENCY - Just 911
LOCAL - 8 Digit number must not start with 0 or have 911 as its first few numbers
INTERNATIONAL - 11 digit telephone number must start with 1.


CODE

typedef enum { RECEPTION, EMERGENCY, LOCAL, INTERNATIONAL } dial_type;
class telephone;
  rand bit [3:0] tele[];
  rand dial_type d;

  constraint c_tele {
    d dist { RECEPTION:= 1, EMERGENCY:= 1, LOCAL:= 1, INTERNATIONAL:= 1};
    if(d == RECEPTION) {
      tele.size() == 1;
      tele[0] == 'd0;
    }
    if(d == EMERGENCY) {
      tele.size() == 3;
      tele[0] == 'd9;
      tele[1] == 'd1;
      tele[2] == 'd1;
    }
    if(d == LOCAL) {
      tele.size() == 8;
      foreach(tele[i]) {
        if(i==0) { tele[i] inside {[2:9]}; }
        else     { tele[i] inside {[0:9]}; }
    }
     {tele[0],tele[1],tele[2]} != {4'h9,4'h1,4'h1}; }
    if(d == INTERNATIONAL) {
      tele.size() == 11;
      foreach(tele[i]) {
        if(i==0) { tele[i] == 'd1; }
        else     { tele[i] inside {[0:9]}; }
      } 
    }

  }

  function void display();
    $display("DIAL_TYPE:%s NUM:%p",d,tele);
  endfunction: display
endclass

module top;
 telephone t;

 initial begin
   t = new;
   repeat(20) begin
   void'(t.randomize());
   t.display();
   end
 end

endmodule: top

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