Sunday, 30 April 2017

p_sequencer vs. m_sequencer

This is probably the most used and still most confusing for me in UVM.
In simple words, p_sequencer is just the dynamic casting of m_sequencer.

In testcase whenever we call start method to run the sequence,
 ------------------------------------------------------------------------------------------
class test extends uvm_test; 
 ...
  seq.start(sequencer);
...
endclass: test
 ------------------------------------------------------------------------------------------

This start method is the source code of UVM class 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);

...
  set_sequencer(sequnecer);
...
endtask
------------------------------------------------------------------------------------------

Inside uvm_sequence_item:
------------------------------------------------------------------------------------------
virtual function void set_sequencer(uvm_sequencer_base sequencer);
  m_sequencer = sequencer;
  m_set_p_sequencer();
endfunction

virtual function void m_set_p_sequencer();
  return; 
endfunction
------------------------------------------------------------------------------------------

So, as we can see whenever we call start method of sequence it's m_sequencer(a variable of uvm_sequencer) is getting set. This variable stores any object derived from uvm_sequencer. And it can access all the properties of uvm_sequencer class. 

Now what if user wants to access the property of it's own user defined sequencer, for that we have to have p_sequencer which points to the sequencer of our environment. 

p_sequencer only exists if we call uvm_decalre_p_sequencer macro, which is defined inside the UVM source code: 
------------------------------------------------------------------------------------------
`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())) \
endfunction
 ------------------------------------------------------------------------------------------

This macro is called inside the user defined sequence and the sequencer passed when we call start method (from the testcase) is casted to p_sequencer.

As we can see in the above code, p_sequencer is just the dynamic casting of m_sequencer with the user defined type class. So ultimately both points to the same thing with different type of class.

Properties of user defined sequencer can be accessed through p_sequencer and that is the reason we required p_sequencer.  














No comments:

Post a Comment