A sequencer generates data transactions as class objects and sends it to the Driver for execution. It is recommended to extend
uvm_sequencer base class since it contains all of the functionality required to allow a sequence to communicate with a driver. The base class is parameterized by the request and response item types that can be handled by the sequencer.
By default, the response type is the same as the request type, and if required to be different, you may specify it as the second parameter during instantiation. Unless you have additional ports to be included, you should directly instantiate it as a
uvm_sequencer parameterized to the required data item.
// class uvm_sequencer #(type REQ = uvm_sequence_item, RSP = REQ) extends uvm_sequencer_param_base #(REQ, RSP); uvm_sequencer #(my_data, data_rsp) seqr0; // with RSP uvm_sequencer #(my_data) seqr0; // without RSP
Generation of objects within the sequencer is very limited in terms of flexibility and re-usability. We'll see how this limitation can be overcome via sequences.
It is not really required to create a custom sequencer to execute every sequence or for every agent. But you can create your version of the UVM sequencer with additional features and create instances of it throughout the testbench.
class my_sequencer extends uvm_sequencer; `uvm_component_utils (my_sequencer) function new (string name="m_sequencer", uvm_component parent); super.new (name, parent); endfunction endclass