Tutorials

Learn More

The sequencer is a mediator who establishes a connection between sequence and driver. Ultimately, it passes transactions or sequence items to the driver so that they can be driven to the DUT.

sequencer connections

uvm_sequencer class hierarchy

uvm_sequencer hierarchy

uvm_sequencer class declaration:

class uvm_sequencer #( type REQ  = uvm_sequence_item, RSP = REQ ) extends uvm_sequencer_param_base #(REQ, RSP)

A user-defined sequencer is recommended to extend from the parameterized base class “uvm_sequencer” which is parameterized by request (REQ) and response (RSP) item types. Response item usage is optional. So, mostly sequencer class is extended from a base class that has only a REQ item.

class my_sequencer extends uvm_sequencer #(data_item, data_rsp); // with rsp
class my_sequencer extends uvm_sequencer #(data_item);           // without rsp

TLM (Transaction Level Modelling) interface is used by sequencer and driver to pass transactions. seq_item_export and seq_item_port TLM connect methods are defined in uvm_sequencer and uvm_driver class. The details are discussed in the sequence-driver-sequencer handshake section.

class my_sequencer extends uvm_sequencer #(data_item);
  `uvm_component_utils(my_sequencer)

  function new (string name, uvm_component parent);
    super.new(name, parent); 
  endfunction
endclass

m_sequencer and p_sequencer in UVM

m_sequencer

m_sequencer is a handle available by default in a sequence. m_sequencer has a type of uvm_sequencer_base.

Simply, it is a reference handle to the sequencer on which the sequence is running.

To run a sequence on the sequencer, the start() method is called. This start method needs to provide a sequencer handle.

Example:

base_seq.start(env_o.seqr);

Here, m_seqeuncer is a handle for base_seq that is set to env_o.seqr.

p_sequencer

All sequences have a m_sequencer handle but they do not have a p_sequencer handle.

p_sequencer is not defined automatically. It is defined using macro `uvm_declare_p_sequencer(sequencer_name). 

`define uvm_declare_p_sequencer(SEQUENCER) \
  SEQUENCER p_sequencer;\
  virtual function void m_set_p_sequencer();\
    super.m_set_p_sequencer(); \
    if( !$cast(p_sequencer, m_sequencer)) \
      `uvm_fatal("DCLPSQ", $sformatf("%m %s Error casting p_sequencer, please verify that this sequence/sequence item is intended to execute on this type of sequencer",get_full_name())) \
  endfunction

As shown above, define p_sequencer macro does declare p_sequencer handle of SEQUENCER type and casts m_sequencer handle to p_sequencer.

A virtual sequencer is generally referred to as a p_sequencer. This is used for user convenience. It is not a mandatory requirement. You can access virtual_sequencer with the env hierarchy path.

It sounds confusing but to understand the usage of p_sequencer and what exactly it is. Let’s understand what is a virtual sequence and virtual sequencer concept in the next section.