Class hierarchy was discussed in the previous session. Now, let's try to construct a testbench that will print out "Hello UVM". We'll keep the testbench simple with only two main components.
- Test
- Environment
Testbench Setup
The testbench structure is setup as shown in the image below, with the environment instantiated inside the test and the DUT interacting with the test via the DUT interface.


DUT
The DUT is a simple memory module that will accept data into the memory array upon a write transaction and provide data at the output ports for a read transaction. It has the following ports
module dut (
input clk, // Clock at some freq
input rstn, // Active Low Sync Reset
input wr, // Active High Write
input en, // Module Enable
input wdata, // Write Data
input addr, // Address
output rdata // Read Data
);
Interface
Let's put all the signals of the DUT inside an interface and use an interface handle to access the signals. The interface is defined as below.
interface dut_if (input clk);
logic rstn;
logic [7:0] wdata;
logic [7:0] rdata;
logic [7:0] addr;
logic wr;
logic en;
endinterface
DUT Wrapper
It'll be easier to instantiate the DUT in the top level module if we put a wrapper around it.
module dut_wrapper (dut_if _if);
// Instantiate the design module and connect interface signals to DUT
dut dsn0 ( .clk (_if.clk),
.rstn (_if.rstn),
.wr (_if.wr),
.en (_if.en),
.wdata (_if.wdata),
.addr (_if.addr),
.rdata (_if.rdata));
endmodule
With the DUT wrapper, instantiating at the top level reduces to a single line.
dut_wrapper dut_wr0 (._if (dut_if1));
Watch how to install Modelsim and run Hello World !
Test
The test is an object of uvm_test
and contains the environment. The interface handle is obtained from the top level module and will pass it to all components inside the environment. The test will also decide on what sequence to run when simulation is started. This is very convenient because now you have the ability to create multiple tests that can choose from a library of sequences wihtout having to edit the code in the testbench. Let's break the class test and go through each line.
class base_test extends uvm_test;
We have defined a class called base_test that inherits all the properties and methods from uvm_test
. Now, we have to register this component with the UVM factory for it to work properly by calling the macro `uvm_component_utils
because test is a derivative of uvm_component
.
`uvm_component_utils (base_test)
Now, we'll create an object of the environment and a virtual interface handle that can be made to point to the correct interface.
my_env m_top_env;
virtual dut_if dut_vi;
Next, we'll code the constructor new ()
with arguments name and parent (default is set to null).
function new (string name, uvm_component parent = null);
super.new (name, parent);
endfunction : new
Then, the build phase is defined to instantiate an object of the environment, and collect the interface from top level module. Note that we have called the parent's build phase first using super
keyword. The line that contains type_id
is the preferred way to create objects of classes in UVM. This is because it uses factory methods to create the object that can be easily substituted/modified later on. Note that you can also create an object using the new ()
method, but that does not make object instantiation flexible enough and hence is not recommended. The line that contains uvm_config_db
is the new way of setting and retrieving variable values in UVM. In C, you would have declared the variable to be global and it can be accessed from anywhere, in any header/C file. In UVM, variables can be put inside the database and make it available to selected components and only those components will be able to access the variable value. So, in this case we are trying to get the dut_if object from the database.
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
m_top_env = my_env::type_id::create ("m_top_env", this);
if (! uvm_config_db #(virtual dut_if) :: get (this, "", "dut_if", dut_vi)) begin
`uvm_error (get_type_name (), "DUT Interface not found !")
end
endfunction : build_phase
The function get ()
has arguments in the order ['context', 'instance_name', 'field_name', 'variable_to store_value'].
We can also print out the topology of the environment after the build and connect phases.
virtual function void end_of_elaboration_phase (uvm_phase phase);
uvm_top.print_topology ();
endfunction
In the start_of_simulation_phase you can specify the sequence that a particular sequencer has to operate on.
Environment
All we do in the environment is to print out a message "Hello UVM !"
class my_env extends uvm_env ;
`uvm_component_utils (my_env)
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase (phase);
endfunction : build_phase
task run_phase (uvm_phase phase);
set_report_verbosity_level (UVM_MEDIUM);
uvm_report_info (get_name(), $sformatf ("Hello UVM ! Simulation has started."), UVM_MEDIUM, `__FILE__, `__LINE__);
`uvm_info (get_name(), $sformatf("Finishing up with run_phase ... "), UVM_LOW)
endtask : run_phase
endclass : my_env
---------------------------------------------------------------- CDNS-UVM-1.1d (14.10-s004) (C) 2007-2013 Mentor Graphics Corporation (C) 2007-2013 Cadence Design Systems, Inc. (C) 2006-2013 Synopsys, Inc. (C) 2011-2013 Cypress Semiconductor Corp. ---------------------------------------------------------------- UVM_INFO @ 0: reporter [RNTST] Running test base_test... UVM_INFO @ 0: reporter [UVMTOP] UVM testbench topology: ------------------------------------ Name Type Size Value ------------------------------------ uvm_test_top base_test - @2601 m_top_env my_env - @201 ------------------------------------ UVM_INFO ./tb/my_pkg.sv(30) @ 0: uvm_test_top.m_top_env [m_top_env] Hello UVM ! Simulation has started. UVM_INFO ./tb/my_pkg.sv(31) @ 0: uvm_test_top.m_top_env [m_top_env] Finishing up with run_phase ... --- UVM Report catcher Summary --- Number of demoted UVM_FATAL reports : 0 Number of demoted UVM_ERROR reports : 0 Number of demoted UVM_WARNING reports: 0 Number of caught UVM_FATAL reports : 0 Number of caught UVM_ERROR reports : 0 Number of caught UVM_WARNING reports : 0 --- UVM Report Summary --- ** Report counts by severity UVM_INFO : 4 UVM_WARNING : 0 UVM_ERROR : 0 UVM_FATAL : 0 ** Report counts by id [RNTST] 1 [UVMTOP] 1 [m_top_env] 2 Simulation complete via $finish(1) at time 0 FS + 179
Go to the next step Data and Driver