UVM: m_sequencer, p_sequencer difference

One of the most confusing UVM stuff is about m_sequencer and p_sequencer and the difference between the two. In reality, its just a game of polymorphism.

Referring to some forum answer, m_sequencer is a generic sequencer pointer of type uvm_sequencer_base. It will always exist for a uvm_sequence and is initialized when the sequence is started.

The p_sequencer is a type specific sequencer pointer, created by registering the sequence to a sequencer using the `uvm_declare_p_sequencer macros. Being type specific, you will be able to access anything added to the sequencer (i.e. pointers to other sequencers, etc.). p_sequencer will not exist if the `uvm_declare_p_sequencer macros isn’t used.

Lets have a look at the UVM sequence and sequencer hierarchy:


Sequence Hierarchy


Sequencer Hierarchy

As we can see sequence is ultimately extended from uvm_sequence_item and in turn from uvm_object. While sequencer has a grandparent of uvm_sequencer_base and uvm_component. This is one of the reason why sequencer has phases and sequence does not. But that’s an entire different part of discussion.

What we are interested in is that m_sequencer is a handle of type uvm_sequencer_base while p_sequencer is a handle of type user_defined_sequencer. The user_defined_sequencer is a grandchild of uvm_sequencer_base class.

When we start a sequence, we provide an object handle of our user_defined_sequencer. Internally, in start method, this child class object is assigned into parent handle called m_sequencer. So, a static casting occurs such that a parent class handle points to child class object (m_sequencer = user_defined_sequencer_object).

Now, when referring to sequence, if a p_sequencer is defined, the macro `uvm_declare_p_sequencer expands to a function that declares a user_defined_sequencer handle known as p_sequencer. This function then casts the m_sequencer (parent class handle) back to p_sequencer (child class handle) using dynamic casting ($cast).

Referring to a simple code as below, the

// uvm_sequencer_base
class base;
int a;

// user_defined_sequencer
class child extends base;
int b;

//... some other class
// Just like m_sequencer
base b;
// user created sequencer
child child1;
// Just like p_sequencer
child child2;

// user sequencer object in env/agent
child1 = new;
// internal in start method, m_sequencer = user_sequencer
b = child1;
// internal in declare_p_sequencer macro casting back from m_sequencer to p_sequencer

A more elaborate example is done at Mimic m_seqr p_seqr link.

Finally, referring to UVM source code, following snippets can give you an intuition.

In uvm_sequence_base:

virtual task start (uvm_sequencer_base sequencer,
uvm_sequence_base parent_sequence = null,
int this_priority = -1,
bit call_pre_post = 1);

// ... some other stuff
// ... some other stuff...

In uvm_sequence_item:

virtual function void set_sequencer(uvm_sequencer_base sequencer);
m_sequencer = sequencer;

virtual function void m_set_p_sequencer();

In user sequence:

`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())) \

In test:


The user_sequencer is passed to start method which invokes set_sequencer method of uvm_sequence_item. This method in turn calls m_set_p_sequencer (empty by default) method. If a p_sequencer is declared during macro expansion, then m_set_p_sequencer sets p_sequencer handle to user_defined_sequencer.

Thus, basically it is just a matter of static and dynamic casting between a base class and extended class. Hope this gives a basic idea about m_sequencer and p_sequencer help and avoiding confusion between the two.


profile for sharvil111 at Stack Overflow, Q&A for professional and enthusiast programmers

