UVM Environment
Learning Objectives
After completing this lab, you should be able to:
Create a simple UVM test environment
Embed report messages
Compile the test environment
Run simulation and observe results
Add data, sequencer and driver classes to the
environment
Compile and simulate the environment to observe
behavior
Lab Duration:
45 minutes
UVM Verification Environment Lab 1-1
Synopsys 40-I-054-LG-004
Lab 1
Getting Started
UVM consists of a set of coding guidelines with a set of base classes and macros.
The set of base classes and macros assist you in developing testbenches that are
consistent in look and feel. The set of coding guidelines enable you to develop
testbench components which are robust and highly re-usable. As a result, you will
spend less time modifying, maintaining the verification infrastructure and more time
verifying your designs.
In this first lab, you will start the process of build a UVM verification environment
using the UVM base classes and macros following the UVM coding guidelines:
program automatic test;
// class definitions
initial begin
run_test();
end
endprogram
build
Environment class
connect
end_of_elaboration Agent Agent
start_of_simulation
Sequencer
run
extract
Monitor Scoreboard Monitor
check
Driver
TBD TBD TBD
report
final
DUT
Figure 1. Lab 1 Testbench Architecture
Lab 1-2 UVM Verification Environment
SystemVerilog UVM 1.1 Workshop
Lab 1
Lab Overview
After you log in, you will see three directories: labs, solutions and rtl.
labs/ solutions/ rtl/
lab1/ Lab7/ lab1/ Lab7/ router.sv
Figure 2. Lab Directory Structure
For each individual lab, you will work in the specified lab directory. Should you
have a question during the lab and want to know what the potential solution is, you
can reference the sample solution provided in the solutions directory.
The work flow for this lab is illustrated as follows:
Create
UVM Test File
Create
UVM Test
Program file
Compile and simulate
UVM Testbench
Add Sequence_item,
Sequence, Driver,
Agent and
Environment
Display Testbench
topology
Figure 3. Lab 1 Flow Diagram
UVM Verification Environment Lab 1-3
SystemVerilog UVM 1.1 Workshop
Lab 1
Building a UVM Testbench
Task 1. Create a Simple Test
For this first task, you will create a simple test and a program block to execute this
simple test. Use the lecture material as your reference.
1. Go into lab1 directory:
> cd labs/lab1
2. Open the existing test_collection.sv file with an editor, and look for
the comment that start with: “// Lab 1: task 1, step 2”.
Enter the class declaration as described in the comment
3. Look for the “// Lab 1: task 1. Step 3” comment.
Register the class with the factory
4. Look for “// Lab 1: task 1. Step 4” comment.
Enter the constructor code as described in the comments
Note: You will be asked to enter the following statement at the beginning
of each method. This is to help you during debugging. With this
statement embedded in every method, you can easily see how
things are being executed sequentially by setting the report
verbosity to UVM_HIGH. Within the statement, %m is a format
specifier that prints the current hierarchical path.
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
5. Near the bottom of the file, look for “// Lab 1: task 1, step 5”
comment in start_of_simulation_phase() method.
Enter the helpful debugging code as described in the comments
6. Save and close the file.
7. Open a new file, call it test.sv. Enter the following test code:
program automatic test;
import uvm_pkg::*;
`include "test_collection.sv"
initial begin
$timeformat(-9, 1, "ns", 10);
run_test();
end
endprogram
Lab 1-4 UVM Verification Environment
SystemVerilog UVM 1.1 Workshop
Lab 1
8. Save and close the file.
9. Compile and simulate this simple UVM testbench:
> vcs –sverilog –ntb_opts uvm-1.1 test.sv
> simv +UVM_TESTNAME=test_base
At the end of simulation, you should see something like the following:
Test as specified by
UVM_INFO @ 0: reporter [RNTST] Running test test_base... +UVM_TESTNAME
#### Factory Configuration (*)
No instance or type overrides are registered with this factory
You will be modifying the test via factory
All types registered with the factory: 37 total configuration with overrides in future labs
(types without type names will not be printed)
Type Name factory.print() displays all class
--------- types registered in the factory via the
test_base `uvm_component_utils macro
Note: The compilation switch to enable UVM is –ntb_opts. There are
several flavors of UVM switches: uvm, uvm-1.0, uvm-1.1 (in the
future there will be uvm-1.2, uvm-2.0 etc.). Be careful and
make sure that you are using the proper version for your project.
Task 2. Create a Simple Environment
In this task, you will build a simple environment that includes sequence item
(packet), sequence (packet_sequence), sequencer (sequencer), driver
(driver) agent (input_agent) and environment (router_env). With very
little effort, you can start to generate stimulus and see interactions between the
sequencer and the driver.
1. Open the packet.sv file with an editor, and look for the comments that
start with: “// Lab 1” and enter the following: (If necessary, look in the
slides for the exact syntax)
The class declaration
The sa, da, and payload properties
And, the constructor
Note: There is a major difference between data class constructor and
component class constructor. In the data class constructor, there is
no parent component handle in the argument.
To create the supporting methods (print, copy, compare, etc.) for properties in
a UVM class, you should use `uvm_field_* macros embedded within the
`uvm_object_utils_begin/end macros (to be covered in the next
unit). These are already done in the file for you, along with a constraint.
2. Save and close the file
UVM Verification Environment Lab 1-5
SystemVerilog UVM 1.1 Workshop
Lab 1
3. Open the packet_sequence.sv file with an editor, and look for the
comments that start with: “// Lab 1”. Enter the following:
The class declaration
And the body() method (see comments)
4. Save and close the file.
With the packet and the packet_sequence classes, you have created
the base mechanism for generating stimulus in UVM.
The next step is to create the component that will be processing the stimulus.
5. Open the driver.sv file with an editor, and look for the comments that
start with: “// Lab 1”. Enter the following:
The class declaration
Print the request (req) sequence item
in the run_phase() method
For now, the driver just gets a packet (req) from the sequencer via the
built-in seq_item_port and displays the content on the console. In future
labs, you will be calling the device driver to drive the contents of the request
object through the DUT.
6. Save and close the file.
Once you have the stimulus generating mechanism and the component to
process the stimulus, you are ready to create the container that will house
them. This container is called an agent.
7. Open the input_agent.sv file with an editor, and look for the comments
that start with: “// Lab 1”. Enter the following:
Use typedef to create a packet_sequencer class for packet
Declare the input_agent class
Create an instance of packet_sequencer and driver
Create these in the build phase
Connect the driver’s and sequencer’s TLM ports in the connect phase
Lab 1-6 UVM Verification Environment
SystemVerilog UVM 1.1 Workshop
Lab 1
8. Save and close the file.
You are now ready to build an environment class for your DUT.
9. Open the router_env.sv file with an editor, and look for the comments
that start with: “// Lab 1”. Enter the following:
Declare a router_env class
Create an instance of input_agent
Construct it in the build phase
Then, set the agent’s sequencer to execute packet_sequence as
the default sequence in the main phase
10. Save and close the file.
An environment consists of a set of components that are configured to process
some default stimulus through the DUT. Where these configurations and
stimulus will be managed is at the test level.
11. Open the test_collection.sv file with an editor and look for the
comments that start with with: “// Lab 1, task 2, step 11”.
Enter the following:
Include the environment file
Create an instance of the environment
Construct the environment object
Print the test topology
12. Save and close the file.
UVM Verification Environment Lab 1-7
SystemVerilog UVM 1.1 Workshop
Lab 1
Task 3. Run Test
1. Use make to compile and run simulation.
> make
You should see that ten packets were printed.
2. Take a look at the simulation result:
> less simv.log
You should see something like the following:
UVM_INFO @ 0: reporter [RNTST] Running test test_base...
UVM_INFO @ 0: reporter [UVMTOP] UVM testbench topology:
-------------------------------------------------------------
Name Type Size Value
-------------------------------------------------------------
uvm_test_top test_base - @460
env router_env - @469
i_agent input_agent - @477
drv driver - @599
rsp_port uvm_analysis_port - @614
sqr_pull_port uvm_seq_item_pull_port - @606
seqr uvm_sequencer - @490
rsp_export uvm_analysis_export - @497
seq_item_export uvm_seq_item_pull_imp - @591
arbitration_queue array 0 -
lock_queue array 0 -
num_last_reqs integral 32 'd1
num_last_rsps integral 32 'd1
------------------------------------------------------------
Test topology printed in table format.
You can display the content in tree format with:
#### Factory Configuration (*) uvm_top.print_topology(uvm_default_tree_printer);
No instance or type overrides are registered with this factory
All types registered with the factory: 42 total
(types without type names will not be printed)
Type Name
factory.print() result.
---------
All class type registered in the factory
driver
via the `uvm_component_utils() and the
input_agent
`uvm_object_utils() macro are printed.
packet
packet_sequence
router_env
If you name your tests properly, you
test_base
can easily identify all of your tests here.
Lab 1-8 UVM Verification Environment
SystemVerilog UVM 1.1 Workshop
Lab 1
Task 4. Run Testbench with Different Log Verbosity
In the previous task, you may have noticed that none of the embedded uvm_info
messages were printed. This is because the default display verbosity of the UVM
reporting mechanism filters out all levels below UVM_MEDIUM. In the
router_env, each of the `uvm_info message were set to the verbosity level
UVM_HIGH. The verbosity being filtered out are: UVM_HIGH, UVM_FULL and
UVM_DEBUG. The recommended way to treat these verbosity levels is to use:
UVM_HIGH for tracing messages
UVM_FULL for general debugging messages
UVM_DEBUG for more detailed debugging messages
1. Turn on the trace messages:
> make verbosity=UVM_HIGH
You should now see the embedded tracing messages.
2. Turn on debugging messages at the most verbose level:
> make verbosity=UVM_DEBUG
3. If you have free time, look through the source files in
$VCS_HOME/etc/uvm. You will find that reading through each of the
source code will give you a lot of insights into how each class and macro
works.
You are done with Lab 1!
UVM Verification Environment Lab 1-9
SystemVerilog UVM 1.1 Workshop
Lab 1 Answers / Solutions
Answers / Solutions
test.sv Solution:
program automatic test;
import uvm_pkg::*;
`include "test_collection.sv"
initial begin
$timeformat(-9, 1, "ns", 10);
run_test();
end
endprogram
test_collection.sv Solution:
class test_base extends uvm_test;
`uvm_component_utils(test_base)
router_env env;
function new(string name, uvm_component parent);
super.new(name, parent);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
endfunction: new
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
env = router_env::type_id::create("env", this);
endfunction: build_phase
virtual function void start_of_simulation_phase(uvm_phase phase);
super.start_of_simulation_phase(phase);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
uvm_top.print_topology();
factory.print();
endfunction: start_of_simulation_phase
endclass: test_base
driver.sv Solution:
class driver extends uvm_driver #(packet);
`uvm_component_utils(driver)
function new(string name, uvm_component parent);
super.new(name, parent);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
endfunction: new
virtual task run_phase(uvm_phase phase);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
forever begin
seq_item_port.get_next_item(req);
req.print();
seq_item_port.item_done();
end
endtask: run_phase
endclass: driver
Lab 1-10 UVM Verification Environment
SystemVerilog UVM 1.1 Workshop
Answers / Solutions Lab 1
packet.sv Solution:
class packet extends uvm_sequence_item;
rand bit [3:0] sa, da;
rand bit [7:0] payload[$];
`uvm_object_utils_begin(packet)
`uvm_field_int(sa, UVM_ALL_ON | UVM_NOCOMPARE)
`uvm_field_int(da, UVM_ALL_ON)
`uvm_field_queue_int(payload, UVM_ALL_ON)
`uvm_object_utils_end
constraint valid {
payload.size inside {[1:10]};
}
function new(string name = "packet");
super.new(name);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
endfunction: new
endclass: packet
input_agent.sv Solution:
typedef uvm_sequencer #(packet) packet_sequencer;
class input_agent extends uvm_agent;
packet_sequencer seqr;
driver drv;
`uvm_component_utils(input_agent)
function new(string name, uvm_component parent);
super.new(name, parent);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
endfunction: new
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
seqr = packet_sequencer::type_id::create("seqr", this);
drv = driver::type_id::create("drv", this);
endfunction: build_phase
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
drv.seq_item_port.connect(seqr.seq_item_export);
endfunction: connect_phase
endclass: input_agent
UVM Verification Environment Lab 1-11
SystemVerilog UVM 1.1 Workshop
Lab 1 Answers / Solutions
router_env.sv Solution:
class router_env extends uvm_env;
input_agent i_agent;
`uvm_component_utils(router_env)
function new(string name, uvm_component parent);
super.new(name, parent);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
endfunction: new
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
i_agent = input_agent::type_id::create("i_agent", this);
uvm_config_db #(uvm_object_wrapper)::set(this, "i_agent.seqr.main_phase",
"default_sequence", packet_sequence::get_type());
endfunction: build_phase
endclass: router_env
packet_sequence.sv Solution:
class packet_sequence extends uvm_sequence #(packet);
`uvm_object_utils(packet_sequence)
function new(string name = "packet_sequence");
super.new(name);
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
endfunction: new
task body();
`uvm_info("TRACE", $sformatf("%m"), UVM_HIGH);
if (starting_phase != null) begin
starting_phase.raise_objection(this);
end
repeat(10) begin
`uvm_do(req);
end
if (starting_phase != null) begin
starting_phase.drop_objection(this);
end
endtask: body
endclass: packet_sequence
Lab 1-12 UVM Verification Environment
SystemVerilog UVM 1.1 Workshop