Showing posts with label SV interviews. Show all posts
Showing posts with label SV interviews. Show all posts

Tuesday, August 12, 2025

Single Linked List in System Verilog

 Lets code a simple singly Linked List which traverse from head to tail in one direction.

Requirement is simple, you will have a Node which contains two main elements, data and pointer to next node.

On adding a new node, the new node should create a handle of the old node and assign the pointer to the new one.


CODE:

class Node;
  int id;
  int data;
  Node next_node;
  
  function new ( int i );
    id = i;
    next_node = null;
  endfunction: new
  
  function void load_data ( int val );
    data = val;
  endfunction: load_data

  function void add_node ( Node node );
    node.next_node  = new(id);
    node.next_node  = this;
  endfunction: add_node
  
 endclass: Node
  
  module top;
    Node n[10];
    
    initial begin
      foreach ( n[i] ) begin
        n[i]      = new(i);
        n[i].data = $urandom_range(10,100);
        if(i>0) n[i].add_node(n[i-1]);           
      end 
      
      foreach ( n[i] ) begin        
        if(i==9) 
          $display ( "NODE ID:%0d Data:%0d NEXT_PTR:NULL", n[i].id,n[i].data );
        else 
          $display ( "NODE ID:%0d Data:%0d NEXT_PTR:%0d", n[i].id,n[i].data,n[i].next_node.id );
      end
    end        
  endmodule: top



RESULT:

Compiler version U-2023.03-SP2_Full64; Runtime version U-2023.03-SP2_Full64; Aug 12 10:17 2025
NODE ID:0 Data:54 NEXT_PTR:1
NODE ID:1 Data:62 NEXT_PTR:2
NODE ID:2 Data:68 NEXT_PTR:3
NODE ID:3 Data:44 NEXT_PTR:4
NODE ID:4 Data:75 NEXT_PTR:5
NODE ID:5 Data:88 NEXT_PTR:6
NODE ID:6 Data:89 NEXT_PTR:7
NODE ID:7 Data:72 NEXT_PTR:8
NODE ID:8 Data:62 NEXT_PTR:9
NODE ID:9 Data:53 NEXT_PTR:NULL
V C S S i m u l a t i o n R e p o r t

Saturday, July 19, 2025

Generating AXI Strobe based on SIZE, DATA WIDTH

AXI write strobe is generated based on the axi size and data width supported. For example, if the axi interface you are using has 64 bit wide data bus, you can have strobe of 64/8 = 8 Let us take the same data width as an example to produce axi write strobe.

In this case, the strobe is set starting at address offset and continues till the size of the transfer is met.

For example, 
ADDR = 0x3
SIZE    = 0x2 (32 bits)
LEN     = 0x2 (3 beats)

For the first beat, ADDR = 0x3, STRB = 0xF8
For the second beat, ADDR = 0x7, STRB = 0x80
For the third beat, ADDR = 0xB, STRB = 0xF8

 
module top;
  parameter int DATA_WIDTH = 64;
  bit [2:0] aw_size;
  bit [7:0] aw_len;
  bit [31:0] aw_addr;
  bit [7:0] w_strb[$];
  bit [31:0] addr_align;
  
  function automatic bit [7:0] gen_strb ( input bit [31:0] addr, input bit [2:0] aw_size );
    bit [7:0] strb;
    int size_in_bytes = 2**aw_size;
    addr_align = addr % (DATA_WIDTH/8);
    
    
    for( int i=0;i<DATA_WIDTH/8;i++) begin
      if ( i inside {[addr_align:addr_align+size_in_bytes-1]}) strb[i] = 1;
      else strb[i] = 0;
    end
    //$display("ADDR_A:%0h BY:%0d STRB:%0h",addr_align,size_in_bytes,strb);
    return strb;
  endfunction
  
  function automatic void load_strb ( );
    bit [31:0] addr_l;
    for ( int i=0;i<aw_len+1;i++) begin
      addr_l = aw_addr + (i << aw_size);
      w_strb.push_back(gen_strb(addr_l,aw_size));
      $display("ADDR:%0d STRB:%0h",addr_l,w_strb[i]);
    end    
  endfunction
  
  initial begin
    aw_addr = 'h3;
    aw_len  = 'h2;
    aw_size = 'h2;
    load_strb();
  end
  endmodule

