UVM NOTES
Anoushka Tripathi
Reporting mechanisms
UVM provides us multiple reporting mechanisms that can be use to communicate data to
console
SV
$display
$strobe
$monitor
UVM_INFO
We use it to send info to terminal
UVM_INFO(ID,MSG,redundancy level)
ID → which class is sending the data
MSG → Message which we have to send to the terminal.
Redundancy level→ default : 200
Multiple verbosity levels
Typedef enum
UVM_NONE =0,
UVM_LOW=100,
UVM_MEDIUM=200,
UVM_HIGH=300,
UVM_FULL=400,
UVM_DEBUG=500,
}UVM_verbosity;
To display message on Console : Simulator
Configure Verbosity >= `uvm_info Verbosity
Formats
UVM_WARNING(ID,MSG)
UVM_ERROR(ID,MSG)
UVM_FATAL(ID,MSG)
CODE
`include "uvm_macros.svh" //All definitions of MACROS
import uvm_pkg::*;//All definitions of classes
module tb;
initial begin
#50;
`uvm_info("TB_TOP","Hello World", UVM_LOW);
$display("Hello World with Display");
end
endmodule
Output
Sending values of variable to console
`include "uvm_macros.svh"
import uvm_pkg::*;
module tb;
int data = 56;
initial begin
`uvm_info("TB_TOP", $sformatf("Value of data : %0d",data), UVM_NONE);
end
Verbosity
Message id
level
endmodule
Output
Working with Verbosity level and ID
`include "uvm_macros.svh"
import uvm_pkg::*;
module tb;
initial begin
uvm_top.set_report_verbosity_level(UVM_HIGH);
$display("Default Verbosity level : %0d ", uvm_top.get_report_verbosity_level);
`uvm_info("TB_TOP", "String", UVM_HIGH);
end
endmodule
uvm_top : Default component which we will execute when we call a run test
Since verbosity level is set to UVM_MEDIUM, all verbosity level set below than UVM_MEDIUM
will send data to console anything higher than that will not be displayed.
This helps in changing default verbosity level
uvm_top.set_report_verbosity_level(UVM_HIGH);
UVM_ROOT is parent to all the classes that we add in UVM Testbench environment(UVM Tree)
Because UVM_ROOT returns a null pointer, we cannot directly access it. However, in a few
situations, we may need to access or configure the default settings of UVM_ROOT.
In such a case, UVM provides a global variable UVM_TOP which is accessible to all classes of
environment. UVM_TOP could be used whenever we need to work with the UVM root.
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
class driver extends uvm_driver; //we extend the uvm driver to create a uvm driver class, we can
override method as per requirement
`uvm_component_utils(driver)// we register a class to a factory
Path name/string type Allow us to create uvm tree
function new(string path , uvm_component parent);///whenever we extend a uvm component,
the constructor have 2 arguments
super.new(path, parent); // this is how we add a constructor to a child class
endfunction
task run();
`uvm_info("DRV1", "Executed Driver1 Code", UVM_HIGH);
`uvm_info("DRV2", "Executed Driver2 Code", UVM_HIGH);
endtask
endclass
///////////////////
module tb;
driver drv; //here we create a instance of driver, this is not required if we call a run test as run
test will automatically create an instance of component in build phase
initial begin PATH NAME, AS THIS IS A STRING WE HAVE USED “ “
drv = new("DRV", null);
drv.set_report_id_verbosity("DRV1",UVM_HIGH);//Change verbosity (first start with class
name), WE CAN HAVE DRV2 also here
drv.run();
end
endmodule
OUTPUT:
In the context of UVM (Universal Verification Methodology), the function new(string path,
uvm_component parent) is a constructor for a child class that extends a uvm_component. Let's
break down the parts:
1. Constructor Definition
function new(string path, uvm_component parent);
• new: This is the constructor function, used to create and initialize an instance of the
class.
• string path: This is typically the hierarchical path of the UVM component. It helps
uniquely identify the component in the UVM hierarchy.
• uvm_component parent: This is a reference to the parent component in the UVM
hierarchy. Each component in UVM has a parent unless it is the top-level component.
2. Calling the Parent Class Constructor
super.new(path, parent);
• super.new(path, parent): This calls the constructor of the parent class (which is also a
uvm_component), passing the path and parent arguments to ensure that the parent
class is properly initialized before the child class starts its own initialization. This is
required when extending any UVM component, as the base class (uvm_component)
needs to be set up with a name (path) and its hierarchical location (parent).
Why is this necessary?
Whenever you extend a uvm_component, you must ensure that the base class
(uvm_component) is initialized with proper arguments for its path and parent, which are
essential for building and managing the UVM testbench hierarchy.
In summary, this code is defining a constructor for a child class that extends uvm_component
and ensures that the parent class constructor is called to correctly initialize the component in
the UVM environment.
Super.new()
Will refer to base/parent class constructor
-------------------------------------------------------------
class parent; // parent/ base class property
int a;
function new (int b) ; // parent class constructor // default argument are i/p and logic type
a=b; // assign b to a
$display ("value of a is 40d", a);
endfunction: new
endclass: parent
class child extends parent;
function new(int c); // child class constructor default argument are i/p and logic type
super.now (c) ; // refer to the base/parent class constructor
endfunction: new
endclass: child
module eg () ;
child c1: // handle for child class
WORKING WITH INDIVIUAL COMPONENT:
Let us see if we have multiple components than how we will change the verbosity of individual
component
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
class driver extends uvm_driver;
`uvm_component_utils(driver)
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
`uvm_info("DRV1", "Executed Driver1 Code", UVM_HIGH);
`uvm_info("DRV2", "Executed Driver2 Code", UVM_HIGH);
endtask
endclass
//////////////////////////////////////////////////
class env extends uvm_env;
`uvm_component_utils(env)
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
`uvm_info("ENV1", "Executed ENV1 Code", UVM_HIGH);
`uvm_info("ENV2", "Executed ENV2 Code", UVM_HIGH);
endtask
endclass
////////////////////
module tb;
driver drv;
env e;
initial begin
drv = new("DRV", null); //add constructor for both driver and env
e = new("ENV", null);
e.set_report_verbosity_level(UVM_HIGH);//here we change the verbosity of env class
drv.run();
e.run();
end
endmodule
WORKING WITH HIERARCHY:
If we want to change the verbosity of entire hierarchy, than also we have a specific method for it
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
class driver extends uvm_driver;
`uvm_component_utils(driver)
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
`uvm_info("DRV", "Executed Driver Code", UVM_HIGH);
endtask
endclass
///////////////////////////////////////////////////
class monitor extends uvm_monitor;
`uvm_component_utils(monitor)
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
`uvm_info("MON", "Executed Monitor Code", UVM_HIGH);
endtask
endclass
//////////////////////////////////////////////////
class env extends uvm_env;
`uvm_component_utils(env)
driver drv;
monitor mon;
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
drv = new("DRV", this);//2nd argument is the parent component,env will serve as a parent for
both driver and monitor
mon = new("MON", this);
drv.run();//main task for both drv and env
mon.run();
endtask
endclass
////////////////////
module tb;
env e;
initial begin
e = new("ENV", null);
e.set_report_verbosity_level_hier(UVM_HIGH);
e.run();
end
endmodule
We have env class in which there is drv class
OUTPUT
ENV class is a parent class here Path of hierarchy
MON and DRV are the child class here
MORE REPORTING MACROS
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
class driver extends uvm_driver;
`uvm_component_utils(driver)
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
`uvm_info("DRV", "Informational Message", UVM_NONE);
`uvm_warning("DRV", "Potential Error");
`uvm_error("DRV", "Real Error");
#10;
`uvm_fatal("DRV", "Simulation cannot continue");
endtask
endclass
/////////////////////////////////////////////
module tb;
driver d;
initial begin
d = new("DRV", null);
d.run();
end
endmodule
SEVERITY OF MACROS
Functions are available to change the capability to change macros.
Override functions help us change the severity.
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
class driver extends uvm_driver;
`uvm_component_utils(driver)
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
`uvm_info("DRV", "Informational Message", UVM_NONE);
`uvm_warning("DRV", "Potential Error");
`uvm_error("DRV", "Real Error");
#10;
`uvm_fatal("DRV", "Simulation cannot continue DRV1");
#10;
`uvm_fatal("DRV1", "Simulation Cannot Continue DRV1");
endtask
endclass
/////////////////////////////////////////////
module tb;
driver d;
initial begin
d = new("DRV", null);
// d.set_report_severity_override(UVM_FATAL, UVM_ERROR);// we wish to change uvm fatal
severity to uvm error
// change the severity of all uvm fatal to uvm error
Output with this program line
d.set_report_severity_id_override(UVM_FATAL, "DRV", UVM_ERROR);
d.run();
end
endmodule
CHANGING ASSOCIATED ACTIONS OF MACROS
UVM_ACTION : this macro simply remove all the default actions associated with a reporting
macros.
UVM_DISPLAY: Allows to send report to standard terminal
UVM_LOG: helps to send message to log file
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
class driver extends uvm_driver;
`uvm_component_utils(driver)
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
`uvm_info("DRV", "Informational Message", UVM_NONE);
`uvm_warning("DRV", "Potential Error");
`uvm_error("DRV", "Real Error"); ///uvm_count
`uvm_error("DRV", "Second Real Error");
/*
#10;
`uvm_fatal("DRV", "Simulation cannot continue DRV1"); /// uvm_exit
#10;
`uvm_fatal("DRV1", "Simulation Cannot Continue DRV1");
*/
endtask
endclass
////////////////////////////////////////////
module tb;
driver d;
initial begin
d = new("DRV", null);
d.set_report_max_quit_count(3);
d.run();
end
endmodule
d.set_report_severity_action(UVM_INFO,UVM_NO_ACTION)
this helps us override the function of UVM_INFO, uvm_info message will not be sent to console
d.set_report_severity_action(UVM_INFO,UVM_NO_DISPLAY | UVM_EXIT)
With this command it will send data to console and also terminate the simulation
OUTPUT of this command
We will not get other output as UVM_EXIT was executed
d.set_report_severity_action(UVM_FATAL,UVM_NO_DISPLAY)
we have changed the action of uvm_fatal for the entire class
OUTPUT of this command
WORKING WITH quit_count and UVM_ERROR
By default UVM_ERROR is considered for a quit count
Helps in setting the maximum threshold for maximum error, as soon as we reach that threshold
we will exit the simulation.
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
class driver extends uvm_driver;
`uvm_component_utils(driver)
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
`uvm_info("DRV", "Informational Message", UVM_NONE);
`uvm_warning("DRV", "Potential Error");
`uvm_error("DRV", "Real Error"); ///uvm_count
`uvm_error("DRV", "Second Real Error");
/*
#10;
`uvm_fatal("DRV", "Simulation cannot continue DRV1"); /// uvm_exit
#10;
`uvm_fatal("DRV1", "Simulation Cannot Continue DRV1");
*/
endtask
endclass
/////////////////////////////////////////////
module tb;
driver d;
initial begin
d = new("DRV", null);
d.set_report_max_quit_count(3);//setting the threshold
d.run();
end
endmodule
WORKING WITH LOG FILE:
Here our agenda is to store data from console to a file
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
class driver extends uvm_driver;
`uvm_component_utils(driver)
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
`uvm_info("DRV", "Informational Message", UVM_NONE);
`uvm_warning("DRV", "Potential Error");
`uvm_error("DRV", "Real Error");
`uvm_error("DRV", "Second Real Error");
endtask
endclass
/////////////////////////////////////////////
module tb;
driver d;
int file;//we create a int variable which will store the file descriptor id
initial begin
file = $fopen("log.txt", "w");
d = new("DRV", null);
//d.set_report_default_file(file); //this will send all the data for which you have enabled
UVM_LOG,allows data from all severity to a single file
d.set_report_severity_file(UVM_ERROR, file);
// d.set_report_severity_action(UVM_INFO, UVM_DISPLAY|UVM_LOG);//we have to display
data as well as log data into file
// d.set_report_severity_action(UVM_WARNING, UVM_DISPLAY|UVM_LOG);
d.set_report_severity_action(UVM_ERROR, UVM_DISPLAY|UVM_LOG);
d.run();
#10;
$fclose(file);
end
endmodule
BASE CLASSES : UVM_OBJECT
STATIC COMPONENTS
Few components in testbench enviournment will be there for entire simulation such
components are referred to as static components.
1. Scoreboard
2. Monitor
3. Driver
Whereas each transaction have life,until we compare that with expected data such components
are dynamic components.
Static components are made using uvm_component
Dynamic components are made using uvm_object. All dynamic components will be built by
extending uvm_object
Transaction → uvm_sequence_item
Uvm_component is built by deriving uvm_object, so we get all the properties of uvm_object in a
uvm_component
UVM_ COMPONENT
➔ UVM_TREE
➔ Phases
All these are not with uvm_object
UVM PROVIDES AUTOMATION.
We can specify the method without describing the method
Instead of using these we can use our own methods and describe them as well these are the
do_methods.
In library the do_copy is specified with virtual extern that means we will have to specify how we
want to use do_copy.
CREATING CLASS
TYPICAL WAY OF CREATING COMPONENTS IN SYSTEM VERILOG
class first;
rand bit[3:0} data;
endclass
module tb;
first f;
initial begin
f=new();
f.randomize();
$display(“VALUE OF DATA :%d,” f.data);
end
endmodule
`include "uvm_macros.svh"
import uvm_pkg::*;
class obj extends uvm_object;//We create obj class by extending uvm_object
`uvm_object_utils(obj) //register a class to factory,this gives us capability to perform some of
method automatically,it help us to perform factory override
function new(string path = "obj");//add a constructor
super.new(path);
endfunction
rand bit [3:0] a;
endclass
module tb;
obj o;
initial begin
o = new("obj");
o.randomize();
`uvm_info("TB_TOP", $sformatf("Value of a : %0d", o.a), UVM_NONE);
end
endmodule
`include "uvm_macros.svh"
import uvm_pkg::*;
class obj extends uvm_object;//We create obj class by extending uvm_object
function new(string path = "obj");//add a constructor
super.new(path);
endfunction
rand bit [3:0] a;
` uvm_object_utils_begin(obj)
`uvm_field_int(a, UVM_DEFAULT):
` uvm_object_utils_end
endclass
module tb;
obj o;
initial begin
o = new("obj");
o.randomize();
o.print();
end
endmodule
OUTPUT
Change the radix of data on console
If we want to change the format in which data is display
o.print();
As here in o.print() we have not choosen any method here so by default it will use
uvm_table_printer
OUTPUT : Tree format data
ENUM,REAL
`include "uvm_macros.svh"
import uvm_pkg::*;
class obj extends uvm_object;
// `uvm_object_utils(obj)
typedef enum bit [1:0] {s0 , s1, s2, s3} state_type;//We are expecting 4 states of fsm, if we don’t
provide value to these states, it will take default values
rand state_type state; //variable which will be working for state type is state
real temp = 12.34;
string str = "UVM";
function new(string path = "obj");
super.new(path);
endfunction
`uvm_object_utils_begin(obj)
`uvm_field_enum(state_type, state, UVM_DEFAULT);
`uvm_field_string(str,UVM_DEFAULT);
`uvm_field_real(temp, UVM_DEFAULT);
`uvm_object_utils_end
endclass
module tb;
obj o;
initial begin
o = new("obj");
o.randomize();
o.print(uvm_default_table_printer);
end
endmodule
OUTPUT
We have initialized this in typedef enum
MACROS FOR A INSTANCE OF A CLASS:
`include "uvm_macros.svh"
import uvm_pkg::*;
class parent extends uvm_object;
function new(string path = "parent");
super.new(path);
endfunction
rand bit [3:0] data;
`uvm_object_utils_begin(parent)
`uvm_field_int(data,UVM_DEFAULT);
`uvm_object_utils_end
endclass
class child extends uvm_object;
parent p;
function new(string path = "child");
super.new(path);
p = new("parent");
endfunction
`uvm_object_utils_begin(child)
`uvm_field_object(p,UVM_DEFAULT);
`uvm_object_utils_end
endclass
module tb;
child c;
initial begin
c = new("child");
c.p.randomize();
c.print();
end
endmodule
If we use c.randomize we will perform randomization of only the child class
With c.randomize
With c.p.randomize
ARRAYS
MACRO FOR STATIC ARRAY
`include "uvm_macros.svh"
import uvm_pkg::*;
class array extends uvm_object;
////////static array
int arr1[3] = {1,2,3};
///////Dynamic array
int arr2[];
///////Queue
int arr3[$];
////////Associative array
int arr4[int];
function new(string path = "array");
super.new(path);
endfunction
`uvm_object_utils_begin(array)//registering array to factory
`uvm_field_sarray_int(arr1, UVM_DEFAULT);//for static array
`uvm_field_array_int(arr2, UVM_DEFAULT);
`uvm_field_queue_int(arr3, UVM_DEFAULT);
`uvm_field_aa_int_int(arr4, UVM_DEFAULT);
`uvm_object_utils_end
task run(); Data type
///////////////////Dynamic array value update
arr2 = new[3];//initialize size of array allocate space for array
arr2[0] = 2;
arr2[1] = 2;
arr2[2] = 2;
///////////////////Queue
arr3.push_front(3);
arr3.push_front(3);
////////////////////Associative arrays
arr4[1] = 4;
arr4[2] = 4;
arr4[3] = 4;
arr4[4] = 4;
endtask
endclass
////////////////////////////////////////////
module tb;
array a;
initial begin
a = new("array");
a.run();
a.print();
end
endmodule
OUTPUT
COPY CLONE METHOD:
`include "uvm_macros.svh"
import uvm_pkg::*;
class first extends uvm_object;
rand bit [3:0] data;
function new(string path = "first");
super.new(path);
endfunction
`uvm_object_utils_begin(first)
`uvm_field_int(data, UVM_DEFAULT);
`uvm_object_utils_end
endclass
////////////////////////////////////////////
module tb;
first f;
first s;
/*
initial begin
f = new("first");
s = new("second");
f.randomize();
s.copy(f);
f.print();
s.print();
end
*/
initial begin
f = new("first");
f.randomize();
$cast(s, f.clone());
f.print();
s.print();
end
endmodule
OUTPUT
Both instance have same data
Cloning
initial begin
f=new(“first”);
f.randomize():
s=f.clone(); //incompatibility type error
f.print();
s.print();
end
endmodule
Why are we getting incompatibility type error??
The return of f.clone() is a parent class which is a uvm_object type, whereas s is of first type i.e
derived type.
How do we correct it?
initial begin
f=new(“first”);
f.randomize():
$cast(s,f.clone());
f.print();
s.print();
end
endmodule
OUTPUT
SHALLOW COPY Vs DEEP COPY
Copying using copy constructor.
OUTPUT
We created d1 object
We copied the d1 data into d2,this is called as copy.
This is a shallow copy example
-copy constructor
-implicit copy assignment operator
Here we used the copy assignment operator
SHALLOW COPY
Creating copy of object by copying data of all member variables as it is.
We will create a pointer in same code
Now in set data we will pass 3 arguments
Now if we do shallow copy of d1 block to d2
If 2 pointers ,point to same resource that is not desirable,that is why memory resource for d2
and d1 should be separate.
DEEP COPY and SHALLOW COPY IN UVM
`include "uvm_macros.svh"
import uvm_pkg::*;
class first extends uvm_object;
rand bit [3:0] data;
function new(string path = "first");
super.new(path);
endfunction
`uvm_object_utils_begin(first)
`uvm_field_int(data, UVM_DEFAULT);
`uvm_object_utils_end
endclass
///////////////////////////////////////
class second extends uvm_object;
first f;
function new(string path = "second");
super.new(path);
f = new("first");
endfunction
`uvm_object_utils_begin(second)
`uvm_field_object(f, UVM_DEFAULT);
`uvm_object_utils_end
endclass
////////////////////////////////////////////
module tb;
second s1, s2; ///shallow
initial begin
s1 = new("s1");//adding constructor for both instance
s2 = new("s2");
s1.f.randomize();
s1.print();
s2 = s1;
s2.print();
s2.f.data = 12;
s1.print();
s2.print();
end
endmodule
……………………………………………………………………………………………………………………………
initial begin
s1 = new("s1");//adding constructor for both instance
s2 = new("s2");
s1.f.randomize();
s1.print();
s2=s1;
s2.print();
end
initial begin
s1 = new("s1");//adding constructor for both instance
s2 = new("s2");
s1.f.randomize();
s1.print();
s2=s1;
s2.print();
s2.f.data =12;
s1.print
end
COMPARE METHOD
`include "uvm_macros.svh"
import uvm_pkg::*;
class first extends uvm_object;
rand bit [3:0] data;
function new(string path = "first");
super.new(path);
endfunction
`uvm_object_utils_begin(first)
`uvm_field_int(data, UVM_DEFAULT);
`uvm_object_utils_end
endclass
////////////////////////////////////////////
module tb;
first f1,f2;
int status = 0;
initial begin
f1 = new("f1");
f2 = new("f2");
f1.randomize();
f2.copy(f1);
f1.print();
f2.print();
status = f1.compare(f2);
$display("Value of status : %0d", status);
end
endmodule
If comparison is miscompared
If both instance have same data
CREATE METHOD
`include "uvm_macros.svh"
import uvm_pkg::*;
class first extends uvm_object;
rand bit [3:0] data;
function new(string path = "first");
super.new(path);
endfunction
`uvm_object_utils_begin(first)
`uvm_field_int(data, UVM_DEFAULT);
`uvm_object_utils_end
endclass
////////////////////////////////////////////
module tb;
first f1,f2;
initial begin
f1 = first::type_id::create("f1");//this will create object for first class,standard method of
creating object in UVM
f2 = first::type_id::create("f2");
f1.randomize();
f2.randomize();
f1.print();
f2.print();
end
endmodule
OUTPUT
FACTORY OVERRIDE
What are the advantages we get when we register our class to factory and use create method for
creating our object
For this we consider a example
Let us assume we are working on a certain project,we have completed the development of
entire testbench env , In our second release we will add one more control signal in our
transaction in class,Instead of changing the existing transaction we will extend the transaction
class and add new signal to it,now our agenda is all the places where we use the old transaction
class we need to replace that with new transaction class.
Factory can help us handle this situation easily,
In the next release of this testbench we want to add ACK to this TB.
`include "uvm_macros.svh"
import uvm_pkg::*;
class first extends uvm_object;
rand bit [3:0] data;
function new(string path = "first");
super.new(path);
endfunction
`uvm_object_utils_begin(first)
`uvm_field_int(data, UVM_DEFAULT);
`uvm_object_utils_end
endclass
/////////////////////////////////////
class first_mod extends first; // first modification to tb made by extending the first class
rand bit ack; //we added ack,which we want to add to recent version of code
function new(string path = "first_mod");
super.new(path);
endfunction
`uvm_object_utils_begin(first_mod)
`uvm_field_int(ack, UVM_DEFAULT);
`uvm_object_utils_end
endclass
////////////////////////////////////////////
class comp extends uvm_component;
`uvm_component_utils(comp)//register class to factory
first f;
function new(string path = "second", uvm_component parent = null);
super.new(path, parent);
f = first::type_id::create("f");//creating object
f.randomize();
f.print();
endfunction
endclass
/////////////////////////////////////////////
module tb;
comp c;
initial begin
c = comp::type_id::create("comp", null); //create object of component
end
endmodule
We still did not get ack here
So to get it we will use
//c.set_type_override_by_type( first ::get_type, first_mod ::get_type);
New class with the changes we want to introduce
Class which we want to override
After doing this change to our testbench.
module tb;
comp c;
initial begin
c.set_type_override_by_type( first ::get_type, first_mod ::get_type);
c = comp::type_id::create("comp", null); //create object of component
end
endmodule
do_print method
1) If we plan to use do methods, Field Macros are not required but
registering class to factory is mandatory to get capabilities of Factory
Override.
2) If we plan to use inbuilt implementation of the core methods then
registering class to factory as well as adding field macros to the data
members is mandatory
//////////////////////////////////////////////
`include "uvm_macros.svh"
import uvm_pkg::*;
class obj extends uvm_object;
`uvm_object_utils(obj)
function new(string path = "OBJ");
super.new(path);
endfunction
bit [3:0] a = 4;
string b = "UVM";
real c = 12.34;
virtual function void do_print(uvm_printer printer);
Source of value
super.do_print(printer);
printer.print_field_int("a", a, $bits(a), UVM_HEX);//$bits calculate total number of bits
printer.print_string("b", b);
printer.print_real("c", c);
What we want to print
endfunction
endclass
module tb;
obj o;
initial begin
o = obj::type_id::create("o");
o.print();
end
endmodule
convert2string
display values of data in single line
`include "uvm_macros.svh"
import uvm_pkg::*;
class obj extends uvm_object;
`uvm_object_utils(obj)
function new(string path = "OBJ");
super.new(path);
endfunction
bit [3:0] a = 4;
string b = "UVM";
real c = 12.34;
virtual function string convert2string();
string s = super.convert2string();
s = {s, $sformatf("a : %0d ", a)};
s = {s, $sformatf("b : %0s ", b)};
s = {s, $sformatf("c : %0f ", c)};
////a : 4 b : UVM c : 12.3400
return s;
endfunction
endclass
module tb;
obj o;
initial begin
o = obj::type_id::create("o");
//$display("%0s", o.convert2string());
`uvm_info("TB_TOP", $sformatf("%0s", o.convert2string()), UVM_NONE);
end
endmodule
do_compare
`include "uvm_macros.svh"
import uvm_pkg::*;
class obj extends uvm_object;
`uvm_object_utils(obj)
function new(string path = "obj");
super.new(path);
endfunction
rand bit [3:0] a;
rand bit [4:0] b;
virtual function void do_print(uvm_printer printer);
super.do_print(printer);
printer.print_field_int("a :", a, $bits(a), UVM_DEC);
printer.print_field_int("b :", b, $bits(b), UVM_DEC);
endfunction
virtual function void do_copy(uvm_object rhs);
obj temp;
$cast(temp, rhs);
super.do_copy(rhs);
this.a = temp.a;
this.b = temp.b;
endfunction
endclass
module tb;
obj o1,o2;
initial begin
o1 = obj::type_id::create("o1");
o2 = obj::type_id::create("o2");
o1.randomize();
o1.print();
o2.copy(o1);
o2.print();
end
endmodule