We discussed sequece_item, sequence, sequencer, and driver independently. In this section, we will discuss how they talk with each other and provide sequence items from sequence to driver via the sequencer. Before you start reading this section, make sure you are aware of all methods used in sequencer and driver. (Refer: UVM Sequencer and UVM Driver).
Sequencer-Driver Connections
The sequencer and driver communicate with each other using a bidirectional TLM interface to transfer REQ and RSP sequence items.
The driver has uvm_seq_item_pull_port which is connected with uvm_seq_item_pull_export of the associated sequencer. This TLM interface provides a facility to use implemented API to retrieve REQ items and turn RSP items.
Note:
Both uvm_seq_item_pull_port and uvm_seq_item_pull_export are parameterized classes with REQ and RSP sequence items.
The TLM connection between driver and sequencer is one-to-one. It means neither multiple sequencers are connected to a single driver nor multiple drivers connected to a single sequencer.
Connections: The driver and sequencers are connected in the connect_phase of the UVM agent.
<driver_inst>.seq_item_port.connect(<sequencer_inst>.seq_item_export);
Where,
The seq_item_port and seq_item_export are an instance handle for uvm_seq_item_pull_port and uvm_seq_item_pull_export respectively.
Sequence-Sequencer-Driver
communication Approaches
Based on the varieties of methods available with sequence and driver, all combinations are explained further.
Approach A: Using get_next_item and item_done methods in the driver
Approach B: Using get and put methods in driver
A. Using get_next_item and item_done methods in the driver
Without RSP packet
Create a sequence item and register in the factory using the create_item function call.
The wait_for_grant issues request to the sequencer and wait for the grant from the sequencer. It returns when the sequencer has granted the sequence.
Randomize the sequence item and send it to the sequencer using send_request call. There should not be any simulation time delay between wait_for_grant and send_request method call. The sequencer forwards the sequence item to the driver with the help of REQ FIFO. This unblocks the get_next_item() call and the driver receives the sequence item.
The wait_for_item_done() call from sequence gets blocked until the driver responds back.
In the meantime, the driver drives the sequence item to the DUT using a virtual interface handle. Once it is completed, the item_done method is called. This unblocks the wait_for_item_done method from the sequence.
If a response has to be sent from the driver to the sequence, item_done(RSP) is called with the RSP item as an argument. The RSP item is communicated to the sequence by a sequencer with help of RSP FIFO. It is important to call the get_response method to get the response. This step is optional and not required if the RSP item is not sent by the DUT.
// Driver Code
class driver extends uvm_driver#(seq_item);
`uvm_component_utils(driver)
function new(string name = "driver", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task run_phase (uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_type_name(), "After get_next_item call", UVM_LOW);
#50; // Driving delay. Assuming time taken to drive RTL signals
seq_item_port.item_done();
`uvm_info(get_type_name(), "After item_done call", UVM_LOW);
end
endtask
endclass
// Sequence Code
class base_seq extends uvm_sequence #(seq_item);
seq_item req;
`uvm_object_utils(base_seq)
function new (string name = "base_seq");
super.new(name);
endfunction
task body();
`uvm_info(get_type_name(), "Base seq: Inside Body", UVM_LOW);
//req = seq_item::type_id::create("req");
// or
$cast(req, create_item(seq_item::get_type(), m_sequencer, "req"));
wait_for_grant();
assert(req.randomize());
send_request(req);
`uvm_info(get_type_name(), "Before wait_for_item_done", UVM_LOW);
wait_for_item_done();
`uvm_info(get_type_name(), "After wait_for_item_done", UVM_LOW);
endtask
endclass
UVM_INFO testbench.sv(21) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Base seq: Inside Body
UVM_INFO testbench.sv(28) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Before wait_for_item_done
UVM_INFO driver.sv(15) @ 0: uvm_test_top.env_o.agt.drv [driver] After get_next_item call
UVM_INFO driver.sv(19) @ 50: uvm_test_top.env_o.agt.drv [driver] After item_done call
UVM_INFO testbench.sv(30) @ 50: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] After wait_for_item_done
With RSP packet
When the driver sends the RSP item to the sequence.
// Driver Code
class driver extends uvm_driver#(seq_item);
`uvm_component_utils(driver)
function new(string name = "driver", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task run_phase (uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_type_name(), "After get_next_item call", UVM_LOW);
#50; // Driving delay. Assuming time taken to drive RTL signals
req.rsp_b = 1;
seq_item_port.item_done(req);
`uvm_info(get_type_name(), "After item_done call", UVM_LOW);
end
endtask
endclass
// Sequence Code
class base_seq extends uvm_sequence #(seq_item);
seq_item req;
`uvm_object_utils(base_seq)
function new (string name = "base_seq");
super.new(name);
endfunction
task body();
`uvm_info(get_type_name(), "Base seq: Inside Body", UVM_LOW);
//req = seq_item::type_id::create("req");
// or
$cast(req, create_item(seq_item::get_type(), m_sequencer, "req"));
wait_for_grant();
assert(req.randomize());
send_request(req);
`uvm_info(get_type_name(), "Before wait_for_item_done", UVM_LOW);
wait_for_item_done();
`uvm_info(get_type_name(), "After wait_for_item_done", UVM_LOW);
get_response(req);
`uvm_info(get_type_name(), $sformatf("After get_response: rsp_b = %0d", req.rsp_b), UVM_LOW);
endtask
endclass
UVM_INFO testbench.sv(21) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Base seq: Inside Body
UVM_INFO testbench.sv(28) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Before wait_for_item_done
UVM_INFO driver.sv(15) @ 0: uvm_test_top.env_o.agt.drv [driver] After get_next_item call
UVM_INFO driver.sv(20) @ 50: uvm_test_top.env_o.agt.drv [driver] After item_done call
UVM_INFO testbench.sv(30) @ 50: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] After wait_for_item_done
UVM_INFO testbench.sv(32) @ 50: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] After get_response: rsp_b = 1
B. Using get and put methods in driver
Create a sequence item and register in the factory using the create_item function call.
The wait_for_grant issues the request to the sequencer and wait for the grant from the sequencer. It returns when the sequencer has granted the sequence.
Randomize the sequence item and send it to the sequencer using send_request call. There should not be any simulation time delay between wait_for_grant and send_request method call. The sequencer forwards the sequence item to the driver with the help of REQ FIFO. This unblocks the get() call and the driver receives the sequence item.
The wait_for_item_done() call from the sequence gets blocked until the driver calls the get method.
Once the get method is called, the wait_for_item_done() call from sequence gets unblocked immediately without caring about driving the virtual interface.
The get_response call is necessary to call that completes the communication. The get_response method is blocked until the driver calls put(RSP).
In the meantime, the driver drives the sequence item to the DUT using a virtual interface handle. Once it is completed, the put(RSP) method is called. This unblocks the get_response method from the sequence. The RSP item is communicated to the sequence by a sequencer with help of RSP FIFO.
// Driver Code
class driver extends uvm_driver#(seq_item);
`uvm_component_utils(driver)
function new(string name = "driver", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task run_phase (uvm_phase phase);
forever begin
seq_item_port.get(req);
`uvm_info(get_type_name(), "After get call", UVM_LOW);
#50; // Driving delay. Assuming time taken to drive RTL signals
req.rsp_b = 1;
seq_item_port.put(req);
`uvm_info(get_type_name(), "After put call", UVM_LOW);
end
endtask
endclass
// Sequence Code
class base_seq extends uvm_sequence #(seq_item);
seq_item req;
`uvm_object_utils(base_seq)
function new (string name = "base_seq");
super.new(name);
endfunction
task body();
`uvm_info(get_type_name(), "Base seq: Inside Body", UVM_LOW);
//req = seq_item::type_id::create("req");
// or
$cast(req, create_item(seq_item::get_type(), m_sequencer, "req"));
wait_for_grant();
assert(req.randomize());
send_request(req);
`uvm_info(get_type_name(), "Before wait_for_item_done call", UVM_LOW);
wait_for_item_done();
`uvm_info(get_type_name(), "After wait_for_item_done call", UVM_LOW);
get_response(req);
`uvm_info(get_type_name(), $sformatf("After get_response: rsp_b = %0d", req.rsp_b), UVM_LOW);
endtask
endclass
UVM_INFO testbench.sv(21) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Base seq: Inside Body
UVM_INFO testbench.sv(28) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Before wait_for_item_done call
UVM_INFO driver.sv(15) @ 0: uvm_test_top.env_o.agt.drv [driver] After get call
UVM_INFO testbench.sv(30) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] After wait_for_item_done call
UVM_INFO driver.sv(20) @ 50: uvm_test_top.env_o.agt.drv [driver] After put call
UVM_INFO testbench.sv(32) @ 50: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] After get_response: rsp_b = 1
另外,由于微信群已经超过200人,添加小编的微信,拉你进入WX学习群。