blob: a96aece45bcb2e054f534abd47285625933e900b [file] [log] [blame]
// $Id: //dvt/vtech/dev/main/ovm/src/base/ovm_phases.sv#25 $
//------------------------------------------------------------------------------
// Copyright 2007-2009 Mentor Graphics Corporation
// Copyright 2007-2009 Cadence Design Systems, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//------------------------------------------------------------------------------
`ifndef OVM_PHASES_SVH
`define OVM_PHASES_SVH
typedef class ovm_component;
//------------------------------------------------------------------------------
//
// Class: ovm_phase
//
// The ovm_phase class is used for defining phases for ovm_component and its
// subclasses. For a list of predefined phases see
// <ovm_component::Phasing Interface>
//
//------------------------------------------------------------------------------
virtual class ovm_phase;
local string m_name;
local bit m_is_top_down;
local bit m_is_task;
local event m_start_event;
local bit m_is_started=0;
local event m_done_event;
local bit m_is_done=0;
local bit m_executed[int];
local ovm_phase m_aliases[$];
local ovm_phase m_insertion_phase;
// Function: new
//
// Creates a phase object.
//
// The name is the name of the phase. When is_top_down is set, the parent is
// phased before its children. is_task indicates whether the phase callback is
// a task (1) or function (0). Only tasks may consume simulation time and
// execute blocking statements.
function new (string name, bit is_top_down, bit is_task);
m_name = name;
m_is_top_down = is_top_down;
m_is_task = is_task;
endfunction
//----------------//
// Info interface //
//----------------//
// Function: get_name
//
// Returns the name of the phase object as supplied in the constructor.
function string get_name (); return m_name; endfunction
// Function: is_task
//
// Returns 1 if the phase is time consuming and 0 if not.
function bit is_task (); return m_is_task; endfunction
// Function: is_top_down
//
// Returns 1 if the phase executes top-down (executes the parent¿s phase
// callback before executing the children¿s callback) and 0 otherwise.
function bit is_top_down (); return m_is_top_down; endfunction
// Function: get_type_name
//
// Derived classes should override this method to return the phase type name.
virtual function string get_type_name();
return "ovm_phase";
endfunction
//--------------------------//
// Event & Status interface //
//--------------------------//
// Task: wait_start
//
// Waits until the phase has beed started.
task wait_start ();
@m_start_event;
endtask
// Task: wait_done
//
// Waits until the phase has been completed.
task wait_done ();
@m_done_event;
endtask
// Function: is_in_progress
//
// Returns 1 if the phase is currently in progress (active), 0 otherwise.
function bit is_in_progress ();
return m_is_started;
endfunction
// Function: is_done
//
// Returns 1 if the phase has completed, 0 otherwise.
function bit is_done ();
return m_is_done;
endfunction
// Function: reset
//
// Resets phase state such that is_done and is_in_progress both return 0.
function void reset ();
m_is_done=0;
m_is_started=0;
m_executed.delete();
foreach(m_aliases[i])
m_aliases[i].reset();
endfunction
// Task: call_task
//
// Calls the task-based phase of the component given by parent, which must be
// derived from ovm_component. A task-based phase is defined by subtyping
// ovm_phase and overriding this method. The override must $cast the base
// parent handle to the actual component type that defines the phase callback,
// and then call the phase callback.
virtual task call_task (ovm_component parent);
foreach(m_aliases[i]) m_aliases[i].call_task(parent);
return;
endtask
// Function: call_func
//
// Calls the function-based phase of the component given by parent. A
// function-based phase is defined by subtyping ovm_phase and overriding this
// method. The override must $cast the base parent handle to the actual
// component type that defines the phase callback, and then call that
// phase callback.
virtual function void call_func (ovm_component parent);
foreach(m_aliases[i]) m_aliases[i].call_func(parent);
return;
endfunction
// psuedo-private methods; do not call directly
function void m_set_is_started(bit val);
foreach(m_aliases[i]) m_aliases[i].m_set_is_started(val);
m_is_started=val;
endfunction
function void m_set_in_progress();
foreach(m_aliases[i]) m_aliases[i].m_set_in_progress();
m_set_is_started(1);
->m_start_event;
endfunction
function void m_set_done();
foreach(m_aliases[i]) m_aliases[i].m_set_done();
m_is_done=1;
m_set_is_started(0);
->m_done_event;
endfunction
function void set_insertion_phase(ovm_phase phase);
if(m_insertion_phase != null) begin
ovm_report_warning("INSPHS", "Cannot set the insertion phase for a phase that has already been set");
return;
end
m_insertion_phase = phase;
endfunction
function ovm_phase get_insertion_phase();
return m_insertion_phase;
endfunction
function bit has_executed(ovm_component comp);
if(m_executed.exists(comp.get_inst_id())) return 1;
foreach(m_aliases[i])
if(m_aliases[i].has_executed(comp)) return 1;
return 0;
endfunction
function void set_executed(ovm_component comp);
m_executed[comp.get_inst_id()] = 1;
endfunction
function void add_alias(ovm_phase the_alias, exist_ph);
ovm_phase insertion_phase;
string alias_nm, insrt_nm, alias_insrt_nm;
//if the alias is null then return
if(the_alias == null) return;
if(the_alias == this && m_insertion_phase == exist_ph) return;
alias_nm = the_alias.get_name();
//This warning can't happen from ovm_root, but in theory a user could create
//their own phase controller in which case, aliasing different names is probably
//not desireable.
if(alias_nm != get_name()) begin
ovm_report_warning("PHSALS", {
"Phases ", get_name(), " and ", alias_nm,
" are being aliased, but have different phase names"});
end
//verify that the aliased phase has the same semantics as the
//master phase.
if(m_is_task != the_alias.is_task()) begin
ovm_report_fatal("PHSALS", {
"Phases ", get_name(), " and ", alias_nm,
" are being aliased, but one is a function phase and one is a task phase"}, OVM_NONE);
return;
end
if(m_is_top_down != the_alias.is_top_down()) begin
ovm_report_fatal("PHSALS", {
"Phases ", get_name(), " and ", alias_nm,
" are being aliased, but one is top-down and the other is bottom-up"}, OVM_NONE);
return;
end
if(exist_ph != null)
alias_insrt_nm = exist_ph.get_name();
else
alias_insrt_nm = "the topmost phase";
if(m_insertion_phase != null)
insrt_nm = m_insertion_phase.get_name();
else
insrt_nm = "the topmost phase";
if(insrt_nm != alias_insrt_nm) begin
ovm_report_fatal("PHSALS", {
"Phases ", get_name(), " and ", alias_nm,
" are being aliased, they have different insertion phase, \"",
insrt_nm, "\" versus \"", alias_insrt_nm, "\""}, OVM_NONE);
return;
end
//for existing aliases, we needed to verify the insertion phase
//which is why we wait to the end before we exit.
foreach(m_aliases[i]) if (the_alias == m_aliases[i]) return;
if(the_alias == this) return;
the_alias.set_insertion_phase(exist_ph);
m_aliases.push_back(the_alias);
endfunction
endclass
// Section: Usage
//
// Phases are a synchronizing mechanism for the environment. They are
// represented by callback methods. A set of predefined phases and corresponding
// callbacks are provided in ovm_component. Any class deriving from
// ovm_component may implement any or all of these callbacks, which are executed
// in a particular order. Depending on the properties of any given phase, the
// corresponding callback is either a function or task, and it is executed in
// top-down or bottom-up order.
//
// The OVM provides the following predefined phases for all ovm_components.
//
// build - Depending on configuration and factory settings,
// create and configure additional component hierarchies.
//
// connect - Connect ports, exports, and implementations (imps).
//
// end_of_elaboration - Perform final configuration, topology, connection,
// and other integrity checks.
//
// start_of_simulation - Do pre-run activities such as printing banners,
// pre-loading memories, etc.
//
// run - Most verification is done in this time-consuming phase. May fork
// other processes. Phase ends when global_stop_request is called
// explicitly.
//
// extract - Collect information from the run in preparation for checking.
//
// check - Check simulation results against expected outcome.
//
// report - Report simulation results.
//
// A phase is defined by an instance of an ~ovm_phase~ subtype. If a phase is to
// be shared among several component types, the instance must be accessible from
// a common scope, such as a package.
//
// To have a user-defined phase get called back during simulation, the phase
// object must be registered with the top-level OVM phase controller, ovm_top.
//
// Inheriting from the ~ovm_phase~ Class:
//
// When creating a user-defined phase, you must do the following.
//
// 1. Define a new phase class, which must extend ~ovm_phase~. To enable use of
// the phase by any component, we recommend this class be parameterized.
// The easiest way to define a new phase is to invoke a predefined macro.
// For example:
//
// | `ovm_phase_func_topdown_decl( preload )
//
// This convenient phase declaration macro is described below.
//
// 2. Create a single instance of the phase in a convenient placein a package,
// or in the same scope as the component classes that will use the phase.
//
// | typedef class my_memory;
// | preload_phase #(my_memory) preload_ph = new;
//
// 3. Register the phase object with ovm_top.
//
// | class my_memory extends ovm_component;
// | function new(string name, ovm_component parent);
// | super.new(name,parent);
// | ovm_top.insert_phase(preload_ph, start_of_simulation_ph);
// | endfunction
// | virtual function void preload(); // our new phase
// | ...
// | endfunction
// | endclass
//
//
// Phase Macros (Optional):
//
// The following macros simplify the process of creating a user-defined phase. They
// create a phase type that is parameterized to the component class that uses the
// phase.
//
// Macro: `ovm_phase_func_decl
//
// `ovm_phase_func_decl (PHASE_NAME, TOP_DOWN)
//
// The ~PHASE_NAME~ argument is used to define the name of the phase, the name of
// the component method that is called back during phase execution, and the
// prefix of the type-name of the phase class that gets generated.
//
// The above macro creates the following class definition.
//
//| class PHASE_NAME``_phase #(type PARENT=int) extends ovm_phase;
//|
//| PARENT m_parent;
//|
//| function new();
//| super.new(`"NAME`",TOP_DOWN,1);
//| endfunction
//| virtual function void call_func();
//| m_parent.NAME(); // call the component¿s phase callback
//| endtask
//| virtual task execute(ovm_component parent);
//| assert($cast(m_parent,parent));
//| call_func();
//| endtask
//| endclass
//
// Macro: `ovm_phase_task_decl
//
//| `ovm_phase_task_decl (PHASE_NAME, TOP_DOWN)
//
// The above macro creates the following class definition.
//
//| class PHASE_NAME``_phase #(type PARENT=int) extends ovm_phase;
//| PARENT m_parent;
//| function new();
//| super.new(`"NAME`",TOP_DOWN,1);
//| endfunction
//| virtual task call_task();
//| m_parent.NAME(); // call the component¿s phase callback
//| endtask
//| virtual task execute(ovm_component parent);
//| assert($cast(m_parent,parent));
//| call_task();
//| endtask
//| endclass
//
//
// Macro: `ovm_phase_func_topdown_decl
//
// Macro: `ovm_phase_func_bottomup_decl
//
// Macro: `ovm_phase_task_topdown_decl
//
// Macro: `ovm_phase_task_bottomup_decl
//
// These alternative macros have a single phase name argument. The top-down or
// bottom-up selection is specified in the macro name, which makes them more
// self-documenting than those with a 0 or 1 2nd argument.
//
//| `define ovm_phase_func_topdown_decl `ovm_phase_func_decl (PHASE_NAME,1)
//| `define ovm_phase_func_bottomup_decl `ovm_phase_func_decl (PHASE_NAME,0)
//| `define ovm_phase_task_topdown_decl `ovm_phase_task_decl (PHASE_NAME,1)
//| `define ovm_phase_task_bottomup_decl `ovm_phase_task_decl (PHASE_NAME,0)
//
`endif // OVM_PHASES_SVH