Skip to content

02.Basics

muneebullashariff edited this page Jan 4, 2024 · 16 revisions

1. Base Classes

The UVM library defines a set of base classes and utilities that facilitate the design of modular, scalable, reusable verification environments.

Untitled Diagram drawio

                Fig-1: Base classes in UVM

UVM_void

This doesn't have any purpose, but servers as base class for all UVM classes.

UVM_object

All components and transactions derive from uvm_object, which defines an interface of core class-based operations: create, copy, compare, print, sprint, record, etc. It also defines interfaces for instance identification (name, type name, unique id).

Code Snippet

`include "uvm_macros.svh"
import uvm_pkg::*;

typedef enum{RED, GREEN, BLUE} color_type;

class my_object extends uvm_object;

   color_type c;

   function  new(string name="my_object");
      super.new(name);
      `uvm_info("NEW", "creating my_object", UVM_LOW)
   endfunction

   function void display();
      for(int i = 0;i<3;i++)begin
         `uvm_info("my_object created", $sformatf("colour: %0s", c.name()), UVM_LOW)
         `uvm_info("ID", $sformatf("id: %0d",c), UVM_LOW)
         c=c.next();
      end
   endfunction:display

endclass:my_object

my_object mb;

module tb();

   initial begin
      mb = new();
      mb.display();
   end

endmodule

Output

obj_ut

                Fig-2: Output of UVM_object

GitHub Code Link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/obj_class/obj_ut/obj_ut.sv
GitHub log file link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/obj_class/obj_ut/obj_ut.sv

UVM_report_object

The uvm_report_object provides an interface to the UVM reporting facility. Through this interface, components issue the various messages that occur during simulation. Users can configure what actions are taken and what file(s) are output for individual messages from a particular component or for all messages from all components in the environment. Defaults are applied where there is no explicit configuration.

Code Snippet

`include "uvm_macros.svh"
import uvm_pkg::*;

class my_object extends uvm_object;

   function new(string name = "my_object");
      super.new(name);
      `uvm_info("NEW", "creating my_object class", UVM_LOW)
   endfunction

   function void display();
      `uvm_info("1", "hi_high", UVM_HIGH)
      `uvm_info("2", "hello_none", UVM_NONE)
      `uvm_info("3", "ciao_deb", UVM_DEBUG)
      `uvm_info("4", "hey_med", UVM_MEDIUM)
      `uvm_info("5", "hola_low", UVM_LOW)
      `uvm_info("6", "bonjour_full", UVM_FULL)
   endfunction:display

endclass:my_object

module tb();

   my_object mb;
  
   initial begin

      mb = new;
      mb.display();
  
   end

endmodule

Output

obj_rep

                Fig-3: Output of UVM_report_object  

GitHub Code Link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/obj_class/obj_rep/obj_rep.sv
GitHub log file link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/obj_class/obj_rep/obj_rep_op.log

UVM_component

The uvm_component class is the root base class for all UVM components. Components are quasi-static objects that exist throughout simulation. This allows them to establish structural hierarchy much like modules and program blocks.

Hierarchy Description
Phasing defines a phased test flow that all components follow, with a group of standard phase methods and an API for custom phases and multiple independent phasing domains to mirror DUT behavior
Configuration provides methods for configuring component topology and other parameters ahead of and during component construction.
Reporting provides a convenience interface to the uvm_report_handler.  All messages, warnings, and errors are processed through this interface.
Transaction recording provides methods for recording the transactions produced or consumed by the component to a transaction database (vendor specific).
Factory provides a convenience interface to the uvm_factory.  The factory is used to create new components and other objects based on type-wide and instance-specific configuration.

UVM_root

The uvm_root class is special uvm_component that serves as the top-level component for all UVM components, provides phasing control for all UVM components, and other global services.

Code Snippet

`include "uvm_macros.svh"
import uvm_pkg::*;

class my_comp extends uvm_component;

   bit [3:0]a;

   function  new(string name="my_comp", uvm_component parent);
      super.new(name, null);
      `uvm_info("NEW", "creating my_comp", UVM_LOW)
   endfunction

   function void display();
      for(int i = 0;i<3;i++)
      begin
         `uvm_info("Randamaizing", $sformatf("a: %0d", a), UVM_LOW)
         `uvm_info("STAT", $sformatf("Randamaize successful"), UVM_LOW)   
         a = $urandom();
      end
   endfunction:display

