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