Thursday, October 16, 2025

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 void gen_prime();
    for(int i=0;i<100;i++) begin
      if(is_prime(i)) prime_q.push_back(i);
    end
    $display("Prime:%p",prime_q);
  endfunction
  
  function bit is_prime(int n);
    if(n<2) return 0;
    for(int i=2;i<n;i++) begin
      if(n%i==0) return 0;
    end
    return 1;
  endfunction
  
endclass

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


OUTPUT:
Compiler version U-2023.03-SP2_Full64; Runtime version U-2023.03-SP2_Full64; Oct 16 07:02 2025
Prime:'{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}
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.390 seconds; Data structure size: 0.0Mb
Thu Oct 16 07:02:15 2025

Tuesday, October 7, 2025

UVM HEARTBEAT

UVM HEART_BEAT 

The UVM heartbeat (uvm_heartbeat) is a class in the Universal Verification Methodology (UVM) that acts as a watchdog timer to monitor the activity of components in a verification environment.

Its primary purpose is to detect simulation hangs or lockups early on, before the global simulation timeout is reached. This can save significant simulation time.

Here's a breakdown of how it works:

  1. Watchdog Functionality: It provides a mechanism for environments to ensure their descendant components are still "alive" and actively contributing to the test.

  2. Association with Objection: A uvm_heartbeat object is associated with a specific objection object (specifically a uvm_callbacks_objection).

  3. Heartbeat "Pulse" (Activity Check):

    • A component being monitored by the heartbeat must raise or drop the associated objection during a defined "heartbeat window" or when a specific uvm_event is triggered. This action is considered the "heartbeat" or a sign of activity.

    • The monitoring process is typically started and triggered by a uvm_event.

  4. Failure Mechanism:

    • If the uvm_heartbeat monitor checks the activity (usually when its associated uvm_event is triggered) and does not detect the required objection activity from the monitored components within the window, it issues a FATAL error and terminates the simulation. This signals a lock-up or stall condition.

  5. Heartbeat Modes: The monitoring can be configured with different modes using the set_mode method:

    • : Every monitored component must trigger the objection.

    • : At least one of the monitored components must trigger the objection.

    • : Exactly one of the monitored components must trigger the objection.

In essence, the uvm_heartbeat ensures that critical components are making progress. If they stop, it assumes a hang and ends the test immediately.


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
class component extends uvm_component;
  uvm_objection obj;
  `uvm_component_utils(component)
  
  function new (string name = "component", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
  endfunction
  
  task run_phase(uvm_phase phase);
    int i;
    repeat(3) begin
      #40;
      obj.raise_objection(this);
      `uvm_info(get_name(), $sformatf("raised objection for i = %0d", i), UVM_LOW)
      i++;
    end
  endtask
endclass

class base_test extends uvm_test;
  uvm_objection obj;
  component comp;
  uvm_component hb_comp[$];
  uvm_heartbeat hb;
  uvm_event hb_e;
  
  `uvm_component_utils(base_test)
  
  function new (string name = "base_test", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    obj = new("obj");
    comp = component::type_id::create("comp", this);
    hb = new("hb", this, obj);
    hb_e = new("hb_e");
    
    comp.obj = this.obj;
  endfunction
  
  task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    
    hb.set_mode(UVM_ANY_ACTIVE);
    hb.set_heartbeat(hb_e,hb_comp);
    hb.add(comp);
    hb.start(hb_e);
    
    repeat(5) begin
      #50 `uvm_info(get_type_name(), $sformatf("triggering hb_e"), UVM_LOW)
      hb_e.trigger();
    end
    phase.drop_objection(this);
  endtask
endclass

module heartbeat_example();
  initial begin
    run_test("base_test");
  end
endmodule

RESULTS:

UVM_INFO @ 0: reporter [RNTST] Running test base_test...

UVM_INFO testbench.sv(18) @ 40: uvm_test_top.comp [comp] raised objection for i = 0
UVM_INFO testbench.sv(56) @ 50: uvm_test_top [base_test] triggering hb_e
UVM_INFO testbench.sv(18) @ 80: uvm_test_top.comp [comp] raised objection for i = 1
UVM_INFO testbench.sv(56) @ 100: uvm_test_top [base_test] triggering hb_e
UVM_INFO testbench.sv(18) @ 120: uvm_test_top.comp [comp] raised objection for i = 2
UVM_INFO testbench.sv(56) @ 150: uvm_test_top [base_test] triggering hb_e
UVM_INFO testbench.sv(56) @ 200: uvm_test_top [base_test] triggering hb_e
UVM_FATAL @ 200: uvm_test_top [HBFAIL] Did not recieve an update of obj on any component since last event trigger at time 150. The list of registered components is:
uvm_test_top.comp
UVM_INFO /apps/vcsmx/vcs/U-2023.03-SP2//etc/uvm-1.2/src/base/uvm_report_server.svh(904) @ 200: reporter [UVM/REPORT/SERVER]
--- UVM Report Summary ---

** Report counts by severity
UVM_INFO : 9
UVM_WARNING : 0
UVM_ERROR : 0
UVM_FATAL : 1
** Report counts by id
[HBFAIL] 1
[RNTST] 1
[UVM/RELNOTES] 1
[base_test] 4
[comp] 3

Saturday, September 27, 2025

Schedule meeting based on free time slots for 4 persons

 

