m_sequencer and p_sequencer in UVM

m_sequencer:

  • Definition:

The m_sequencer is a handle to the sequencer instance in the sequence. It is default sequencer. It provides access to the sequencer’s methods and properties.

  • Scope: Private (internal to UVM).
  • Use Case:

The m_sequencer is automatically created and managed by UVM. It is used internally by the sequence to communicate with the sequencer. Users typically do not interact with m_sequencer directly.

p_sequencer:

  • Definition:

The p_sequencer is a type-specific reference to the parent sequencer. It allows sequences to interact with user-defined methods or attributes in a customized sequencer.

  • Scope: Public (available to the user).
  • Use case:

When you extend the UVM sequencer and define additional functionality, sequences can access this functionality via p_sequencer. It requires type casting to ensure the sequence knows the exact type of the sequencer it interacts with.

Example for m_sequencer and p_sequencer:

m_sequencer:

Consider a simple example with an adder DUT that takes two inputs (a and b) and generates an output (sum). Here’s how the UVM sequencer works:

  1. sequence class
class adder_sequence extends uvm_sequence #(adder_transaction);
  `uvm_object_utils(adder_sequence)
   
  adder_transaction trans;  

  // Constructor
  function new(string name = "adder_sequence");
    super.new(name);
  endfunction

  // Body
  virtual task body();
     trans=adder_transaction::type_id::create("trans");
    // Start generating transactions
    for (int i=0; i<5; i++) begin
      start_item(trans);
      trans = adder_transaction::type_id::create("trans");
      trans.randomize();
      `uvm_info("SEQUENCE", $sformatf("Generated transaction: a=%0d, b=%0d", trans.a, trans.b), UVM_MEDIUM)
      finish_item(trans);
    end
  endtask
endclass

2. Sequencer class (default or m_sequencer)

class adder_sequencer extends uvm_sequencer #(adder_transaction);
  `uvm_component_utils(adder_sequencer)

  // Constructor
  function new(string name = "adder_sequencer", uvm_component parent = null);
    super.new(name, parent);
  endfunction
endclass

p_sequencer:

Suppose you want to extend the sequencer to include a transaction_count variable:

  1. Customized Sequencer:
class custom_adder_sequencer extends adder_sequencer;
  `uvm_component_utils(custom_adder_sequencer)

  int transaction_count;

  // Constructor
  function new(string name = "custom_adder_sequencer", uvm_component parent = null);
    super.new(name, parent);
    transaction_count = 0;
  endfunction
endclass

2. Using p_sequencer in the Sequence:

class custom_adder_sequence extends adder_sequence;
  `uvm_object_utils(custom_adder_sequence)
   
  adder_transaction trans;

  // Body
  virtual task body();
    trans = adder_transaction::type_id::create("trans");
    for (int i=0; i<5; i++) begin
      start_item(trans);
      trans.randomize();
      `uvm_info("SEQUENCE", $sformatf("Generated transaction: a=%0d, b=%0d", trans.a, trans.b), UVM_MEDIUM)

      // Access custom sequencer properties using p_sequencer
      p_sequencer.transaction_count++;
      `uvm_info("SEQUENCE", $sformatf("Transaction Count: %0d", p_sequencer.transaction_count), UVM_LOW)

      finish_item(trans);
    end
  endtask
endclass

In this example, the sequence accesses the transaction_count variable of the customized sequencer using p_sequencer.