Sequence-Driver-Sequencer communication in UVM
The communication between sequences, drivers, and sequencers is a fundamental aspect of UVM. It’s the core mechanism for generating and applying stimulus to the Design Under Verification (DUV). This communication flow ensures a well-coordinated and controlled verification process.
Key Components and Their Roles
- Sequence (
uvm_sequence
): Generates and controls the flow of transactions (sequence items). - Sequencer (
uvm_sequencer
): Manages the execution of sequences and coordinates the flow of sequence items. - Driver (
uvm_driver
): Drives the sequence items from the sequencer to the DUT through an interface.
Communication Flow Diagram
+-----------------------+
| Sequence |
| (uvm_sequence) |
+-----------------------+
|
v
+-----------------------+
| Sequencer |
| (uvm_sequencer) |
+-----------------------+
|
v
+-----------------------+
| Driver |
| (uvm_driver) |
+-----------------------+
|
v
+----------------------+
| DUT |
+----------------------+
- Sequence: Generates transactions (sequence items).
- Sequencer: Manages sequences and provides sequence items to the driver.
- Driver: Drives the sequence items onto the DUV interface.
The Communication Flow:
The communication follows a specific protocol:
-
Sequence Starts: A sequence is started on a particular sequencer using
seq.start(sequencer)
. -
Request for Item (Sequence to Sequencer): The sequence calls
start_item(item)
to request that the sequencer make the item available to the driver. This call is blocking, meaning the sequence waits until the driver is ready to accept the item. -
Item Creation (Sequencer): The sequencer creates a new sequence item (transaction) using the factory (
item_type::type_id::create()
). -
Item Randomization (Sequence): The sequence randomizes the created item using
item.randomize()
. -
Item Sending (Sequencer to Driver): The sequencer sends the randomized item to the driver through its
seq_item_export
using theput()
method. Thestart_item()
task within the sequence will return only after the item is sent to the driver. -
Item Reception (Driver): The driver retrieves the item from its
seq_item_port
using the blockingget_next_item(item)
method. The driver waits here until an item is available. -
Driving (Driver to DUV): The driver drives the data from the received item onto the DUV interface.
-
Item Completion (Driver to Sequence): After driving the transaction, the driver calls
item_done()
to signal completion to the sequence. Thefinish_item(item)
task within the sequence will return after the driver callsitem_done()
.
Diagram 1: Sequence, Sequencer, and Driver Interaction
+-----------+ start_item() +-----------+ put() +---------+ drive() +-----+
| Sequence |---------------------->| Sequencer |------------->| Driver |------------->| DUV |
+-----------+ (Blocking) +-----------+ +---------+ +-----+
| randomize()| | create() | | get_next_| | |
| finish_item()|<----------------------| | | item() | | |
+-----------+ (Blocking) +-----------+ +---------+ +-----+
1.Sequence to Sequencer:
- Start Sequence: The sequence generates sequence items and sends them to the sequencer.
- Start Item: The
start_item
task is called to notify the sequencer that a new item is ready. - Randomization: The sequence item can be randomized before being sent to the sequencer.
- Finish Item: The
finish_item
task is called after the item is processed.
class my_sequence extends uvm_sequence#(my_transaction);
`uvm_object_utils(my_sequence)
task body();
my_transaction tx;
tx = my_transaction::type_id::create("tx");
start_item(tx);
if (!tx.randomize())
`uvm_fatal("RAND_ERR", "Randomization failed");
finish_item(tx);
endtask
endclass
- Sequencer to Driver:
- Get Next Item: The driver calls
get_next_item
to retrieve the next sequence item from the sequencer. - Item Port Connection: The sequence item port of the driver is connected to the sequence item export of the sequencer.
class my_driver extends uvm_driver#(my_transaction); `uvm_component_utils(my_driver) virtual function void build_phase(uvm_phase phase); super.build_phase(phase); // Other build tasks endfunction task run_phase(uvm_phase phase); my_transaction tx; forever begin seq_item_port.get_next_item(tx); // Fetch transaction from sequencer drive(tx); // Drive the transaction to DUT seq_item_port.item_done(); // Indicate transaction completion end endtask virtual task drive(my_transaction tx); // Example driving logic // Drive transaction to DUT endtask endclass
- Get Next Item: The driver calls
- Driver to DUT:
- Drive Transaction: The driver takes the sequence item and drives it to the DUT through the interface.
- Synchronization: The driver ensures proper synchronization with the DUT’s clock or control signals.
class my_agent extends uvm_agent; `uvm_component_utils(my_agent) my_driver drv; my_sequencer seqr; function new(string name = "my_agent", uvm_component parent = null); super.new(name, parent); endfunction virtual function void build_phase(uvm_phase phase); super.build_phase(phase); drv = my_driver::type_id::create("drv", this); seqr = my_sequencer::type_id::create("seqr", this); endfunction virtual function void connect_phase(uvm_phase phase); super.connect_phase(phase); drv.seq_item_port.connect(seqr.seq_item_export); endfunction endclass
Example Code (Simplified):
// Sequence
class my_sequence extends uvm_sequence#(my_transaction);
`uvm_object_utils(my_sequence)
task body();
my_transaction trans;
trans = my_transaction::type_id::create("trans");
assert trans.randomize();
start_item(trans); // Blocking call - Sequence waits here
finish_item(trans); // Blocking call - Sequence waits here
endtask
endclass
// Driver
class my_driver extends uvm_driver#(my_transaction);
`uvm_component_utils(my_driver)
task run_phase(uvm_phase phase);
my_transaction trans;
forever begin
seq_item_port.get_next_item(trans); // Blocking call - Driver waits here
drive_transaction(trans);
seq_item_port.item_done();
end
endtask
// ... drive_transaction implementation ...
endclass
Diagram 2: Detailed Timing Diagram
Time -->
Sequence: | create | randomize | start_item (BLOCKING) -------------------------- finish_item (BLOCKING) |
^ ^
| |
Sequencer: | | put() |
v v
Driver: | | get_next_item (BLOCKING) - drive_transaction - item_done() |
Key Points:
start_item()
andget_next_item()
are blocking calls, ensuring synchronization between the sequence and the driver.- The
put()
method on the sequencer’s export sends the item to the driver. - The
item_done()
method signals completion of the transaction to the sequence. - This handshaking mechanism ensures that transactions are processed in the correct order and that no data is lost.