UVM Driver and Sequencer Handshaking
UVM Driver and Sequencer Handshaking
Step 1 - Creation
The sequence_item is derived from uvm_object and should be created via the
factory:
Using the factory creation method allows the sequence_item to be overridden with a
sequence_item of a derived type if required.
Step 3 - Set
The sequence_item is prepared for use, usually through randomization, but it may
also be initialised by setting properties directly.
Step 4 - Go - finish_item()
The finish_item() call is made, which blocks until the driver has completed its side of
the transfer protocol for the item. No simulation time should be consumed between
start_item() and finish_item().
Late Randomization
In the sequence_item flow above, steps 2 and 3 could be done in any order.
However, leaving the randomization of the sequence_item until just before the
finish_item() method call has the potential to allow the sequence_item to be
randomized according to conditions true at the time of generation. This is sometimes
referred to as late randomization.
The alternative approach is to generate the sequence_item before the start_item()
call, in this case the item is generated before it is necessarily clearhow it is going to
be used.
In previous generation verification methodologies, such as Specman and the AVM,
generation was done at the beginning of the simulation and a stream of pre-prepared
sequence_items was sent across to the driver. With late randomization,
sequence_items are generated just in time and on demand.
get_next_item()
This method blocks until a REQ sequence_item is available in the sequencers
request FIFO and then returns with a pointer to the REQ object.
The get_next_item() call implements half of the driver-sequencer protocol
handshake, and it must be followed by an item_done() call which completes the
handshake. Making another get_next_item() call before issuing an item_done() call
will result in a protocol error and driver-sequencer deadlock.
try_next_item()
This is a non-blocking variant of the get_next_item() method. It will return a null
pointer if there is no REQ sequence_item available in the sequencers request FIFO.
However, if there is a REQ sequence_item available it will complete the first half of
the driver-sequencer handshake and must be followed by an item_done() call to
complete the handshake.
item_done()
The non-blocking item_done() method completes the driver-sequencer handshake
and it should be called after a get_next_item() or a successful try_next_item() call.
If it is passed no argument or a null pointer it will complete the handshake without
placing anything in the sequencer's response FIFO. If it is passed a pointer to a RSP
sequence_item as an argument, then that pointer will be placed in the sequencer's
response FIFO.
The get_next_item() method initiate the sequencer arbitration process, which results
in a sequence_item being returned from the active sequence which has selected.
This means that the driver is effectively pulling sequence_items from the active
sequences as it needs them.
// Driver parameterised with the same sequence_item for request & response
// response defaults to request
class my_driver extends uvm_driver #(my_sequence_item);
my_interface vif;
.....
task run_phase(uvm_phase phase);
my_sequence_item req_item;
forever
begin
seq_item_port.get_next_item(req_item); // Blocking call returning the next
transaction
@(posedge vif.clk);
vif.addr = req_item.address; // vif is the drivers Virtual Interface
//
// etc
//
// End of bus cycle
if(req_item.read_or_write == READ)
begin // Assign response data to the req_item fields
req_item.rdata = vif.rdata;
end
req_item.resp = vif.error; // Assign response to the req_item response field
seq_item_port.item_done(); // Signal to the sequence that the driver has finished
with the item
end
endtask: run
endclass: my_driver
// Sequencer parameterised with the same sequence item for request & response
class my_sequencer extends uvm_sequencer #(my_sequence_item);
.....
endclass: my_sequencer
//Sequence, Sequencer and Driver parameterised with the different sequence_item for
request & response
my_sequence extends uvm_sequence #(my_sequence_item1, (my_sequence_item2); // type of req
= my_sequence_item1, type of rsp = my_sequence_item2
.....
task body();
// Step 1 - Creation
req = my_sequence_item1::type_id::create("req"); // type of req = my_sequence_item1
// Step 2 - Ready - start_item()
start_item(req);
// Step 3 - Set
if(!req.randomize() with {address inside {[0:32'h4FFF_FFFF]};})
begin
`uvm_error("body", "randomization failure for req")
end
// Step 4 - Go - finish_item()
finish_item(req);
// Step 5 - Response - get_response()
get_response(rsp); // type of rsp = my_sequence_item2
endtask: body
endclass: my_sequence