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?
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:
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.
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.
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
m_sequencer is a base (parent) type.p_sequencer is an extended(child) type .m_sequencer is a handle of āuvm_sequencer_baseā that is the base of āuvm_sequencerā.p_sequencer is a user-defined handle.When we start a sequence,we provide an object handle of our user_defind_sequencer . In the start method extended class instance is assigned to the base handle called m_sequencer . So a static casting is required to base an object to extend the handle.If p_sequencer is defined in the macro that is the p_sequencer function then define m_sequencer back to the p_sequencer using dynamic casting($cast).