How does starting, running and randomizing a sequence item on a sequencer differ from doing it on a sequence?
Till now, I have been using sequence class to run item eg.
//Sequencer
import uvm_pkg::*;
`include "pkg.sv"
`include "uvm_macros.svh"
import my_pkg::*;
class pkt_sequence extends uvm_sequence#(Packet);
`uvm_object_utils(pkt_sequence)
function new(string name = "Sequence of Packet");
super.new(name);
endfunction
function void pre_randomize();
`uvm_info("PRE", "Starting randomization of Packets", UVM_MEDIUM);
endfunction
function void post_randomize();
`uvm_info("POST", "Finished randomization of Packets", UVM_MEDIUM);
endfucntion
task body();
Packet pkt;
pkt = Packet::type_id::create("Sequence of data", get_full_name());
start_item(pkt);
assert(pkt.randomize());
finish_item(pkt);
endtask
endclass
Now can I do the same thing from a sequencer instead? My sequencer is
//Sequencer
import uvm_pkg::*;
`include "uvm_macros.svh"
class pkt_sequencer extends uvm_sequencer#(Packet);
`uvm_component_utils(pkt_sequencer);
function new(string name="Sequencer", uvm_component parent);
super.new(name, parent);
endfunction
function build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
endclass
No, you can’t do this. The run_phase Task is intended to perform the run Control and not the behavior of a sequence.
You should have a look to the Basics of UVM.
In reply to chr_sue:
Actually, you could do the pk_sequence.start(this), assuming you constructed the pkt_sequence beforehand. But it is not the recommend way.
A Sequence is a functor - an object that represents a handle to a routine - the sequence’s body() task in the UVM. You typically want your test to start the top-level sequence, and have it orchestrate the flow of all the other sequences in your tests. A sequence can start other other sequences in parallel or in series, and sequences can send transaction items (uvm_sequence_item) to the driver. The driver only sees sequence_items. The sequenceRs job is arbitrate the order of sequence items that get sent to the driver, and manage the protocol between the active sequence and driver. The sequencer typically has no user code associated with it.
start_item() blocks until the driver executes
get()and the sequencer picks the sequence that responds to that request. The advantage placing code in-between
start_item()/finish_item() gives you the opportunity to perform any computation, including randomization, at the exact point in time the driver requests it. Then you can use the current state of the DUT or testbench to perform those computations. You may sometime see the term "*late-randomization*", but the principle apply to more than just randomization.