2. Sequencer
• Generates stimulus data and passes it to a driver for execution.
• The sequencer controls the flow of request and response sequence items
between sequences and the driver
• Uses uvm_sequencer base class, which is parameterized by the request
and response item types.
• The uvm_sequencer base class contains all of the base functionality
required to allow a sequence to communicate with a driver.
class sequencer extends uvm_sequencer#(seqss_item);
`uvm_sequencer_utils(sequencer)
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
endclass
3. Driver
• The driver’s role is to drive data items to the bus following the interface
protocol.
• The UVM Class Library provides the uvm_driver base class, from which all
driver classes should be extended.
• The driver has a TLM port through which it communicates with the
sequencer.
• The driver implement the run phase define its operation.
• To create a driver:
• a) Derive from the uvm_driver base class.
• b) If desired, add UVM infrastructure macros for class properties to implement
utilities for printing, copying, comparing, and so on.
• c) Obtain the next data item from the sequencer and execute it.
• d) Declare a virtual interface in the driver to connect the driver to the DUT.
5. Connecting the Driver and Sequencer
• The driver and the sequencer are connected via TLM, with the driver’s
seq_item_port connected to the sequencer’s seq_item_export.
• The sequencer produces data items to provide via the export. The driver
consumes data items through its seq_item_port and, optionally, provides
responses.
function void mas_agt::connect_phase(uvm_phase phase);
if(m_cfg.is_active == UVM_ACTIVE) begin
m_dri.seq_item_port.connect(m_seqr.seq_item_export); end
endfunction
•
6. Basic Sequencer and Driver Interaction
• Basic interaction between the driver and the sequencer is done using the tasks
get_next_item() and item_done().
• the driver uses get_next_item() to fetch the next randomized item to be sent.
• After sending it to the DUT, the driver signals the sequencer that the item was
processed using item_done().
forever
begin
get_next_item(req);
// Send item following the protocol.
item_done();
end
get_next_item() is blocking until an item is provided by the sequences running on that sequencer.
7. Try_next_item
• Try_next_item will return in the same simulation step if no data items are
available for execution.
• we can use this task to have the driver execute some idle transactions, such as
when the DUT has to be stimulated when there are no meaningful data to
transmit.
8. Sending Processed Data back to the Sequencer
• In some sequences, a generated value depends on the response to previously
generated data.
• So the driver needs to return the processed response back to the sequencer.
• Do this using the optional argument to item_done(),
seq_item_port.item_done(rsp);
• or using the put_response() method,
seq_item_port.put_response(rsp);
• or using the built-in analysis port in uvm_driver.
rsp_port.write(rsp);
• Before providing the response, the response’s sequence and transaction id must
be set to correspond to the request transaction using rsp.set_id_info(req).
• put_response() is a blocking method, so the sequence must do a corresponding
get_response(rsp).
9. Using TLM-Based Drivers
• The seq_item_port, which is built into uvm_driver, is a bidirectional port.
• It also includes the standard TLM methods get() and peek() for requesting an item
from the sequencer, and put() to provide a response.
• peek() is a blocking method, so the driver may block waiting for an item to be
returned.
peek(req); // Pause sequencer operation while the driver operates on the transaction.
• The get() operation notifies the sequencer to proceed to the next transaction. It
returns the same transaction as the peek(), so the transaction may be ignored.
get(req);//Allow sequencer to proceed immediately upon driver receiving transaction.
• To provide a response using the blocking_slave_port, the driver would call:
seq_item_port.put(rsp);
• The response may also be sent back using an analysis_port as well.
10. Declaring User-Defined Sequences
• Sequences are made up of several data items, which together form an interesting
scenario or pattern of data.
• To create a user-defined sequence:
• a) Derive a sequence from the uvm_sequence base class and specify the request and
response item type parameters. In the example below, only the request type is specified,
simple_item. This will result in the response type also being of type simple_item.
• b) Use the `uvm_object_utils macro to register the sequence type with the factory.
• c) If the sequence requires access to the derived type-specific functionality of its associated
sequencer, add code or use the ‘uvm_declare_p_sequencer macro to declare and set the
desired sequencer pointer.
• d) Implement the sequence’s body task with the specific scenario you want the sequence to
execute. In the body task, you can execute data items and other sequences
12. Basic Flow for Sequences and Sequence Items
• To send a sequence item, the body() of a sequence needs to create() the item
(use the factory).,
• call start_item() on the item, optionally randomize the item, and call
finish_item() on the item.
• To send a subsequence, the body() of the parent sequence needs to create the
subsequence, optionally randomize it, and call start() for the subsequence.
• If the subsequence item has an associated response, the parent sequence can
call get_response().
14. Sequencer Arbitration
• Multiple sequences can interact concurrently with a driver connected to a single
interface.
• The sequencer supports an arbitration mechanism to ensure that at any point of
time only one sequence has access to the driver.
• The choice of which sequence can send a sequence_item is dependent on a user
selectable sequencer arbitration algorithm.
• There are five built-in sequencer arbitration mechanisms that are implemented in
UVM.
15. • SEQ_ARB_FIFO (Default if none specified).
• If this arbitration mode is specified, then the sequencer picks sequence items in a FIFO order
from all sequences running on the sequencer.
• For Example: if seq0, seq1,seq2 and seq3 are running on a sequencer, it will pick an item
from seq0 first, followed by seq1, followed by seq2 and then seq3 if available, and continue.
16. • SEQ_ARB_WEIGHTED:
• If this arbitration mode is selected, sequence items from the highest priority sequence are
always picked first until none available, then the sequence items from next priority sequence,
and so on. If two sequences have equal priority, then the items from them are picked in a
random order.
17. • SEQ_ARB_RANDOM:
• If this arbitration mode is selected, sequence items from different sequences are picked in a
random order by ignoring all priorities.
18. • SEQ_ARB_STRICT_FIFO:
• This is similar to SEQ_ARB_WEIGHTED except that if two sequences have same priority, then
the items from those sequences are picked in a FIFO order rather than in a random order.
19. • SEQ_ARB_STRICT_RANDOM:
This is similar to SEQ_ARB_RANDOM except that the priorities are NOT ignored. The items
are picked randomly from sequences with highest priority first followed by next and in that order.
• SEQ_ARB_USER:
This algorithm allows a user to define a custom algorithm for arbitration between
sequences. This is done by extending the uvm_sequencer class and overriding the
user_priority_arbitration() method.