RESULT:

Compiler version U-2023.03-SP2_Full64; Runtime version U-2023.03-SP2_Full64; Oct 16 02:13 2025
ADDR:3 STRB:78
ADDR:7 STRB:80
ADDR:11 STRB:78
V C S S i m u l a t i o n R e p o r t

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

Friday, April 21, 2023

CIRCULAR QUEUE implementation in System Verilog


NOTE:

Print Statements are implemented on every function call.

The Read pointer in dequeue is incremented by one, if not empty before the print.

Same is the case for write pointer.


In this setup, I used the MSB of wr_ptr and rd_ptr to represent a rollover of the memory ( array ).This in turn is used to generate the FULL and EMPTY signals.


 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
class circular_queue;
  parameter int N = 5;
  parameter int WIDTH = 3;
  
  int arr[N];
  bit isFull;
  bit isEmpty;
  bit [WIDTH:0] wr_ptr; //clog2 ??
  bit [WIDTH:0] rd_ptr;
  
  extern function new();
  extern function void enqueue(int val);
  extern function int dequeue();
  extern function int peek();  
  
endclass: circular_queue
    
    function circular_queue::new();
      isEmpty = 1;
      isFull = 0;
    endfunction: new
    
    function void circular_queue::enqueue(int val);
      if(!isFull) begin
        isEmpty     = 0;
        arr[wr_ptr[WIDTH-1:0]] = val;
        wr_ptr[WIDTH-1:0] = (wr_ptr[WIDTH-1:0]+1) % N;
        wr_ptr[WIDTH] = wr_ptr[WIDTH-1:0] == 0 ? ~wr_ptr[WIDTH] : wr_ptr[WIDTH];
      end
      isFull = ( wr_ptr[WIDTH-1:0] == rd_ptr[WIDTH-1:0] && wr_ptr[WIDTH]!=rd_ptr[WIDTH]) ? 1 : 0;
      $display("ENQUEUE:: WR_PTR:%d RD_PTR:%d VAL:%02d ARR:%p FULL:%d EMPTY:%d",wr_ptr[WIDTH-1:0],rd_ptr[WIDTH-1:0],val,arr,isFull,isEmpty);
    endfunction: enqueue
    
    function int circular_queue::dequeue();
      int val;
      if(!isEmpty) begin
        isFull = 0;
        val = arr[rd_ptr[WIDTH-1:0]];
        rd_ptr[WIDTH-1:0] = (rd_ptr[WIDTH-1:0]+1) % N;
        rd_ptr[WIDTH] = rd_ptr[WIDTH-1:0] == 0 ? ~rd_ptr[WIDTH] : rd_ptr[WIDTH]; 
      end
      isEmpty = ( wr_ptr[WIDTH-1:0] == rd_ptr[WIDTH-1:0] && wr_ptr[WIDTH]==rd_ptr[WIDTH]) ? 1 : 0;
      $display("DEQUEUE:: WR_PTR:%d RD_PTR:%d VAL:%02d ARR:%p FULL:%d EMPTY:%d",wr_ptr[WIDTH-1:0],rd_ptr[WIDTH-1:0],val,arr,isFull,isEmpty);
      return val;
    endfunction: dequeue
    
    function int circular_queue::peek();
      int val;
      if(!isEmpty)
      val = arr[rd_ptr];
      $display("PEEK   :: WR_PTR:%d RD_PTR:%d VAL:%02d ARR:%p FULL:%d EMPTY:%d",wr_ptr[WIDTH-1:0],rd_ptr[WIDTH-1:0],val,arr,isFull,isEmpty);
      return val;
    endfunction: peek
    
module top;
  circular_queue cq;
  
  initial begin
    int wr_val;
    int rd_val;
    
    cq = new;
    repeat(4) begin
      wr_val = $urandom_range(1,100);
      cq.enqueue(wr_val);
    end
    repeat(20) begin
      randcase
      	2 : begin
          wr_val = $urandom_range(1,100);
          cq.enqueue(wr_val);
        end
        2 : begin
          rd_val = cq.dequeue();
        end
        1 : begin
          rd_val = cq.peek();
        end
      endcase
    end
  end
endmodule: top


> OUTPUT::

