In the previous session, we had a simple testbench structure with only test and environment.That was just enough to utilize a UVM component, and print "Hello UVM". But, in a normal testbench we would have a data element that gets routed through different verification components. So, in this part, we will create a "data" packet object and send it to the "driver".

As you might know already, data packet encapsulates a lot of information into a single entity - a class object. We may not need all the information in the data object to drive signals to DUT. The driver obtains the data packet and extracts the required information and converts it into the pin-wiggles of DUT interface.


You can download/clone uvm-201 from repository.


We have added two more elements to the environment

  • Data Object
  • Driver

data and driver uvm-201

Let us discuss on the new additions


A data packet should be extended from uvm_sequence_code so that it can interact with a uvm_sequencer. Since our design element is a simple memory element, we only need address and data to be captured inside the data class. We also have a custom function to display data values. Note that this class has been registered with the factory as `uvm_object_utils because it is a derivative of uvm_sequence_item (another derivative of uvm_object).

class my_data extends uvm_sequence_item;
	`uvm_object_utils (my_data)
	rand bit [7:0]   data;
	rand bit [7:0]   addr;

	constraint c_addr { addr > 0; addr < 8;}
 	virtual function void display ();
		`uvm_info (get_type_name (), $sformatf ("addr = 0x%0h, data = 0x%0h", addr, data), UVM_MEDIUM);


This is the component responsible for driving data values to the DUT using the interface. Data is usually generated by another component called generator, but for our purposes in this session, we have data being generated inside the driver. We have already seen the following code in the previous session.

class my_driver extends uvm_driver;
	`uvm_component_utils (my_driver)

	int unsigned      n_times;
	my_data           data_obj;
	virtual  dut_if   vif;
	function new (string name, uvm_component parent); (name, parent);

	virtual function void build_phase (uvm_phase phase);
		super.build_phase (phase);
		if (! uvm_config_db #(virtual dut_if) :: get (this, "", "vif", vif)) begin
			`uvm_fatal (get_type_name (), "Didn't get handle to virtual interface dut_if")

Next, we'll write the reset_phase, so that reset can be applied to the DUT in this phase.

    task reset_phase (uvm_phase phase);
       super.reset_phase (phase);
       `uvm_info (get_type_name (), $sformatf ("Applying initial reset"), UVM_MEDIUM)
       this.vif.rstn = 0;
       repeat (20) @ (posedge vif.clk);
       this.vif.rstn = 1;
       `uvm_info (get_type_name (), $sformatf ("DUT is now out of reset"), UVM_MEDIUM)

Now, we'll focus on how data should be generated and how it can be driven to the DUT. Note, that we already have a handle to the DUT interface that was obtained from top-level module during the build_phase. So, all we have to do now is generate and drive data.

	task main_phase (uvm_phase phase);
		super.main_phase (phase);
		phase.raise_objection (phase);
		`uvm_info (get_type_name (), $sformatf ("Inside Main phase"), UVM_MEDIUM)

		// Let's create a data object, randomize it and send it to the DUT
		n_times = 5;
		repeat (n_times) begin
			`uvm_info (get_type_name (), $sformatf ("Generate and randomize data packet"), UVM_DEBUG)
			data_obj = my_data::type_id::create ("data_obj", this);
			assert(data_obj.randomize ());
			@(posedge vif.clk);
			`uvm_info (get_type_name (), $sformatf ("Drive data packet to DUT"), UVM_DEBUG)
			this.vif.en    = 1;
			this.vif.wr    = 1;
 			this.vif.addr  = data_obj.addr;
			this.vif.wdata =;
 			data_obj.display ();
		phase.drop_objection (phase);

raise_objection and drop_objection are methods of the phase object that allows the testbench to know about the current status of each component. So, if a component is actively working during the run_phase, it has to raise an objection. Only when all the components have dropped their objection will the simulation end. If you have forgetten to drop objection on a component, there are chances that your simulation will keep running.

Simulation Output

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               -     @2615
  m_top_env          my_env                  -     @204
    m_drv0           my_driver               -     @198
      rsp_port       uvm_analysis_port       -     @2814
      seq_item_port  uvm_seq_item_pull_port  -     @2763

UVM_INFO ./tb/ @ 0: uvm_test_top.m_top_env.m_drv0 [my_driver] Applying initial reset
UVM_INFO ./tb/ @ 0: uvm_test_top.m_top_env.m_drv0 [my_driver] Inside Main phase
UVM_INFO ./tb/ @ 10000: reporter@@data_obj [my_data] addr = 0x6, data = 0x15
UVM_INFO ./tb/ @ 30000: reporter@@data_obj [my_data] addr = 0x5, data = 0xa8
UVM_INFO ./tb/ @ 50000: reporter@@data_obj [my_data] addr = 0x3, data = 0xcf
UVM_INFO ./tb/ @ 70000: reporter@@data_obj [my_data] addr = 0x2, data = 0xaa
UVM_INFO ./tb/ @ 90000: reporter@@data_obj [my_data] addr = 0x5, data = 0x4c
UVM_INFO ./tb/ @ 90000: uvm_test_top.m_top_env.m_drv0 [my_driver] Finished DUT simulation

--- 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 :   10
UVM_ERROR :    0
UVM_FATAL :    0
** Report counts by id
[RNTST]     1
[UVMTOP]     1
[my_data]     5
[my_driver]     3
Simulation complete via $finish(1) at time 90 NS + 83

Go to the next step Sequencer and Monitor