endclass:my_comp

module tb();

   my_comp cp;

   initial begin

      cp= new("cp",null);
      cp.display();

   end

endmodule

Output

root

                Fig-4: Output of UVM_root 

GitHub Code Link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/root_class/root.sv
GitHub log file link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/root_class/root_op.log

UVM_transaction

The uvm_transaction is the root base class for UVM transactions, which, unlike uvm_components, are transient in nature. It extends uvm_object to include a timing and recording interface.

Code Snippet

`include "uvm_macros.svh"
import uvm_pkg::*;

class my_tran extends uvm_transaction;

   randc bit [3:0] a;
   constraint c {a>9;}

   function new(string name = "my_tran");
      super.new(name);
   endfunction
 
   task display();
      #1 `uvm_info("Randomize", $sformatf("[%0t]a = %0d",$time,a),UVM_LOW)
   endtask

endclass

module tb;

   my_tran t;
  
   initial begin

      t=new();
      repeat(3)
      begin
         void'(t.randomize());
         t.display();
      end
   end
endmodule

Output

transaction

                Fig-5:  Output of UVM_transaction  

GitHub Code Link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/transcation/tran.sv
GitHub log file link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/transcation/tran_op.log

UVM_sequence_item

The base class for user-defined sequence items and also the base class for the uvm_sequence class. The uvm_sequence_item class provides the basic functionality for objects, both sequence items and sequences, to operate in the sequence mechanism.

Code Snippet

`include "uvm_macros.svh"
import uvm_pkg::*;

class my_seq_item extends uvm_sequence_item;

   rand bit [3:0] a;
   constraint c {a>9;}

   function new(string name = "my_seq_item");
      super.new(name);
   endfunction
 
   function void display();
      `uvm_info("Randomize", $sformatf("a = %0d",a),UVM_LOW)
   endfunction

endclass

module tb;

   my_seq_item s;
  
   initial begin
      s=new();
      repeat(3)
      begin
         void'(s.randomize());
         s.display();
      end
   end
endmodule

Output

seq

              Fig-6: Output of UVM_sequence_item

GitHub Code Link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/seq_item/seq.sv
GitHub log file link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/seq_item/seq_op.log

UVM_sequence

UVM sequence is a container that holds data items (uvm_sequence_items) which are sent to the driver via the sequencer.

Code Snippet

`include "uvm_macros.svh"
import uvm_pkg::*;

class my_seq_item extends uvm_sequence_item;

   rand bit [3:0] a;
   constraint c {a>9;}

   function new(string name = "my_seq_item");
      super.new(name);
   endfunction
 
   function void display();
      `uvm_info("Randomize", $sformatf("a = %0d",a),UVM_LOW)
   endfunction

endclass

module tb;

   my_seq_item s;
  
   initial begin
      s=new();
      repeat(3)
      begin
         void'(s.randomize());
         s.display();
      end
   end
endmodule

Output

sequence

              Fig-7: Output of UVM_sequence

GitHub Code Link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/seq/seq.sv GitHub log file link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/base_classes/seq/seq_op.log

2. UVM Utility & field macros

macros

