Creation of user-defined phases in UVM is a possibility although it may hinder in complete re-usability of the testbench. There are chances for components to go out of sync and cause errors related to null pointer handles. But, in case you decide that you have to use one for your project, keep reading.

user-defined phase in uvm

Some of the main steps to using a custom phase are:

  • Create and define a new phase class
  • Add the new phase to an existing schedule
  • Use the new phase in a component that supports this phase

Create custom phase class

1. Extend appropriate base class for your phase type

class my_PHASE_phase extends uvm_task_phase;
class my_PHASE_phase extends uvm_topdown_phase;
class my_PHASE_phase extends uvm_bottomup_phase;
2. Implement exec_task or exec_func method based on whether this phase consumes simulation time.
task          exec_task (uvm_component comp, uvm_phase schedule);
function void exec_func (uvm_component comp, uvm_phase schedule);

Here's the complete example of a new phase class definition.


class uvm_user_phase extends uvm_task_phase; 

   // Define the new method; set the name without "uvm" and "phase"
   protected function new(string name="post_run"); 
      super.new(name); 
   endfunction
   
   // Create a function to return the type name
   static const string type_name = "uvm_user_phase"; 
   virtual function string get_type_name(); 
      return type_name; 
   endfunction
   
   // If this phase is a task that requires simulation time, you need to
   // define "exec_task" method
   virtual task exec_task(uvm_component comp, uvm_phase phase); 
      my_test TEST;
      if ($cast(TEST, comp))
         TEST.post_run_phase (phase);
   endtask
   
   // Create a singleton object that can be accessed elsewhere
   local static uvm_user_phase m_inst; 
   
   // Create a method to return the singleton object
   static function uvm_user_phase get(); 
      if(m_inst == null)
         m_inst = new; 
      return m_inst; 
   endfunction
endclass

user-defined phase inserted into run-time phases

Insert new phase into schedule

UVM has a certain sequence of executing phases which you can review in Phases . We can insert the new phase in between any of the existing phases for which we have to obtain the handle to the UVM phase scheduler or domain. A domain is a phasing schedule node that represents and independent branch of the schedule. Individual phases are added to a domain which will be inserted into the required schedule.

1. Get handle to the appropriate domain

// Use this if you want to insert in between the common phases 
// build, connect, end_of_elaboration, start_of_simulation, run, extract, check, report, final
uvm_domain dm = uvm_domain::get_common_domain ();

// Use this if you want to insert in between run-time phases
// reset, configure, main, shutdown
uvm_domain dm = uvm_domain::get_uvm_domain ();
2. Get a handle to the phase after which you want to insert

uvm_phase ph = dm.find (uvm_connect_phase::get());

// Or whichever phase; substitute phase_name with actual phase name like build, reset, etc
uvm_phase ph = dm.find (uvm_[phase_name]_phase::get());
3. Insert phase into the domain

dm.add (uvm_user_phase::get(), null, ph, null);

Here's the complete example and for our purpose it has been included as part of the testcase.


class my_test extends uvm_test;
	...
	virtual function void add_my_phase ();
		uvm_domain dm = uvm_domain::get_common_domain ();
		uvm_phase ph = dm.find (uvm_connect_phase::get());
		dm.add (uvm_user_phase::get(), null, ph, null);
	endfunction
	
	function new (string name = "my_test", uvm_component parent);
		super.new (name, parent);
		add_my_phase();
	endfunction
	...
	
	// Define what needs to be done when the new phase is executed
	virtual task user_phase (uvm_phase phase);
		`uvm_info ("TEST", $sformatf ("In %s phase", phase.get_name()), UVM_MEDIUM)
	endtask
endclass
 Simulation Log
----------------------------------------------------------------
(C) 2007-2013 Mentor Graphics Corporation
(C) 2007-2013 Cadence Design Systems, Inc.
(C) 2006-2013 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
----------------------------------------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test my_test...
UVM_INFO ./tb_top.sv(42) @ 0: uvm_test_top [TEST] In build_phase
UVM_INFO ./tb_top.sv(47) @ 0: uvm_test_top [TEST] In connect_phase
UVM_INFO ./tb_top.sv(66) @ 0: uvm_test_top [TEST] In user_phase
UVM_INFO ./tb_top.sv(57) @ 0: uvm_test_top [TEST] In run_phase
UVM_INFO ./tb_top.sv(62) @ 0: uvm_test_top [TEST] In extract_phase
UVM_INFO ./tb_top.sv(71) @ 0: uvm_test_top [TEST] In final_phase

--- UVM Report catcher Summary ---


Number of demoted UVM_FATAL reports  :    0
Number of demoted UVM_ERROR reports  :    0
Number of demoted UVM_WARNING reports:    0
Number of caught UVM_FATAL reports   :    0
Number of caught UVM_ERROR reports   :    0
Number of caught UVM_WARNING reports :    0

--- UVM Report Summary ---

Note that user_phase was inserted after the connect_phase as expected.