Site icon

What is a p_sequencer and an m_sequencer in UVM?

In SystemVerilog based OVM/UVM methodologies,  UVM sequences are objects with limited life time unlike a component which has a lifetime through out simulation.

UVM Testbench – Sequences vs  Components

Refer following standard UVM test bench diagram for a general concept.  All components like  test, env, scoreboard, agent, monitor, sequencer and driver  are derived from   uvm_component  base class.  These are constructed at beginning of simulation in  a hierarchy – as parents and children.  All of the components can be accessed hierarchically from any other component by  traversing up till top  and further going down to any component.

 

On the other hand ,  UVM sequences , which are used a stimulus generators  are derived from the base class  uvm_sequence_item.  uvm_sequence_item is further derived from base uvm_object class.  These are not constructed at beginning of simulation and have no hierarchy associated.

As the test or simulation progresses, one or more UVM sequences are created and those are started on a sequencer. The sequencer-driver interface then sends one or more sequence items as stimulus to DUT.  Once the sequence completes generating all stimulus,  it will be de-referenced from memory.   This can be any time in the duration of a test.

Efficient Sequences – Need to query Testbench components

Sometimes to generate effective stimulus, a UVM sequence might want to query a testbench component like a monitor or a checker.  These are useful to generate efficient stimulus and sometimes reactively.  One example could be to monitor a DUT FIFO and keep sending sequence items untill it hits a full condition.   Since the sequence is not part of testbench hierarchy, this is not possible straightforward.   The only handle that a sequence will have access is the sequencer on which it is running currently.    Hence the sequence will need to access the monitor through the sequencer handle.

This is where the m_sequencer / p_sequencer concept is useful.

m_sequencer is a handle of type uvm_sequencer_base which is available by default in every sequence.

The real sequencer that connects to a driver is derived from the uvm_sequencer_base class. It is also parameterized to the sequence item type that is used to communicate to driver.

Hence to access the real sequencer on which sequence is running , we would need to typecast the m_sequencer to the real sequencer which is generally called p_sequencer. (I think this name was coined by some one initially to refer a physical sequencer. Alternatively, this can be named anything in your implementation)

Here is a simple example where a sequence wants to access a clock monitor component which is available with its sequencer

[code language=”cpp”]

//A test_sequencer class derived from base UVM sequencer
//Lets say, it has a clock monitor component to access clock.
class test_sequencer_c extends uvm_sequencer;
clock_monitor_c clk_monitor;
endclas

//Here is a test sequence that runs on the test_sequencer
//Lets say, sequence need access to sequencer to get access to clock monitor

class test_sequence_c extends uvm_sequence;

test_sequencer_c p_sequencer;
clock_monitor_c my_clock_monitor;

task pre_body()
//Typecast the m_sequencer base type to p_sequencer
if(!$cast(p_sequencer, m_sequencer)) begin
`uvm_fatal("Sequencer Type Mismatch:", " Worng Sequencer");
end
//get access to clock monitor
my_clock_monitor = p_sequencer.clk_monitor;
endtask

endclass

[/code]

Exit mobile version