uvm_driver
is a child of uvm_component
that has a TLM port to communicate with the sequencer. The driver is a parameterized class with the type of request and response sequence items. This allows the driver to send back a different sequence_item type back to the sequencer as the response. However, most drivers use a response object of the same type as the request sequence item.
The uvm_driver
gets request sequence items (REQ) from the sequencer FIFO using a handshake mechanism and optionally returns a response sequence item (RSP) back to the sequencer response FIFO. There are primarily two ways for the driver to get a sequence item from the sequencer. In this article, we'll look at an example that uses the first style.

Using get_next_item
method in a driver
In this case, the driver requests for a sequence item from the sequencer using the get_next_item
method through the seq_item_port
TLM handle. Since the implementation of this port is defined in the sequencer, the function call makes the sequencer to pop an item from its internal FIFO and provide it to the driver via the argument provided in get_next_item
method.
class my_driver extends uvm_driver #(my_data);
`uvm_component_utils (my_driver)
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
// 1. This task will get an item from the sequencer using get_next_item()
`uvm_info ("DRIVER", $sformatf ("Waiting for data from sequencer"), UVM_MEDIUM)
seq_item_port.get_next_item(req);
// 2. For simplicity, lets just assume the driver drives the received packet
// during this time and consumes 20ns to complete driving the transaction
`uvm_info ("DRIVER", $sformatf ("Start driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
#20;
// 3. After driver has finished the transaction, it has to let the sequencer know
// by calling item_done()
`uvm_info ("DRIVER", $sformatf ("Finish driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
seq_item_port.item_done();
endtask
Once driver gets the next item, it can drive the data in the received sequence item to the DUT via a virtual interface handle. After the driver has finished driving the item, it has to let the sequencer know that the process has finished using item_done
method.
How does the sequencer get these sequence items ?
A uvm_sequence
is started on a sequencer which pushes the sequence item onto the sequencer's FIFO.
class my_sequence extends uvm_sequence;
`uvm_object_utils (my_sequence)
virtual task body();
// 1. Create an item the connected sequencer can accept
my_data tx = my_data::type_id::create("tx");
`uvm_info ("SEQ", $sformatf("About to call start_item"), UVM_MEDIUM)
// 2. Call the start_item() task which will send this object to the driver
start_item(tx);
`uvm_info ("SEQ", $sformatf("start_item() fn call done"), UVM_MEDIUM)
// 3. Because the class handle passed to the driver points to the same object, we
// can do late randomization
tx.randomize();
`uvm_info ("SEQ", $sformatf("tx randomized with addr=0x%0h data=0x%0h", tx.addr, tx.data), UVM_MEDIUM)
// 4. Call finish_item method so that the sequence waits until the driver lets the
// sequencer know that this item has finished
finish_item(tx);
`uvm_info ("SEQ", $sformatf("finish_item() fn call done"), UVM_MEDIUM)
endtask
endclass
Example
To illustrate how the get
and put
method calls between driver and sequencer work, let us build a simple testbench structure like the one shown below.

Define a sequence item
To keep things simple, let us define a transaction object class that will become the sequence item used for sequencer-driver communication. Assume that this sequence item contains two variables called addr and data.
// Note that this class is dervide from "uvm_sequence_item"
class my_data extends uvm_sequence_item;
rand bit [7:0] data;
rand bit [7:0] addr;
// Rest of the class contents come here ...
endclass
Define the driver
The uvm_driver
is parameterized to accept a class object of the type my_data and the driver is expected to unpack this class object and drive the signals appropriately to the DUT via the interface.
class my_driver extends uvm_driver #(my_data);
`uvm_component_utils (my_driver)
// Other parts of the driver code if they exist
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
// 1. Get the next available item from the sequencer. If none exists, then wait until
// next item is available -> this is blocking in nature
`uvm_info ("DRIVER", $sformatf ("Waiting for data from sequencer"), UVM_MEDIUM)
seq_item_port.get_next_item(req);
// 2. Let us assume that the driver actively does the pin wiggling of the DUT during this time and
// consider it takes 20ns
`uvm_info ("DRIVER", $sformatf ("Start driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
#20;
// 3. After the driver has driven all data to the DUT, it should let the sequencer know that it finished
// driving the transaction by calling "item_done". Optionally the response packet can be passed along with
// the item_done method call and it will be placed in the sequencer's response FIFO
`uvm_info ("DRIVER", $sformatf ("Finish driving tx addr=0x%0h data=0x%0h", req.addr, req.data), UVM_MEDIUM)
seq_item_port.item_done();
endtask
endclass
Define the sequence
A sequence item is always started using the start_item
and finish_item
methods.
class my_sequence extends uvm_sequence #(my_data);
// Rest of the sequence code
virtual task body();
// 1. Create a sequence item of the given type
my_data tx = my_data::type_id::create("tx");
`uvm_info ("SEQ", $sformatf("About to call start_item"), UVM_MEDIUM)
// 2. Start the item on the sequencer which will send this to the driver
start_item(tx);
`uvm_info ("SEQ", $sformatf("start_item() fn call done"), UVM_MEDIUM)
// 3. Do some late randomization to create a different content in this transaction object
tx.randomize();
`uvm_info ("SEQ", $sformatf("tx randomized with addr=0x%0h data=0x%0h", tx.addr, tx.data), UVM_MEDIUM)
// 4. Call finish_item to let driver continue driving the transaction object or sequence item
finish_item(tx);
`uvm_info ("SEQ", $sformatf("finish_item() fn call done"), UVM_MEDIUM)
endtask
endclass
Define the test class
To keep things simple, let us directly create instances of the driver and sequencer inside the test class.
Driver and Sequencer should be instantiated inside an agent. An agent is instantiated in an environment and the the environment in turn should be created in the test.
class base_test extends uvm_test;
// Rest of the test code is here
// The sequencer is parameterized to accept objects of type "my_data" only
my_driver m_drv0;
uvm_sequencer #(my_data) m_seqr0;
my_sequence m_seq;
// Build the sequencer and driver components
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
m_drv0 = my_driver::type_id::create ("m_drv0", this);
m_seqr0 = uvm_sequencer#(my_data)::type_id::create ("m_seqr0", this);
endfunction
// Connect the sequencer "export" to the driver's "port"
virtual function void connect_phase (uvm_phase phase);
super.connect_phase (phase);
m_drv0.seq_item_port.connect (m_seqr0.seq_item_export);
endfunction
// Start the sequence on the given sequencer
virtual task run_phase(uvm_phase phase);
m_seq = my_sequence::type_id::create("m_seq");
phase.raise_objection(this);
m_seq.start(m_seqr0);
phase.drop_objection(this);
endtask
endclass
UVM_INFO @ 0: reporter [RNTST] Running test base_test... UVM_INFO testbench.sv(33) @ 0: uvm_test_top.m_top_env.m_drv0 [DRIVER] Waiting for data from sequencer UVM_INFO testbench.sv(71) @ 0: uvm_test_top.m_top_env.m_seqr0@@m_seq [SEQ] About to call start_item UVM_INFO testbench.sv(73) @ 0: uvm_test_top.m_top_env.m_seqr0@@m_seq [SEQ] start_item() fn call done UVM_INFO testbench.sv(75) @ 0: uvm_test_top.m_top_env.m_seqr0@@m_seq [SEQ] tx randomized with addr=0x8f data=0x1d UVM_INFO testbench.sv(35) @ 0: uvm_test_top.m_top_env.m_drv0 [DRIVER] Start driving tx addr=0x8f data=0x1d UVM_INFO testbench.sv(37) @ 20: uvm_test_top.m_top_env.m_drv0 [DRIVER] Finish driving tx addr=0x8f data=0x1d UVM_INFO testbench.sv(77) @ 20: uvm_test_top.m_top_env.m_seqr0@@m_seq [SEQ] finish_item() fn call done UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 20: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 20: reporter [UVM/REPORT/SERVER] --- UVM Report Summary ---