UVM Notes
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
UVM_INFO(ID,MSG,redundancy level)
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
Formats
UVM_WARNING(ID,MSG)
UVM_ERROR(ID,MSG)
UVM_FATAL(ID,MSG)
CODE
module tb;
initial begin
#50;
end
endmodule
Output
Sending values of variable to console
`include "uvm_macros.svh"
import uvm_pkg::*;
module tb;
initial begin
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);
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.
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
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
endfunction
task run();
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
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
• 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.
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).
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()
-------------------------------------------------------------
int a;
function new (int b) ; // parent class constructor // default argument are i/p and logic type
a=b; // assign b to a
endfunction: new
endclass: parent
function new(int c); // child class constructor default argument are i/p and logic type
endfunction: new
endclass: child
module eg () ;
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::*;
//////////////////////////////////////////////////
`uvm_component_utils(driver)
function new(string path , uvm_component parent);
super.new(path, parent);
endfunction
task run();
endtask
endclass
//////////////////////////////////////////////////
`uvm_component_utils(env)
super.new(path, parent);
endfunction
task run();
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);
drv.run();
e.run();
end
endmodule
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::*;
//////////////////////////////////////////////////
`uvm_component_utils(driver)
super.new(path, parent);
endfunction
task run();
endtask
endclass
///////////////////////////////////////////////////
`uvm_component_utils(monitor)
super.new(path, parent);
endfunction
task run();
endtask
endclass
//////////////////////////////////////////////////
`uvm_component_utils(env)
driver drv;
monitor mon;
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.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
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
`uvm_component_utils(driver)
super.new(path, parent);
endfunction
task run();
#10;
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.
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
`uvm_component_utils(driver)
super.new(path, parent);
endfunction
task run();
#10;
`uvm_fatal("DRV", "Simulation cannot continue DRV1");
#10;
endtask
endclass
/////////////////////////////////////////////
module tb;
driver d;
initial begin
d = new("DRV", null);
d.run();
end
endmodule
CHANGING ASSOCIATED ACTIONS OF MACROS
UVM_ACTION : this macro simply remove all the default actions associated with a reporting
macros.
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////////////////////////////////
`uvm_component_utils(driver)
super.new(path, parent);
endfunction
task run();
/*
#10;
#10;
*/
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
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::*;
//////////////////////////////////////////////////
`uvm_component_utils(driver)
endfunction
task run();
/*
#10;
#10;
*/
endtask
endclass
/////////////////////////////////////////////
module tb;
driver d;
initial begin
d = new("DRV", null);
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::*;
//////////////////////////////////////////////////
`uvm_component_utils(driver)
super.new(path, parent);
endfunction
task run();
endtask
endclass
/////////////////////////////////////////////
module tb;
driver d;
int file;//we create a int variable which will store the file descriptor id
initial begin
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_WARNING, UVM_DISPLAY|UVM_LOG);
d.set_report_severity_action(UVM_ERROR, UVM_DISPLAY|UVM_LOG);
d.run();
#10;
$fclose(file);
end
endmodule
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.
Dynamic components are made using uvm_object. All dynamic components will be built by
extending uvm_object
Transaction → uvm_sequence_item
UVM_ COMPONENT
➔ UVM_TREE
➔ Phases
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;
endclass
module tb;
first f;
initial begin
f=new();
f.randomize();
end
endmodule
`include "uvm_macros.svh"
import uvm_pkg::*;
super.new(path);
endfunction
endclass
module tb;
obj o;
initial begin
o = new("obj");
o.randomize();
end
endmodule
`include "uvm_macros.svh"
import uvm_pkg::*;
super.new(path);
endfunction
` 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
As here in o.print() we have not choosen any method here so by default it will use
uvm_table_printer
ENUM,REAL
`include "uvm_macros.svh"
import uvm_pkg::*;
// `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
super.new(path);
endfunction
`uvm_object_utils_begin(obj)
`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
import uvm_pkg::*;
super.new(path);
endfunction
`uvm_object_utils_begin(parent)
`uvm_field_int(data,UVM_DEFAULT);
`uvm_object_utils_end
endclass
parent p;
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
With c.randomize
With c.p.randomize
ARRAYS
MACRO FOR STATIC ARRAY
`include "uvm_macros.svh"
import uvm_pkg::*;
////////static array
///////Dynamic array
int arr2[];
///////Queue
int arr3[$];
////////Associative array
int arr4[int];
super.new(path);
endfunction
`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
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
import uvm_pkg::*;
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
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.
initial begin
f=new(“first”);
f.randomize():
$cast(s,f.clone());
f.print();
s.print();
end
endmodule
OUTPUT
OUTPUT
We created d1 object
SHALLOW COPY
import uvm_pkg::*;
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;
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;
initial begin
s2 = new("s2");
s1.f.randomize();
s1.print();
s2 = s1;
s2.print();
s2.f.data = 12;
s1.print();
s2.print();
end
endmodule
……………………………………………………………………………………………………………………………
initial begin
s2 = new("s2");
s1.f.randomize();
s1.print();
s2=s1;
s2.print();
end
initial begin
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::*;
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);
end
endmodule
If comparison is miscompared
If both instance have same data
CREATE METHOD
`include "uvm_macros.svh"
import uvm_pkg::*;
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
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
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.
In the next release of this testbench we want to add ACK to this TB.
`include "uvm_macros.svh"
import uvm_pkg::*;
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
super.new(path);
endfunction
`uvm_object_utils_begin(first_mod)
`uvm_field_int(ack, UVM_DEFAULT);
`uvm_object_utils_end
endclass
////////////////////////////////////////////
first f;
super.new(path, parent);
f = first::type_id::create("f");//creating object
f.randomize();
f.print();
endfunction
endclass
/////////////////////////////////////////////
module tb;
comp c;
initial begin
end
endmodule
We still did not get ack here
module tb;
comp c;
initial begin
end
endmodule
do_print method
1) If we plan to use do methods, Field Macros are not required but
Override.
members is mandatory
//////////////////////////////////////////////
`include "uvm_macros.svh"
import uvm_pkg::*;
class obj extends uvm_object;
`uvm_object_utils(obj)
super.new(path);
endfunction
bit [3:0] a = 4;
string b = "UVM";
real c = 12.34;
Source of value
super.do_print(printer);
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::*;
`uvm_object_utils(obj)
super.new(path);
endfunction
bit [3:0] a = 4;
string b = "UVM";
real c = 12.34;
string s = super.convert2string();
return s;
endfunction
endclass
module tb;
obj o;
initial begin
o = obj::type_id::create("o");
//$display("%0s", o.convert2string());
end
endmodule
do_compare
`include "uvm_macros.svh"
import uvm_pkg::*;
class obj extends uvm_object;
`uvm_object_utils(obj)
super.new(path);
endfunction
super.do_print(printer);
endfunction
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