The term ‘macro’ refers to the substitution of a line or a few lines of text code. The directive “define” creates a macro for substitution code. Once the macro is defined, it can be used anywhere in a compilation unit scope, wherever required. It can be called by the (`) character followed by the macro name. A macro can be defined with arguments. Arguments are useful to customize the macro to use widely, like a function task. Such macro arguments can be defined with default values so that if a DV engineer won’t pass any specific value, the macro substitutes the default value.

Example for the macro in SV

`define calculate(val1,val2,result,expression) \   
result = valu1 expression val2; \   
$display("result is %d",result);   
// the new line is preceded by a backslash    
module macro;  
int a=15,b=7;  
  int c;
  initial begin  
    calculate(a,b,c,+) //it will expand to calculate and display result
  end    
endmodule    

In UVM, To reduce coding overhead, the UVM library provides a set of macro declarations. These macros can be used to combine the definition of multiple things into one step (e.g., declare a field and a task, when both are required to exist at the same time).

UVM uses the concept of a factory, where all objects are registered with it so that it can return an object of the requested type when required. The utility macros help to register each object with the factory. It is required to be used inside every user-defined class that is derived from uvm_object which includes all types of sequence items and components.

Object Utility
All classes derived directly from uvm_object or uvm_transaction require them to be registered using `uvm_object_utils macro. Note that it is mandatory for the new function to be explicitly defined for every class, and takes the name of the class instance as an argument.

class ABC extends uvm_object;
// Register this user defined class with the factory
`uvm_object_utils(ABC)
  function new(string="ABC"); 
    super.new(name);
  endfunction
endclass

Component Utility

All classes derived directly or indirectly from uvm_component require them to be registered with the factory using `uvm_component_utils macro. Note that it is mandatory for the new function to be explicitly defined for every class derived directly or indirectly from uvm_component and takes the name of the class instance and a handle to the parent class where this object is instantiated.

class DEF extends uvm_component;
// Class derived from uvm_component, register with factory

   `uvm_component_utils(DEF)

   function new(string="DEF",uvm_component parent=null);
      super.new(name,parent);
   endfunction 

endclass

Creation of class object

It is recommended that all class objects are created by calling the type_id::create() method which is already defined using the macro `m_uvm_object_create_func. This makes any child class object to be created and returned using factory mechanism and promotes testbench flexibility and reusability.

class ABC extends uvm_object;  

   `uvm_object_utils(ABC)  

   function new(string name ="ABC");  
      super.new(name);  
   endfunction  

endclass  

class base_test extends uvm_test;  

   `uvm_component_utils(base_test)  

   function new(string name ="base_test",uvm_component parent=null);  
      super.new(name,parent);   
   endfunction  

   virtual function voidbuild_phase(uvm_phase phase);  
      // An object of class "ABC" is instantiated in UVM by calling// its "create()"    
      function which has been defined using a macroas shown above  
      ABC abc=ABC::type_id::create("abc_inst");  
   endfunction  

endclass  

Field macros

`uvm_field_* macros that were used between *_begin and *_end utility macros are basically called field macros since they operate on class properties and provide automatic implementations of core methods like copy, compare and print. This helps the user save some time from implementing custom do_copy, do_compare and do_print functions for each and every class. However, since these macros are expanded into general code, it may impact simulation performance and are generally not recommended.

Usage Example

class ABC extends uvm_object;  
   randbit[15:0] m_addr;  
   randbit[15:0] m_data;  

   `uvm_object_utils_begin(ABC)  
   `uvm_field_int(m_addr,UVM_DEAFULT)  
   `uvm_field_int(m_data,UVM_DEAFULT)  
   `uvm_object_utils_end

   function new(string name="ABC");
      super.new(name);
   endfunction

endclass

The uvm_field_*corresponding to the data type of each variable should be used. For example, variables of type int, bit, byte should use `uvm_field_int, while variables of type string should use uvm_field_string and so on. The macro accepts atleast two arguments: ARG and FLAG.

Argument Description
ARG Name of the variable, whose type should be appropriate for the macro that is used
FLAG When set to something other than UVM_DEFAULT or UVM_ALL_ON, it specifies which data method implementations will not be included. For example, if FLAG is set to NO_COPY, everything else will be implemented for the variable except copy.

The field FLAG can take the following values and multiple values can be OR'ed together. A combination of these flags determine the kind of operations that are allowed to be done on the given variable.

Flag Description
UVM_ALL_ON All operations are turned on
UVM_DEFAULT Enables all operations and equivalent to UVM_ALL_ON
UVM_NOCOPY Do not copy the given variable
UVM_NOCOMPARE Do not compare the given variable
UVM_NOPRINT Do not print the given variable
UVM_NOPACK Do not pack or unpack the given variable
UVM_REFERENCE Operate only on handles, i.e. for object types, do not do deep copy, etc

Along with control on operations, `uvm_field_* macros also provide some control on the radix of the given variable which can take the following values. This value can be used with the operational flags listed in the table above. UVM_HEX is the default radix if none is specified.

Radix Description
UVM_BIN Print/record the given variable in binary format
UVM_DEC Print/record the given variable in decimal format
UVM_HEX Print/record the given variable in hexadecimal format
UVM_OCT Print/record the given variable in octal format
UVM_STRING Print/record the given variable in string format
UVM_TIME Print/record the given variable in time format

3. UVM Object

UVM Object is basically a class in which functions to print, copy and compare objects of the same class are defined.
So, it is important to import uvm_object class and also extend from this class to use these methods in our test bench.

UVM Object (1)

                Fig-8: UVM_object   

print()

This function prints the content i.e., name, size, datatype and value of the variable in table format by default.

Here is a basic example to know how print function of uvm_object works.

Code Snippet

class example extends uvm_object;
   int a[3];
   string b;
   bit [2:0]c;

   `uvm_object_utils_begin(example)
   `uvm_field_sarray_int(a, UVM_DEFAULT)
   `uvm_field_string(b, UVM_DEFAULT)
   `uvm_field_int(c, UVM_DEFAULT)
   `uvm_object_utils_end

   function new(string name="example");
      super.new(name);
      this.a={1,2,3};
      this.b="HELLO";
      this.c=4;
   endfunction

endclass
               Fig-9: Creating a class which extends uvm_object 

TB Code:

class test extends uvm_test;
   
   `uvm_component_utils(test)

   function new(string name="test", uvm_component parent=null);
      super.new(name,parent);
   endfunction

   function void build;
      example Ex = example::type_id::create("Ex");
      Ex.print();
   endfunction

endclass

module uvm_object_print_tb;
   test t;
   initial begin
      t=test::type_id::create("t",null);
      t.build();
   end
endmodule
                Fig-10: Creating a test class to print contents of above class   

Output

Screenshot (475)

                Fig-11: Output of UVM_object_print  

GitHub Code Link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/obj_print/uvm_object_print.sv
GitHub Test Bench code link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/obj_print/uvm_object_print_tb.sv

do_print()

Instead of using macros in the print() function to register the class properties into factory we can explicitly write a do_print() function in which we use the object of uvm_printer to print the required contents of the class.

Here, a new function do_print() is added to the code.

Code Snippet

class example extends uvm_object;
   string b;
   bit [2:0]c;

   `uvm_object_utils(example)

   function new(string name="example");
      super.new(name);
      this.b="HELLO";
      this.c=4;
   endfunction

   function void do_print(uvm_printer printer);
      super.do_print(printer);
      printer.print_string("b",b);
      printer.print_int("c",c,$bits(c));
   endfunction

endclass

TB code:-

class test extends uvm_test;

   `uvm_component_utils(test)

   function new(string name="test", uvm_component parent=null);
      super.new(name,parent);
   endfunction

   function void build;
      example Ex = example::type_id::create("Ex");
      Ex.print();
   endfunction

endclass

module uvm_object_print_do_tb;
   test t;
   initial begin
      t=test::type_id::create("t",null);
      t.build();
   end
endmodule
               Fig-12: do_print()   

do_print() function is by default called by print() function.

Output

Screenshot (478)

                Fig-13: Output of do_print() 

GitHub Code Link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/obj_print/uvm_object_do_print.sv
GitHub Test Bench code link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/obj_print/uvm_object_print_do_tb.sv

sprint()

It returns the formatted content in string format which can further be stored in a variable of string datatype.

Code Snippet
TB Code:

class test extends uvm_test;

   `uvm_component_utils(test)

   function new(string name="test", uvm_component parent=null);
      super.new(name,parent);
   endfunction

   function void build;
      example Ex = example::type_id::create("Ex");
      string s=Ex.sprint();
      $display(s);
   endfunction
endclass

module uvm_object_sprint_tb;
   test t;
   initial begin
      t=test::type_id::create("t",null);
      t.build();
   end
endmodule

Output

Screenshot (482)

               Fig-14: Output of sprint()

GitHub Code Link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/obj_print/uvm_object_print.sv
GitHub Test Bench code link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/obj_print/uvm_object_sprint_tb.sv

NOTE: Here in the above 3 functions- print() and do_print() are of void type so they will not return any thing and sprint() is of string type. Also do_print() is called by using print() and print() function called by sprint() internally for printing the contents.

convert2string()

This function is written explicitly which returns a string instead of printing in a predefined format. And we can print the contents in a single line if wanted.

Code Snippet

class example extends uvm_object;
   string b;
   bit [2:0]c;

   `uvm_object_utils(example)

   function new(string name="example");
      super.new(name);
      this.b="HELLO";
      this.c=4;
   endfunction

   function string convert2string();
      string s=" ";
      $sformat(s,"%s b = %s",s,b);
      $sformat(s,"%s c = %0h",s,c);
      return s;
   endfunction

endclass

TB code:-

import uvm_pkg::*;
`include "uvm_object_conv2str.sv"
`include "uvm_macros.svh"

class test extends uvm_test;
   `uvm_component_utils(test)

   function new(string name="test", uvm_component parent=null);
      super.new(name,parent);
   endfunction

   function void build;
      example Ex = example::type_id::create("Ex");
      `uvm_info(get_type_name(),$sformatf("Contents:%s",Ex.convert2string()),UVM_LOW)
   endfunction

endclass

module uvm_object_con2str_tb;
   test t;
   initial begin
      t=test::type_id::create("t",null);
      t.build();
   end
endmodule

Output

Screenshot (485)

               Fig-15: Output of convert2string()

GitHub Code Link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/obj_print/uvm_object_con2str.sv
GitHub Test Bench code link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/obj_print/uvm_object_con2str_tb.sv

4. object copy method():

UVM object has copy method to copy the content of one object to another object. This copy method is same as deep copy in systemverilog.

syntax:
Destination.copy(source);

code snippet:

class mem_seq_item extends uvm_sequence_item;
   rand bit [3:0]a;
   rand bit b;
   rand bit c;
  
   //Utility and Field macros,
   `uvm_object_utils_begin(mem_seq_item)
   `uvm_field_int(a,UVM_ALL_ON)
   `uvm_field_int(b,UVM_ALL_ON)
   `uvm_field_int(c,UVM_ALL_ON)
   `uvm_object_utils_end
  
   //Constructor
   function new(string name = "mem_seq_item");
      super.new(name);
   endfunction
  
endclass

//-------------------------------------------------------------------------
//Simple TestBench to access sequence item
//-------------------------------------------------------------------------
module seq_item_tb;
  
   //instance
   mem_seq_item seq_item_0;
   mem_seq_item seq_item_1;
  
   initial begin
      //create method
      seq_item_0 = mem_seq_item::type_id::create("seq_item_0"); 
      seq_item_1 = mem_seq_item::type_id::create("seq_item_1");
    
      seq_item_0.randomize(); //randomizing the seq_item   
      seq_item_0.print();     //printing the seq_item_0
    
      //copy method
      seq_item_1.copy(seq_item_0); //copy seq_item_0 to seq_item_1
      seq_item_1.print();          //printing the seq_item_1
   end  
endmodule  

Output:

copy _uvm
                Fig-16: Output of Object_copy     

By using the method "seq_item_1.copy(seq_item_0); " the contents of seq_item_0 are copied in to seq_item_1.

5. object clone method():

object clone method is same as object copy but the only difference is that clone method create an object and returns the copy of the object so, that clone method saves the time of creating another object before copying. simply we can say that clone method is create method followed by copy method .In clone method $cast is used because we are assigning a parent class handle to a derived class handle.

syntax

$cast(destination,source.clone());

code snippet:

class mem_seq_item extends uvm_sequence_item;
   rand bit [3:0]a;
   rand bit b;
   rand bit c;
  
   //Utility and Field macros,
   `uvm_object_utils_begin(mem_seq_item)
   `uvm_field_int(a,UVM_ALL_ON)
   `uvm_field_int(b,UVM_ALL_ON)
   `uvm_field_int(c,UVM_ALL_ON)
   `uvm_object_utils_end
  
   //Constructor
   function new(string name = "mem_seq_item");
      super.new(name);
   endfunction
  
endclass

//-------------------------------------------------------------------------
//Simple TestBench to access sequence item
//-------------------------------------------------------------------------
module seq_item_tb;
  
   //instance
   mem_seq_item seq_item_0;
   mem_seq_item seq_item_1;
  
   initial begin
      //creating seq_item_0  
      seq_item_0 = mem_seq_item::type_id::create("seq_item_0"); 
    
      seq_item_0.randomize(); //randomizing the seq_item   
      seq_item_0.print();     //printing the seq_item_0
      //clone method
      $cast(seq_item_1,seq_item_0.clone()); cloning seq_item_0 to seq_item_1
    
      seq_item_1.print();          //printing the seq_item_1
   end  
endmodule   

In the code we created object seq_item_0 but object seq_item_1 is not created ,even though the clone method creates the object seq_item_1 and copies the content of seq_item_0 to seq_item_1

** Output:**

copy _uvm
                Fig-17: Output of UVM_Object_clone   

In the output we an see that by using "$cast(seq_item_1,seq_item_0.clone());" the clone method creates the object seq_item_1 and copies the content of seq_item_0 to seq_item_1.

6. UVM object compare

compare()

uvm_object is a base_class which have many common functions like print,copy and compare in it. These functions are available to all the child classes of uvm_object base_class.
Deep compares members of this data object with those of the object provided in the rhs (right-hand side) argument, returning 1 on a match, 0 othewise.
The compare method is not virtual and should not be overloaded in derived classes.

This is the function general syntax for a compare() method in base_class uvm_object

function bit compare(uvm_object rhs, uvm_comparer comparer=null);

The optional comparer argument specifies the comparison policy. It allows you to control some aspects of the comparison operation. It also stores the results of the comparison, such as field-by-field miscompare information and the total number of miscompares.
If a compare policy is not provided, then the global uvm_default_comparer policy is used.

Syntax:
class_name object_1,object_2;
object_1.compare(object_2);

code snippet:

`include "uvm_macros.svh"
import uvm_pkg::*;

class object extends uvm_object;
   rand bit [3:0]a;
   rand bit [2:0]b;
  
   `uvm_object_utils_begin(object)
      `uvm_field_int(a,UVM_DEFAULT)
      `uvm_field_int(b,UVM_DEFAULT)
   `uvm_object_utils_end
  
   function new(string name = "object");
      super.new(name);
   endfunction:new

endclass:object

class sample;

   object obj_1,obj_2;
  
   function void creating();
      obj_1 = object::type_id::create("obj_1");
      obj_2 = object::type_id::create("obj_2");
   endfunction:creating
  
   function void randomization();
      void'(obj_1.randomize() with {a inside {1,2,3};});
      void'(obj_2.randomize() with {a inside {4,5,6};});
   endfunction:randomization
  
   function void comparing();
      if(obj_1.compare(obj_2))
      begin
         `uvm_info("v","obj_1 matching with obj_2",UVM_LOW)
         obj_1.print();
         obj_2.print();
      end
      else
      begin
         `uvm_error("v","obj_1 is not matching with obj_2")
         obj_1.print();
         obj_2.print();
      end
   endfunction:comparing
  
   function void copying();
      obj_2.copy(obj_1);
   endfunction:copying
 
endclass:sample

module top;
   sample s = new;
   
   initial begin:BEGIN_I
      s.creating();
      repeat(3)
      begin:BEGIN_LOOP
         s.randomization();
         s.comparing();
      end:BEGIN_LOOP
      s.copying();
      s.comparing();
   end:BEGIN_I
  
endmodule:top

output:

In the below Fig-18 , we are doing comparision between two objects of same class i.e., obj_1 and obj_2. There are two rand variables a and b after randomization we are comparing all the variables in both the objects if any one of the variable was not matched then the simulator gives an info_message as Mismatched.
Next we are doing copy of all the variables from obj_1 to obj_2 Then again we compare both the objects.

compare

                Fig-18: Output for uvm_object compare method.  

Github lab link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/obj_compare/uvm_object_compare.sv

Github log_file link: https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_BJT/basics/obj_compare/compare.log

do_compare()

The do_compare method is the virtual user-definable hook called by the compare method. A derived class should override this method to include its fields in a compare operation. It should return 1 if the comparison succeeds, 0 otherwise.
To compare the fields of a derived class, that class should override the do_compare method.

Syntax:

virtual function bit do_compare (uvm_object rhs,uvm_comparer comparer);

7. UVM object pack and unpack

Pack and unpack are a part of UVM automation macros that are used to pack class variables to convert into bitstream.

Method Description
pack Performs a bit-wise concatenation of object's properties into an array of type bit.
pack_bytes Performs a bit-wise concatenation of object's properties into an array of type byte.
pack_ints Performs a bit-wise concatenation of the object's properties into an array of type int.
do_pack The do_pack method is the user-definable hook called by the pack methods.
unpack Extracts property values from an array of type bit and stores into correct class variable.
unpack_bytes Extracts property values from an array of type byte and stores into correct class variable.
unpack_ints Extracts property values from an array of type int and stores into correct class variable.
do_unpack The do_unpack method is the user-definable hook called by the pack methods.

code snippet:

class test extends uvm_test;

   `uvm_component_utils(test)
   
   function  new(string name= "test",uvm_component parent=null);
      super.new(name,parent);
   endfunction
   
   my_object obj;
   bit bits[];
   byte unsigned bytes[];
   int unsigned ints[];
   my_object unp_obj;
   
   virtual function void build_phase(uvm_phase phase);
      obj=my_object::type_id::create("my_object",this);
      obj.randomize();
      obj.print();
      $display("before pack values of byte are %p and stream bytes is %p",obj.data,bytes);
      obj.pack(bits);
      obj.pack_bytes(bytes);
      $display("after pack values of byte are %p and stream bytes is %p",obj.data,bytes);
      obj.pack_ints(ints);
      `uvm_info(get_type_name(),$sformatf("pack bitdata=%p",bits),UVM_LOW)
      `uvm_info(get_type_name(),$sformatf("pack bytedata=%p",bytes),UVM_LOW)
      `uvm_info(get_type_name(),$sformatf("pack intdata=%p",ints),UVM_LOW)
      $display("----------------------------------------------------------");
      unp_obj=my_object::type_id::create("my_object",this);
      unp_obj.unpack(bits);
      unp_obj.unpack_bytes(bytes);
      unp_obj.unpack_ints(ints);
      unp_obj.print();
      `uvm_info(get_type_name(),$sformatf("pack bitdata=%p",bits),UVM_LOW)
      `uvm_info(get_type_name(),$sformatf("pack bytedata=%p",bytes),UVM_LOW)
      `uvm_info(get_type_name(),$sformatf("pack intdata=%p",ints),UVM_LOW)
   endfunction  
    
endclass

output:

image

                Fig-19: Output of the code

Output explanation

In the above code obj is the handle of the my_object class that extends uvm_object.All the properties in the class are packed into bitstream in the bits array and all the class properties are packed into bytestream in bytes array and into intstream by ints array. The main objective of the pack is to convert all the object properties into the required stream,for example in the code the array bytes stores all the values of the object properties in the form of byte datatype,you can see in the output that the byte type class property is only data and the size is 5 bytes but after packing the bytestream bytes has 10 values of byte type,this is how the pack works.And unpack helps us to distribute the values to the respective class variables.

Note
1.do_pack and do_unpack are functions that implement all the packing and unpacking in single function call. 2.unpack actions are done by the receiver side like instance of same one class can unpack the values packed usong the instance o another class.

Why pack and unpack?

In bus protocol,you will be having a large amount of data on particular bus transaction and hence it becomes very tough to extract specific field value from that bus transactions. So we use classes on higher level,so that by using different fields,it becomes easy for you to control the value of those fields.
But in real hardware,everything is in bits,so you need to convert those class fields into valid bit patterns and transmit them along the bus.for that we use pack at transmitter and unpack at receiver.

Github Lab link:- https://github.com/vineethkumarv/uvm-repos/blob/master/pack/goex.sv

Clone this wiki locally