Sunday, August 23, 2020

Driving chunks of data using verilog classes

 Problem Statement :

  • Consider a DUT which asks for say n chunks of data (n <=200 bytes). 
  • The driver needs to drive these chunks on the interface. 
  • Write a transaction class which randomly generates these chunks of data. 
  • Each chunk of data has to be a collection of beats where the size of all beats except the last one is a multiple of 4 and maximum beat size is 64.

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
class chunk_data #(parameter N =200);

  rand bit [7:0] data[$];
  rand bit [7:0] chunk_size[$];

  constraint data_size  { data.size == N; }
  constraint chuuk_size { chunk_size.size inside {[3:25]}; 
                          int'(chunk_size.sum) == N-(N%4);
                          foreach(chunk_size[i]) { 
                            chunk_size[i]%4 == 0; 
                            chunk_size[i] inside {[4:64]}; }
                        }

  function void post_randomize();
    int diff_chunk;
    diff_chunk = N - chunk_size.sum();
    if(diff_chunk != 0) chunk_size.push_back(diff_chunk);
  endfunction: post_randomize

  function void display();
    $display("==============================");
    foreach(chunk_size[i])
    $display("Chunk_Size:%0d",chunk_size[i]);
  endfunction: display
endclass: chunk_data


module top;
  parameter N = 199;
  chunk_data#(N) c;

  initial begin
    c = new;
    repeat(2) begin
      void'(c.randomize());
      c.display();
    end
  end
endmodule: top

 

Results :

Compiler version L-2016.06; Runtime version L-2016.06;  Aug 23 22:38 2020
==============================
Chunk_Size:4
Chunk_Size:4
Chunk_Size:24
Chunk_Size:4
Chunk_Size:20
Chunk_Size:4
Chunk_Size:4
Chunk_Size:36
Chunk_Size:20
Chunk_Size:24
Chunk_Size:4
Chunk_Size:4
Chunk_Size:36
Chunk_Size:8
Chunk_Size:3
==============================
Chunk_Size:56
Chunk_Size:4
Chunk_Size:20
Chunk_Size:8
Chunk_Size:20
Chunk_Size:8
Chunk_Size:4
Chunk_Size:52
Chunk_Size:24
Chunk_Size:3
           V C S   S i m u l a t i o n   R e p o r t
Time: 0
CPU Time:      1.780 seconds;       Data structure size:   0.0Mb
 

 

Saturday, August 22, 2020

Using System Verilog Constraints judiciously

System verilog constraints take up lot of simulation time if not used properly.

Let me try to illustrate it with an example.

Take a scenario where we need to generate unique address ( for burst traffic ) each time we randomize.

Configuration is as follows....

1. Page - 4096 ( 4K) 

2. Address range - 63: 0

3. Align signal is used to take either offset range ( range starts from offset value to the end of the page )

or to take the whole page as a burst ( 4096 in our case ).

align == 1 -> no page offset

align == 0 -> some page offset

Since the address is 64 bits and Page is 12 bits, I took a variable page_num ( 64 -12 = 52 sized vector ) to represent the pages that can be addressed with the address range ( 63:0 ).

Lets take 2 approaches to prove our point ( to pick the random address )

1. With Constraints

2. Without using constraints  


CASE 1 :

In this case, we simply used a queue to push all the used page numbers in post randomize.

For constraints we used unique keyword to make sure that we do not repeat the same value.


 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
class address_selector;
  rand bit [51:0] page_num;
  rand bit [11:0] page_offset;
  rand bit align;
  bit [51:0] used_pages[$];
  constraint c_addr {
    unique { used_pages, page_num }; 
  }
  constraint c_align {
    solve align before page_offset;
    (align == 1) -> page_offset == 0;
  }
  function void post_randomize();
    used_pages.push_back(page_num);
  endfunction: post_randomize
endclass: address_selector

module top;
  address_selector as;
  
  int transfer_size = 1024 * 1000; // Size of 1000K
  initial begin
    as = new;
    while (transfer_size > 0) begin
      void'(as.randomize());
      transfer_size = transfer_size - (4096 - as.page_offset);
      $display("TRANSFER SIZE:%0x ALIGN:%0d ADDR:%0x PAGE:%0x OFFSET:%0x",transfer_size,as.align, {as.page_num,as.page_offset},as.page_num,as.page_offset);
    end
  end
endmodule

Simulation results:

V C S   S i m u l a t i o n   R e p o r t
Time: 0
CPU Time:    143.710 seconds;       Data structure size:   0.0Mb
Sat Aug 22 04:39:05 2020
CPU time: .134 seconds to compile + .023 seconds to elab + .392 seconds to link + 144.630 seconds in simulation

 

CASE 2:

In this case, we used an associative array instead of  queue.

We removed the constraint for generating unique page numbers, instead we used logic to look for the address used ( page_num) inside the post_randomize() function.

 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
class address_selector;
  rand bit [51:0] page_num;
  rand bit [11:0] page_offset;
  rand bit align;
  bit [51:0] used_pages[*];
  constraint c_align {
    solve align before page_offset;
    (align == 1) -> page_offset == 0;
  }
  function void post_randomize();
    while(used_pages.exists(page_num)) begin
      std::randomize(page_num);
    end
    used_pages[page_num] = 1;
  endfunction: post_randomize
endclass: address_selector

module top;
  address_selector as;
  
  int transfer_size = 1024 * 1000;// 128 * 1024 * 100000;
  initial begin
    as = new;
    while (transfer_size > 0) begin
      void'(as.randomize());
      transfer_size = transfer_size - (4096 - as.page_offset);
      $display("TRANSFER SIZE:%0x ALIGN:%0d ADDR:%0x PAGE:%0x OFFSET:%0x",transfer_size,as.align, {as.page_num,as.page_offset},as.page_num,as.page_offset);
    end
  end
endmodule


Simulation results :

  V C S   S i m u l a t i o n   R e p o r t
Time: 0
CPU Time:      0.430 seconds;       Data structure size:   0.0Mb
Sat Aug 22 04:39:35 2020
CPU time: .141 seconds to compile + .022 seconds to elab + .460 seconds to link + .568 seconds in simulation


Conclusion :

See the difference 143 seconds vs .430 seconds.

For smaller address ranges, it doesn't make much of a difference, but for larger footprints it does show a significant improvement in the simulation times.

 


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}

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