40 responses

  1. Excellent article, keep up the good work πŸ™‚



    1. Nice to hear about that.
      Thanks Karthik.


  2. I was just looking at your UVM: m_sequencer, p_sequencer difference | ASIC Verification website and see that your site has the potential to get a lot of visitors. I just want to tell you, In case you don’t already know… There is a website network which already has more than 16 million users, and the majority of the users are looking for topics like yours. By getting your website on this network you have a chance to get your site more visitors than you can imagine. It is free to sign up and you can read more about it here: http://url.laspas.gr/h7 – Now, let me ask you… Do you need your site to be successful to maintain your business? Do you need targeted traffic who are interested in the services and products you offer? Are looking for exposure, to increase sales, and to quickly develop awareness for your website? If your answer is YES, you can achieve these things only if you get your website on the service I am describing. This traffic service advertises you to thousands, while also giving you a chance to test the service before paying anything at all. All the popular blogs are using this service to boost their readership and ad revenue! Why aren’t you? And what is better than traffic? It’s recurring traffic! That’s how running a successful site works… Here’s to your success! Find out more here: http://pixz.nu/lywL


    1. Thanks Rachel for the opportunity. But this blog is all about knowledge sharing. No immediate remuneration is targeted. Regards, Sharvil.


  3. what is the difference in terms of application ? in terms of p_sequencer and m_sequencer ? thats not yet clear to me please help


    1. This is a wide-scope question.
      When you want to get some variable or connect some feedback port (from monitor most probably) in sequence, then p_sequencer is to be used. Since p_sequencer is the sequencer of user defined type, one can get the variable (config_db get) or implement some port in it. m_sequencer is a parent class; so one can not connect port or get a variable using m_sequencer handle (since m_sequencer can not access child class variables).

      But, the drawback of p_sequencer is that once the p_sequencer is defined, one cannot run the sequence on any other sequencer type.


      1. thanks this is in line with my understanding good work


      2. Nice to hear that. πŸ™‚


      3. on a different note i had this question … tb_top is a static component then how come we do a set_config_object of interface handles in tb_top ?


      4. I quite don’t get it exactly, but here is the best I can try. uvm_top is a singleton of uvm_root declared globally inside uvm_pkg. The interface instances are static entities. When we do a set_config_object/uvm_config_db, we set a “virtual” interface and not the actual interface. We just pass the handle of the actual interface, no new instance is created or passed down the hierarchy.

        On the get side, all the components reside inside under the uvm_top instance (somewhere inside m_add_child API). So, setting the object for uvm_top.*, adds the get-able handle of virtual interface to all the components that are registered with factory.


    2. Nice to hear that. πŸ™‚


  4. Muneeb Ulla Shariff | Reply

    Amazing lucid explaination! Really appreciate the effort.


    1. Thanks. It was my pleasure.


  5. Hi,

    Thanks for the explanation! However, I have a doubt:

    As per your explanation, for m_sequencer and p_sequencer to get handle to user_sequencer, user_sequence has to be started at-least once. Correct?
    I’ve seen below code at some places :


    How does this work?


    1. When we call the user_defined_sequence using “m_sequencer” or “p_sequencer” handle, then it must be invoked from some parent sequence and not from the test.

      This is mainly used in layered sequence where one sequence invokes other low level sequence. Refer this link where the set_sequencer API sets the m_sequencer to the sequencer provided in the start method. Here, the “m_sequencer” is the sequencer of the low level sequence and “sequencer” is again the “p/m_sequencer” of the high level sequence.

      Does it clear your doubt somewhat?


      1. Yes. This explains it clearly. So, we can start a sequence with p/m_sequencer only inside a virtual or hierarchical sequence. Thanks for the clarification. Appreciate your effort!


      2. Correct. Thanks Rishi. I am gratified πŸ™‚

        Liked by 1 person

  6. My spouse and I stumbled over here coming from a different website and thought I may as well check things out. I like what I see so now i am following you. Look forward to looking over your web page again.


    1. Thanks. Nice to see that it was helpful. πŸ™‚


  7. Excellent article, but i have a doubt. why p-sequencer came?


  8. Thanks Gaurav. “p_sequencer” is a user-defined type sequencer. When we want to access some variables from user sequencer or there is some feedback mechanism port connected to our sequencer, at that time “p_sequencer” is useful (by using m_sequencer handle, we can’t access variables of extended class — user defined sequencer). Hope this clears the doubt. πŸ™‚

    Liked by 1 person

  9. Thanks sharvil, now my doubt is clear.


  10. Well explained.. Will help many..
    Thanks Sharvil πŸ˜€


    1. Thanks Shrey. Nice to know that it helped. πŸ™‚


  11. Nice explanation, to such a confusing concept.


    1. Thanks Fuwad. Hope it cleared the concept.


  12. Great web site. Lots of useful information here. I’m sending it to several friends ans also sharing in delicious. And obviously, thanks for your effort!

    Liked by 1 person

  13. So far the best website, I ever visited.
    Kudos to you!!

    Liked by 1 person

    1. Thanks Divya. πŸ™‚

      Liked by 1 person

  14. Thank you Sharvil. This is a great article and m_sequencer and p_sequencer no longer confusing me. Great work.

    Liked by 1 person

    1. Thanks Harish. Nice to see that it is helpful. πŸ™‚

      Liked by 1 person

  15. Sharvil, randomly stumbled onto this site & OMG you cleared one of the doubts that has haunted me for a long time ! And I see that you have a talent at explaining things.
    What a clear and thorough explanation ! Great job ! Thank you !
    I look forward to your explanations to many more such confusing/complex topic !
    Also is there a way we could ask you questions ? πŸ™‚
    I am adding your blog site to my Favorite list on my browser.
    Thanks again !


    1. Thanks.. this means a lot!

      You can post the questions on any of the blog post. We can connect over the network via LinkedIn also πŸ™‚


      1. Hi sharvil, that was easy explanation to confusing concept. Thank you so much!

        I have a doubt on the concept of packed and unpacked arrays, why basic need of unpacked arrays when we can use packed arrays?

        when to use dynamic, associative and queues ??


  16. Thank you so much Sharvil


  17. Wow thanks dude


  18. Hi Sarvil,

    Nice explaining. I need some more help on this explanation.

    When do really need to modify the sequencer in reality?
    And how dose p sequencer compromise the reusability.

    If you can expand this blog as part 2 then it would help based on previous comments.


  19. Adding to previous post:

    When we really need a p_sequencer in env? Any use case?

    Or what can not be done with m_sequencer?


  20. Beautifully explained. Thanks a lot for clearing my concept!


  21. Website is very good. The explanation of concept is very clearance and good to understand.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: