P_sequencer and m_sequencer

Hi,

Can someone tell me What is the key difference between p and m sequencers? And also give me an example WHERE & WHEN we can use these sequencers?

Read this UVM Cookbook article which describes the m_sequencer handle.

The p_sequencer handle is the same as the m_sequencer handle, except it is type-specific to the sequencer. However, it is highly recommended that you never use p_sequencer due to re-use concerns. If you need to get configuration information into your sequence, use the uvm_config_db and the m_sequencer handle.

In reply to cgales:

I read it but I dint get the difference exactly.

m_sequencer is the default handle for uvm_vitual_sequencer and p_sequencer is the hook up for child sequencer.

m_sequencer is the generic uvm_sequencer pointer. it will always exist for the uvm_sequence and is initialized when the sequence is started.

p_sequencer is a typed-specific sequencer pointer, created by registering the sequence to the sequencer using macros. It will not exist if we have not registered the sequence with macros.
As it is type-specific we can access almost everything added to the sequencer.

try to avoid using p_sequencer.

Regards
Ujjwal

In reply to Ujjwal Kaushik:

Can you explain it with one example?

In reply to syed taahir ahmed:

http://cluelogic.com/2011/07/uvm-tutorial-for-candy-lovers-transactions-and-sequences/

Go through this. Specially the post and comments below on this page.

In reply to Ankur Jain4:

Thanks Ankur.

In reply to cgales:

Just to be clear, when you say use m_sequencer to get configuration information, do you mean something like:

class seq_plb_base extends uvm_sequence #(plb_transaction);
  `uvm_object_utils(seq_plb_base);
  const string report_id="SEQ";

  plb_agent_configuration cfg;

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

  virtual task body();
    if( !uvm_config_db #( plb_agent_configuration )::get( m_sequencer, "", "AGENT_CONFIG", cfg ))
      `uvm_fatal(report_id, "cannot find resource AGENT_CONFIG" )
    // .. do stuff

  endtask

endclass

But, as soon as I enter the work of transient dynamic objects like this, does performance not dictate that I should avoid using the config_db? I seems simpler to simply use p_sequencer.cfg (which is assigned once, in the agent).

An even more drastic situation: I extend a transaction, and apply constraints to it based on some configuration variable. If I rely on the database in that case, I’m really up the creek for performance. Example, I am generating IP packets, so I extend ip_transaction, and add a constraint that the destination IP address should be … some distribution or another. That distribution is based off IP addresses that were randomized in the test. That’s not really something I’d like to pull from DB every single time I create a packet. What do you think?

In reply to bmorris:

There are several approaches that I’ve seen to getting configuration information into a sequence/sequence_item:

  1. Use the uvm_config_db() with the m_sequencer. This is very flexible and allows the object to be ‘self configuring’ and have no additional configuration requirements on the parent sequence/test. However, this method can add some significant overhead if you do large numbers of sequences/sequence_items.

  2. Have the parent sequence/test set the configuration handles after creating the sequence/sequence_item. This can reduce the uvm_config_db() accesses, but adds the requirements that the parent set these objects prior to starting the sequence. This precludes the use of the `uvm_do… macros, but we don’t like them anyway.

  3. Have the sequence get the config objects directly from the p_sequencer. This will reduce the uvm_config_db() accesses, but will require the use of a p_sequencer which is highly discouraged due to re-usability concerns.

I prefer option 2 myself, but either 1 or 2 is recommended.

In reply to cgales:

Understood. Just to be fully explicit, why does using the p_sequencer reduce the re-usability?

In reply to bmorris:

Using a p_sequencer requires that the sequence be run on a sequencer of a specific type (or base type). This will limit your ability to run the sequence on other sequencers.

My preference is to always create a generic uvm_sequencer typed with the specific uvm_sequence_item (or generic uvm_sequence_item for a virtual sequencer). This simplifies the requirement to make an agent or environment specific sequencer. Also, I have seen environments where they will create a specific sequencer and override the run_phase() method (because every component needs a run_phase()…). Trying to debug that issue is fun.

For portability, your sequence will be only limited to a sequencer that is typed to your sequence_item, instead of being limited to a sequencer of your p_sequencer type. It’s a subtle difference and won’t make a difference in 90% of environments, but it’s a pain to go back and re-architect if you hit the corner case.

In reply to cgales:

Also, I have seen environments where they will create a specific sequencer and override the run_phase() method (because every component needs a run_phase()…). Trying to debug that issue is fun.

That never crossed my mind; lol

For portability, your sequence will be only limited to a sequencer that is typed to your sequence_item, instead of being limited to a sequencer of your p_sequencer type. It’s a subtle difference and won’t make a difference in 90% of environments, but it’s a pain to go back and re-architect if you hit the corner case.

I can’t picture when this could happen right at the moment, but see where you are coming from. Thanks