This post answers the following question “How the typical sequencer to sequence coonection works?!”
An example Link to heading
- Create sequencer class handle from vanilla
uvm_sequencer
uvm_sequencer #(foo_req, foo_rsp) sqr;
- Connect it to driver port in connect phase
drv.seq_item_port.connect(sqr.seq_item_export);
- Define
uvm_sequence
withbody
class foo_sequence extends uvm_sequence#(foo_seq_item);
virtual task body();
start_item(item);
// Create the seq item
...
finish_item(item);
endtask
endclass
- Call the sequence with sequencer instance.
seq.start(sqr, null);
- Finally the driver can use
get_next_item
to get the sequence_item
seq_item_port.get_next_item(req);
// Do something with req
seq_item_port.item_done();
Following seq.start down the rabbit hole Link to heading
let’s start with uvm_sequence
and seq.start
, it turns out it’s very lean class as most logic is define in uvm_sequence_base
in src/seq/uvm_sequence_base.svh
uvm_sequence_base
is a sub class of uvm_sequence_item
with sequence phases to be overridden.
anyway, start
eventually calls body
. note that body
is a virtual task that issues a warning if not overridden.
virtual task body();
uvm_report_warning("uvm_sequence_base", "Body definition undefined");
return;
endtask
How the sequencer and sequence are linked? body to get_next_item. Link to heading
after creating the item, body
calls finish_item
to pass over control to sequencer. finish_item
is defined in src/seq/uvm_sequence_base.svh
, the task finish_item calls send_request
virtual task finish_item (uvm_sequence_item item,
int set_priority = -1);
...
sequencer.send_request(this, item);
...
endtask
sequencer.send_request
is defined in src/seq/uvm_sequence.svh
. which uses m_sequencer
to call m_sequencer.send_sequest
function void send_request(uvm_sequence_item request, bit rerandomize = 0);
REQ m_request;
...
m_sequencer.send_request(this, m_request, rerandomize);
endfunction
m_sequencer.send_request
is called from sequencer is defined at src/seq/uvm_sequencer_param_base.svh
.
and it pushes the item into tlm fifo m_req_fifo
if (m_req_fifo.try_put(param_t) != 1) begin
uvm_report_fatal(get_full_name(), "Concurrent calls to get_next_item() not supported. Consider using a semaphore to ensure that concurrent processes take turns in the driver", UVM_NONE);
end
at this point, we need to jump to the other side seq_item_port.get_next_item(req);
then returns the req in the m_req_fifo
.
task uvm_sequencer::get_next_item(output REQ t);
REQ req_item;
...
m_req_fifo.peek(t);
endtask