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

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

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



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

How to kill a thread(s) in System Verilog

 The code use process class to kill the thread. 

class base;
  int id;
  
  task display();
    int x=0;
    for(int i=0;i<5;i++) begin 
      #10ns;
      x++;
      $display("%t BASE:%0d X:%0d",$time,id,x);
    end
  endtask

endclass

class test;
  process p[4];
  task run_phase();
    for(int i=0;i<4;i++) begin //{
      base b = new;
      fork: fork_p
        automatic base b1 = b;
        automatic int j = i;
        begin: run_d
          p[j] = process::self();
          b1.id = j;
          b1.display();
        end
      join_none
    end //}
    $display("%t Threads spawned",$time);
  endtask
  
endclass

module top;
  test t;
  
  initial begin
    t = new;
    fork
    t.run_phase();
    join_none
     #30ns;
    foreach(t.p[i]) t.p[i].kill();
  end
  
endmodule
  

Result:

Compiler version U-2023.03-SP2_Full64; Runtime version U-2023.03-SP2_Full64; Sep 17 10:31 2024
0 Threads spawned
10 BASE:0 X:1
10 BASE:1 X:1
10 BASE:2 X:1
10 BASE:3 X:1
20 BASE:0 X:2
20 BASE:1 X:2
20 BASE:2 X:2
20 BASE:3 X:2
V C S S i m u l a t i o n R e p o r t
Time: 30 ns
CPU Time: 0.370 seconds; Data structure size: 0.0Mb
Tue Sep 17 10:31:42 2024

How to bind multiple instances of module inside DUT

module my_mod ( input clk, input rst );
endmodule: my_mod
 
module dut ( input clk, input rst );
  genvar i;
  generate
    for(i=0;i<2;i++) begin: gen_my_mod
      my_mod u_my_mod ( .clk(clk), .rst(rst) );
    end
  endgenerate
endmodule
 
module bind_x ( input clk, input rst );
endmodule: bind_x
 
module tb;
  bit clk;
  bit rst;
  dut u_dut ( .clk(clk), .rst(rst) );
  bind u_dut.gen_my_mod[0].u_my_mod bind_x bind_inst (.clk(clk), .rst(rst));
  bind u_dut.gen_my_mod[1].u_my_mod bind_x bind_inst (.clk(clk), .rst(rst));
endmodule: tb

Saturday, April 22, 2023

KNIGHT TOUR in System Verilog

Following is the SV code for knight tour. On each randomisation, we get the next position of knight.

The concept is simple, based on which we derived the constraints.

  1. knight should operate within boundaries of the chess board.
  2. knight can move on any direction if it does not violate point (1).
  3. The position of the knight can be taken as row, col.
  4. At best it can move in 8 directions
    1. If row is incremented/decremented by 2 positions, column can move 1 position from the latest row pos.
    2. If row is incremented/decremented by 1 position, column can move 2 position from the latest row pos.
  5. The position is calculated based on the board length, current row and column.

NOTE:
I'll check if we can walk with the knight on the chess board without repeating the same chess square again.
I doubt that there might some limitations to achieve this.
I'll  update on it, as and when I get some clues ...

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
class knight_walk;
  parameter int N = 5;
  int row;
  int col;
  rand int next_row;
  rand int next_col;
  rand int pos;
  
  function new ();
    row = $urandom_range(0,N-1);
    col = $urandom_range(0,N-1);
    pos = N*row + col;
    $display(" INITIAL POS:%0d ROW:%0d COL:%0d",pos,row,col);
  endfunction
  
  constraint c_knight {
    solve next_row before next_col;
    next_row inside { row+2,row-2,row+1,row-1 };
    next_col inside { col+2,col-2,col+1,col-1 };
    next_row inside {[0:4]};
    next_col inside {[0:4]};
    
    if( next_row inside {row+2,row-2} ) { next_col inside {col+1,col-1}; }
    else                                { next_col inside {col+2,col-2}; }
    
   }
  
  function void post_randomize();
    row = next_row;
    col = next_col;
    pos = row*N+col;
    $display("POST_RANDOMIZE:: POS:%0d ROW:%0d COL:%0d",pos,row,col);
  endfunction
  
  
endclass: knight_walk

module top;
  knight_walk chess;
  
  initial begin
    chess = new;
    repeat(4)
    void'(chess.randomize());
  end
endmodule: top



RESULTS:
Compiler version S-2021.09; Runtime version S-2021.09; Apr 22 04:34 2023
INITIAL POS:3 ROW:0 COL:3
POST_RANDOMIZE:: POS:12 ROW:2 COL:2
POST_RANDOMIZE:: POS:19 ROW:3 COL:4
POST_RANDOMIZE:: POS:8 ROW:1 COL:3
POST_RANDOMIZE:: POS:1 ROW:0 COL:1
POST_RANDOMIZE:: POS:8 ROW:1 COL:3
POST_RANDOMIZE:: POS:1 ROW:0 COL:1
POST_RANDOMIZE:: POS:8 ROW:1 COL:3
POST_RANDOMIZE:: POS:1 ROW:0 COL:1
POST_RANDOMIZE:: POS:8 ROW:1 COL:3
POST_RANDOMIZE:: POS:11 ROW:2 COL:1
V C S S i m u l a t i o n R e p o r t

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