Chronologic VCS simulator copyright 1991-2021
Contains Synopsys proprietary information.
Compiler version S-2021.09; Runtime version S-2021.09; Apr 22 02:40 2023
ENQUEUE:: WR_PTR:1 RD_PTR:0 VAL:39 ARR:'{39, 0, 0, 0, 0} FULL:0 EMPTY:0
ENQUEUE:: WR_PTR:2 RD_PTR:0 VAL:61 ARR:'{39, 61, 0, 0, 0} FULL:0 EMPTY:0
ENQUEUE:: WR_PTR:3 RD_PTR:0 VAL:74 ARR:'{39, 61, 74, 0, 0} FULL:0 EMPTY:0
ENQUEUE:: WR_PTR:4 RD_PTR:0 VAL:71 ARR:'{39, 61, 74, 71, 0} FULL:0 EMPTY:0
DEQUEUE:: WR_PTR:4 RD_PTR:1 VAL:39 ARR:'{39, 61, 74, 71, 0} FULL:0 EMPTY:0
ENQUEUE:: WR_PTR:0 RD_PTR:1 VAL:97 ARR:'{39, 61, 74, 71, 97} FULL:0 EMPTY:0
ENQUEUE:: WR_PTR:1 RD_PTR:1 VAL:23 ARR:'{23, 61, 74, 71, 97} FULL:1 EMPTY:0
PEEK :: WR_PTR:1 RD_PTR:1 VAL:61 ARR:'{23, 61, 74, 71, 97} FULL:1 EMPTY:0
ENQUEUE:: WR_PTR:1 RD_PTR:1 VAL:91 ARR:'{23, 61, 74, 71, 97} FULL:1 EMPTY:0
DEQUEUE:: WR_PTR:1 RD_PTR:2 VAL:61 ARR:'{23, 61, 74, 71, 97} FULL:0 EMPTY:0
ENQUEUE:: WR_PTR:2 RD_PTR:2 VAL:58 ARR:'{23, 58, 74, 71, 97} FULL:1 EMPTY:0
DEQUEUE:: WR_PTR:2 RD_PTR:3 VAL:74 ARR:'{23, 58, 74, 71, 97} FULL:0 EMPTY:0
DEQUEUE:: WR_PTR:2 RD_PTR:4 VAL:71 ARR:'{23, 58, 74, 71, 97} FULL:0 EMPTY:0
PEEK :: WR_PTR:2 RD_PTR:4 VAL:97 ARR:'{23, 58, 74, 71, 97} FULL:0 EMPTY:0
ENQUEUE:: WR_PTR:3 RD_PTR:4 VAL:27 ARR:'{23, 58, 27, 71, 97} FULL:0 EMPTY:0
DEQUEUE:: WR_PTR:3 RD_PTR:0 VAL:97 ARR:'{23, 58, 27, 71, 97} FULL:0 EMPTY:0
DEQUEUE:: WR_PTR:3 RD_PTR:1 VAL:23 ARR:'{23, 58, 27, 71, 97} FULL:0 EMPTY:0
DEQUEUE:: WR_PTR:3 RD_PTR:2 VAL:58 ARR:'{23, 58, 27, 71, 97} FULL:0 EMPTY:0
ENQUEUE:: WR_PTR:4 RD_PTR:2 VAL:20 ARR:'{23, 58, 27, 20, 97} FULL:0 EMPTY:0
DEQUEUE:: WR_PTR:4 RD_PTR:3 VAL:27 ARR:'{23, 58, 27, 20, 97} FULL:0 EMPTY:0
DEQUEUE:: WR_PTR:4 RD_PTR:4 VAL:20 ARR:'{23, 58, 27, 20, 97} FULL:0 EMPTY:1
DEQUEUE:: WR_PTR:4 RD_PTR:4 VAL:00 ARR:'{23, 58, 27, 20, 97} FULL:0 EMPTY:1
ENQUEUE:: WR_PTR:0 RD_PTR:4 VAL:06 ARR:'{23, 58, 27, 20, 6} FULL:0 EMPTY:0
ENQUEUE:: WR_PTR:1 RD_PTR:4 VAL:73 ARR:'{73, 58, 27, 20, 6} FULL:0 EMPTY:0
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.700 seconds; Data structure size: 0.0Mb
Sat Apr 22 02:40:54 2023

Generating prime numbers between 1 to 100

  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 class test ; int prime_q[$]; function voi...