Given free-time schedule in the form (a - b) i.e., from 'a' to 'b' of n people, print all time intervals where all n participants are available

  Person1: (4 - 16), (18 - 23)  
  Person2: (2 - 14), (17 - 24)  
  Person3: (6 - 8), (12 - 20)  
  Person4: (10 - 22) 

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
// Code your testbench here
// or browse Examples
class scheduler;
  int time_slots[23];
 int fr_q[$];
  
 int p1[24];
 int p2[24];
 int p3[24];
 int p4[24];
  
  function void free_time();
  
    for(int i=0;i<24;i++) begin
      p1[i]= (i inside {[4:16]} || i inside {[18:23]} ) ? 1 : 0;
      p2[i]= (i inside {[2:14]} || i inside {[17:24]} ) ? 1 : 0;
      p3[i]= (i inside {[6:8] } || i inside {[12:20]} ) ? 1 : 0;
      p4[i]= (i inside {[10:22]} ) ? 1 : 0;
    end
    
    $display("P:%p",p1);
    for(int i=0;i<23;i++) begin
      if ( p1[i]&&p1[i+1] ) time_slots[i]++;
      if ( p2[i]&&p2[i+1] ) time_slots[i]++;
      if ( p3[i]&&p3[i+1] ) time_slots[i]++;
      if ( p4[i]&&p3[i+1] ) time_slots[i]++;
       
    end
    $display("Time slots:%p",time_slots);
    fr_q = time_slots.find_index with ( item == 4 );
    $display("FR_Q:%p",fr_q);
    
    foreach ( fr_q[i] ) begin
      $display ("Free Slot at %0d-%0d",fr_q[i],fr_q[i]+1);
    end 
    
  endfunction: free_time
  
endclass: scheduler

module top;
  scheduler s;
  
  initial begin
    s = new;
    s.free_time();
  end
endmodule

Tuesday, August 12, 2025

Generate two arrays of length 10, whose elements are unique to each other.


CODE:

class mem;
  rand int a[10];
  rand int b[10];
  
  constraint c_a_b {
    unique { b };
    foreach ( a[i] ) {
      b[i] inside {[1:20]};
      a[i] inside {[1:20]};
      !(a[i] inside b);      
    }
  }
  
  function void post_randomize();
    $display ("A:%p",a);
    $display ("B:%p",b);
  endfunction: post_randomize
    
endclass: mem
    
module top;
  mem m;
  
  initial begin
    m = new;
    void'(m.randomize());
    
  end
endmodule: top


OUTPUT:

Compiler version U-2023.03-SP2_Full64; Runtime version U-2023.03-SP2_Full64; Aug 12 11:01 2025
A:'{4, 5, 17, 19, 8, 4, 5, 12, 9, 15}
B:'{18, 16, 3, 20, 1, 11, 7, 2, 10, 14}
V C S S i m u l a t i o n R e p o r t

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 26, 2025

TCAM

TCAM stands for Ternary Content Addressable Memory.

In this, instead of data, the search returns address and number of entries that match the search key.

What the code does:

  • TCAM is 16 locations deep.
  • TCAM class contains 3 methods.
    • load_tcam ( )     - It takes data and address as inputs and loads the TCAM memory
    • search_tcam ( ) - Lets dive more into this method, this is where things are handled differently when compared with the normal SRAM's. The inputs contain key and mask. Key is used to search all the entries and find the matching addresses. If there is a single hit, output bit match is set to 1. For multiple entries, match_entries field corresponding to the hit index is set to 1. Mask is what differentiates a normal CAM with TCAM. When MASK field is set to 1, the entry is always treated as matched irrespective of the contents of the entry. Finally address ( output ), this can be set as per the priority order set. In this case, I choose last match as the highest priority.
    • clear_tcam() - To clear all contents of the TCAM memory.

class tcam;
  logic [31:0] tcam_mem[16];
  
  virtual task clear_tcam ( );
    foreach (tcam_mem[i]) tcam_mem[i] = 0;
  endtask: clear_tcam
  
  virtual task load_tcam ( input logic [31:0] data , input logic [31:0] addr ); 
    tcam_mem[addr] = data;
  endtask: load_tcam
  
  virtual task search_tcam ( 
    input logic [31:0] key, 
    input logic [31:0] mask, 
    output bit match, 
    output bit [15:0] match_entries, 
    output bit [31:0] address );
for ( int i=0;i<16;i++ ) begin //{ // mask[i] == 1, don't care, always matches irrespective of key if(tcam_mem[i] == key || mask[i]) begin //{ match = 1; match_entries[i] = 1; address = i; // You can choose any priority, I choose priority of Last match address end //} end //} endtask: search_tcam endclass: tcam module top; tcam t; initial begin logic match; logic [31:0] match_entries; logic [31:0] match_address; t = new; t.load_tcam(10,0); t.load_tcam(20,1); t.load_tcam(25,2); t.load_tcam(30,3); t.load_tcam(20,4); t.search_tcam(20,0,match,match_entries,match_address); $display ("Match:%0d Entries:%0b Address:%0d",match, match_entries,match_address ); end endmodule: top

OUTPUT:

Compiler version U-2023.03-SP2_Full64; Runtime version U-2023.03-SP2_Full64; Jul 26 13:19 2025
Match:1 Entries:10010 Address:4
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.530 seconds; Data structure size: 0.0Mb
Sat Jul 26 13:19:05 2025
Done



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

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