task run_test (string test_name="");
uvm_root top;
...
top.run_test(test_name);
endtask
uvm_root::run_test will call uvm_phase::m_run_phase, which will first call uvm_domain::get_common_domain to create the phases.
task uvm_root::run_test(string test_name="");
...
// phase runner, isolated from calling process
fork begin
// spawn the phase runner task
phase_runner_proc = process::self();
uvm_phase::m_run_phases();
end
join_none
#0; // let the phase runner start
wait (m_phase_all_done == 1);
...
endtask
task uvm_phase::m_run_phases();
...
// initiate by starting first phase in common domain
begin
uvm_phase ph = uvm_domain::get_common_domain();
void'(m_phase_hopper.try_put(ph));
end
forever begin
uvm_phase phase;
m_phase_hopper.get(phase);
fork
begin
phase.execute_phase();
end
join_none
#0; // let the process start running
end
endtask
uvm_root top;
...
top.run_test(test_name);
endtask
uvm_root::run_test will call uvm_phase::m_run_phase, which will first call uvm_domain::get_common_domain to create the phases.
task uvm_root::run_test(string test_name="");
...
// phase runner, isolated from calling process
fork begin
// spawn the phase runner task
phase_runner_proc = process::self();
uvm_phase::m_run_phases();
end
join_none
#0; // let the phase runner start
wait (m_phase_all_done == 1);
...
endtask
task uvm_phase::m_run_phases();
...
// initiate by starting first phase in common domain
begin
uvm_phase ph = uvm_domain::get_common_domain();
void'(m_phase_hopper.try_put(ph));
end
forever begin
uvm_phase phase;
m_phase_hopper.get(phase);
fork
begin
phase.execute_phase();
end
join_none
#0; // let the process start running
end
endtask
The phases created by uvm_domain::get_common_domain are uvm_build_phase, uvm_connect_phase, uvm_end_of_elaboration_phase, uvm_start_of_simulation_phase, uvm_run_phase, uvm_extract_phase, uvm_check_phase, uvm_report_phase and uvm_final_phase.
Then uvm_domain::get_common_domain will call get_uvm_domain() to create phases uvm_pre_reset_phase, uvm_reset_phase, uvm_post_reset_phase, uvm_pre_configure_phase, uvm_configure_phase, uvm_post_configure_phase, uvm_pre_main_phase, uvm_main_phase, uvm_post_main_phase, uvm_pre_shutdown_phase, uvm_shutdown_phase and uvm_post_shutdown_phase.
static function uvm_domain get_common_domain();
uvm_domain domain;
uvm_phase schedule;
if (m_common_domain != null)
return m_common_domain;
domain = new("common");
domain.add(uvm_build_phase::get());
domain.add(uvm_connect_phase::get());
domain.add(uvm_end_of_elaboration_phase::get());
domain.add(uvm_start_of_simulation_phase::get());
domain.add(uvm_run_phase::get());
domain.add(uvm_extract_phase::get());
domain.add(uvm_check_phase::get());
domain.add(uvm_report_phase::get());
domain.add(uvm_final_phase::get());
m_domains["common"] = domain;
// for backward compatibility, make common phases visible;
// same as uvm_<name>_phase::get().
build_ph = domain.find(uvm_build_phase::get());
connect_ph = domain.find(uvm_connect_phase::get());
end_of_elaboration_ph = domain.find(uvm_end_of_elaboration_phase::get());
start_of_simulation_ph = domain.find(uvm_start_of_simulation_phase::get());
run_ph = domain.find(uvm_run_phase::get());
extract_ph = domain.find(uvm_extract_phase::get());
check_ph = domain.find(uvm_check_phase::get());
report_ph = domain.find(uvm_report_phase::get());
m_common_domain = domain;
domain = get_uvm_domain();
m_common_domain.add(domain,
.with_phase(m_common_domain.find(uvm_run_phase::get())));
return m_common_domain;
endfunction
static function uvm_domain get_uvm_domain();
if (m_uvm_domain == null) begin
m_uvm_domain = new("uvm");
m_uvm_schedule = new("uvm_sched", UVM_PHASE_SCHEDULE);
add_uvm_phases(m_uvm_schedule);
m_uvm_domain.add(m_uvm_schedule);
end
return m_uvm_domain;
endfunction
static function void add_uvm_phases(uvm_phase schedule);
schedule.add(uvm_pre_reset_phase::get());
schedule.add(uvm_reset_phase::get());
schedule.add(uvm_post_reset_phase::get());
schedule.add(uvm_pre_configure_phase::get());
schedule.add(uvm_configure_phase::get());
schedule.add(uvm_post_configure_phase::get());
schedule.add(uvm_pre_main_phase::get());
schedule.add(uvm_main_phase::get());
schedule.add(uvm_post_main_phase::get());
schedule.add(uvm_pre_shutdown_phase::get());
schedule.add(uvm_shutdown_phase::get());
schedule.add(uvm_post_shutdown_phase::get());
endfunction
uvm_domain domain;
uvm_phase schedule;
if (m_common_domain != null)
return m_common_domain;
domain = new("common");
domain.add(uvm_build_phase::get());
domain.add(uvm_connect_phase::get());
domain.add(uvm_end_of_elaboration_phase::get());
domain.add(uvm_start_of_simulation_phase::get());
domain.add(uvm_run_phase::get());
domain.add(uvm_extract_phase::get());
domain.add(uvm_check_phase::get());
domain.add(uvm_report_phase::get());
domain.add(uvm_final_phase::get());
m_domains["common"] = domain;
// for backward compatibility, make common phases visible;
// same as uvm_<name>_phase::get().
build_ph = domain.find(uvm_build_phase::get());
connect_ph = domain.find(uvm_connect_phase::get());
end_of_elaboration_ph = domain.find(uvm_end_of_elaboration_phase::get());
start_of_simulation_ph = domain.find(uvm_start_of_simulation_phase::get());
run_ph = domain.find(uvm_run_phase::get());
extract_ph = domain.find(uvm_extract_phase::get());
check_ph = domain.find(uvm_check_phase::get());
report_ph = domain.find(uvm_report_phase::get());
m_common_domain = domain;
domain = get_uvm_domain();
m_common_domain.add(domain,
.with_phase(m_common_domain.find(uvm_run_phase::get())));
return m_common_domain;
endfunction
static function uvm_domain get_uvm_domain();
if (m_uvm_domain == null) begin
m_uvm_domain = new("uvm");
m_uvm_schedule = new("uvm_sched", UVM_PHASE_SCHEDULE);
add_uvm_phases(m_uvm_schedule);
m_uvm_domain.add(m_uvm_schedule);
end
return m_uvm_domain;
endfunction
static function void add_uvm_phases(uvm_phase schedule);
schedule.add(uvm_pre_reset_phase::get());
schedule.add(uvm_reset_phase::get());
schedule.add(uvm_post_reset_phase::get());
schedule.add(uvm_pre_configure_phase::get());
schedule.add(uvm_configure_phase::get());
schedule.add(uvm_post_configure_phase::get());
schedule.add(uvm_pre_main_phase::get());
schedule.add(uvm_main_phase::get());
schedule.add(uvm_post_main_phase::get());
schedule.add(uvm_pre_shutdown_phase::get());
schedule.add(uvm_shutdown_phase::get());
schedule.add(uvm_post_shutdown_phase::get());
endfunction
After the phases are created, uvm_phase::m_run_phases() will call phase.execute_phase() to run phases.
task uvm_phase::m_run_phases();
...
// initiate by starting first phase in common domain
begin
uvm_phase ph = uvm_domain::get_common_domain();
void'(m_phase_hopper.try_put(ph));
end
forever begin
uvm_phase phase;
m_phase_hopper.get(phase);
fork
begin
phase.execute_phase();
end
join_none
#0; // let the process start running
end
endtask
class uvm_build_phase extends uvm_topdown_phase;
virtual function void exec_func(uvm_component comp, uvm_phase phase);
comp.build_phase(phase);
endfunction
local static uvm_build_phase m_inst;
static const string type_name = "uvm_build_phase";
static function uvm_build_phase get();
if(m_inst == null)
m_inst = new();
return m_inst;
endfunction
protected function new(string name="build");
super.new(name);
endfunction
virtual function string get_type_name();
return type_name;
endfunction
endclass
virtual class uvm_topdown_phase extends uvm_phase;
...
...
// initiate by starting first phase in common domain
begin
uvm_phase ph = uvm_domain::get_common_domain();
void'(m_phase_hopper.try_put(ph));
end
forever begin
uvm_phase phase;
m_phase_hopper.get(phase);
fork
begin
phase.execute_phase();
end
join_none
#0; // let the process start running
end
endtask
task uvm_phase::execute_phase();
uvm_task_phase task_phase;
uvm_root top;
uvm_phase_state_change state_chg;
uvm_coreservice_t cs;
cs = uvm_coreservice_t::get();
top = cs.get_root();
// If we got here by jumping forward, we must wait for
// all its predecessor nodes to be marked DONE.
// (the next conditional speeds this up)
// Also, this helps us fast-forward through terminal (end) nodes
foreach (m_predecessors[pred])
wait (pred.m_state == UVM_PHASE_DONE);
// If DONE (by, say, a forward jump), return immed
if (m_state == UVM_PHASE_DONE)
return;
state_chg = uvm_phase_state_change::type_id::create(get_name());
state_chg.m_phase = this;
state_chg.m_jump_to = null;
//---------
// SYNCING:
//---------
// Wait for phases with which we have a sync()
// relationship to be ready. Sync can be 2-way -
// this additional state avoids deadlock.
state_chg.m_prev_state = m_state;
m_state = UVM_PHASE_SYNCING;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
#0;
if (m_sync.size()) begin
foreach (m_sync[i]) begin
wait (m_sync[i].m_state >= UVM_PHASE_SYNCING);
end
end
m_run_count++;
if (m_phase_trace) begin
`UVM_PH_TRACE("PH/TRC/STRT","Starting phase",this,UVM_LOW)
end
// If we're a schedule or domain, then "fake" execution
if (m_phase_type != UVM_PHASE_NODE) begin
state_chg.m_prev_state = m_state;
m_state = UVM_PHASE_STARTED;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
#0;
state_chg.m_prev_state = m_state;
m_state = UVM_PHASE_EXECUTING;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
#0;
end
else begin // PHASE NODE
//---------
// STARTED:
//---------
state_chg.m_prev_state = m_state;
m_state = UVM_PHASE_STARTED;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
m_imp.traverse(top,this,UVM_PHASE_STARTED);
m_ready_to_end_count = 0 ; // reset the ready_to_end count when phase starts
#0; // LET ANY WAITERS WAKE UP
//if (m_imp.get_phase_type() != UVM_PHASE_TASK) begin
if (!$cast(task_phase,m_imp)) begin
//-----------
// EXECUTING: (function phases)
//-----------
state_chg.m_prev_state = m_state;
m_state = UVM_PHASE_EXECUTING;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
#0; // LET ANY WAITERS WAKE UP
m_imp.traverse(top,this,UVM_PHASE_EXECUTING);
end
else begin
m_executing_phases[this] = 1;
state_chg.m_prev_state = m_state;
m_state = UVM_PHASE_EXECUTING;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
fork : master_phase_process
begin
m_phase_proc = process::self();
//-----------
// EXECUTING: (task phases)
//-----------
task_phase.traverse(top,this,UVM_PHASE_EXECUTING);
wait(0); // stay alive for later kill
end
join_none
uvm_wait_for_nba_region(); //Give sequences, etc. a chance to object
// Now wait for one of three criterion for end-of-phase.
fork
begin // guard
fork
// JUMP
begin
wait (m_premature_end);
`UVM_PH_TRACE("PH/TRC/EXE/JUMP","PHASE EXIT ON JUMP REQUEST",this,UVM_DEBUG)
end
// WAIT_FOR_ALL_DROPPED
begin
bit do_ready_to_end ; // bit used for ready_to_end iterations
// OVM semantic: don't end until objection raised or stop request
if (phase_done.get_objection_total(top) ||
m_use_ovm_run_semantic && m_imp.get_name() == "run") begin
if (!phase_done.m_top_all_dropped)
phase_done.wait_for(UVM_ALL_DROPPED, top);
`UVM_PH_TRACE("PH/TRC/EXE/ALLDROP","PHASE EXIT ALL_DROPPED",this,UVM_DEBUG)
end
else begin
if (m_phase_trace) `UVM_PH_TRACE("PH/TRC/SKIP","No objections raised, skipping phase",this,UVM_LOW)
end
wait_for_self_and_siblings_to_drop() ;
do_ready_to_end = 1;
//--------------
// READY_TO_END:
//--------------
while (do_ready_to_end) begin
uvm_wait_for_nba_region(); // Let all siblings see no objections before traverse might raise another
`UVM_PH_TRACE("PH_READY_TO_END","PHASE READY TO END",this,UVM_DEBUG)
m_ready_to_end_count++;
if (m_phase_trace)
`UVM_PH_TRACE("PH_READY_TO_END_CB","CALLING READY_TO_END CB",this,UVM_HIGH)
state_chg.m_prev_state = m_state;
m_state = UVM_PHASE_READY_TO_END;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
if (m_imp != null)
m_imp.traverse(top,this,UVM_PHASE_READY_TO_END);
uvm_wait_for_nba_region(); // Give traverse targets a chance to object
wait_for_self_and_siblings_to_drop();
do_ready_to_end = (m_state == UVM_PHASE_EXECUTING) && (m_ready_to_end_count < max_ready_to_end_iter) ; //when we don't wait in task above, we drop out of while loop
end
end
// TIMEOUT
begin
if (this.get_name() == "run") begin
if (top.phase_timeout == 0)
wait(top.phase_timeout != 0);
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/TO_WAIT", $sformatf("STARTING PHASE TIMEOUT WATCHDOG (timeout == %t)", top.phase_timeout), this, UVM_HIGH)
`uvm_delay(top.phase_timeout)
if ($time == `UVM_DEFAULT_TIMEOUT) begin
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/TIMEOUT", "PHASE TIMEOUT WATCHDOG EXPIRED", this, UVM_LOW)
foreach (m_executing_phases[p]) begin
if ((p.phase_done != null) && (p.phase_done.get_objection_total() > 0)) begin
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/TIMEOUT/OBJCTN",
$sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(), p.phase_done.convert2string()),
this,
UVM_LOW)
end
end
`uvm_fatal("PH_TIMEOUT",
$sformatf("Default timeout of %0t hit, indicating a probable testbench issue",
`UVM_DEFAULT_TIMEOUT))
end
else begin
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/TIMEOUT", "PHASE TIMEOUT WATCHDOG EXPIRED", this, UVM_LOW)
foreach (m_executing_phases[p]) begin
if ((p.phase_done != null) && (p.phase_done.get_objection_total() > 0)) begin
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/TIMEOUT/OBJCTN",
$sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(), p.phase_done.convert2string()),
this,
UVM_LOW)
end
end
`uvm_fatal("PH_TIMEOUT",
$sformatf("Explicit timeout of %0t hit, indicating a probable testbench issue",
top.phase_timeout))
end
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/EXE/3","PHASE EXIT TIMEOUT",this,UVM_DEBUG)
end // if (this.get_name() == "run")
else begin
wait (0); // never unblock for non-run phase
end
end // if (m_phase_trace)
join_any
disable fork;
end
join // guard
end
end
m_executing_phases.delete(this);
//---------
// JUMPING:
//---------
// If jump_to() was called then we need to kill all the successor
// phases which may still be running and then initiate the new
// phase. The return is necessary so we don't start new successor
// phases. If we are doing a forward jump then we want to set the
// state of this phase's successors to UVM_PHASE_DONE. This
// will let us pretend that all the phases between here and there
// were executed and completed. Thus any dependencies will be
// satisfied preventing deadlocks.
// GSA TBD insert new jump support
if (m_phase_type == UVM_PHASE_NODE) begin
if(m_premature_end) begin
if(m_jump_phase != null) begin
state_chg.m_jump_to = m_jump_phase;
`uvm_info("PH_JUMP",
$sformatf("phase %s (schedule %s, domain %s) is jumping to phase %s",
get_name(), get_schedule_name(), get_domain_name(), m_jump_phase.get_name()),
UVM_MEDIUM);
end
else begin
`uvm_info("PH_JUMP",
$sformatf("phase %s (schedule %s, domain %s) is ending prematurely",
get_name(), get_schedule_name(), get_domain_name()),
UVM_MEDIUM);
end
#0; // LET ANY WAITERS ON READY_TO_END TO WAKE UP
if (m_phase_trace)
`UVM_PH_TRACE("PH_END","ENDING PHASE PREMATURELY",this,UVM_HIGH)
end
else begin
// WAIT FOR PREDECESSORS: // WAIT FOR PREDECESSORS:
// function phases only
if (task_phase == null)
m_wait_for_pred();
end
//-------
// ENDED:
//-------
// execute 'phase_ended' callbacks
if (m_phase_trace)
`UVM_PH_TRACE("PH_END","ENDING PHASE",this,UVM_HIGH)
state_chg.m_prev_state = m_state;
m_state = UVM_PHASE_ENDED;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
if (m_imp != null)
m_imp.traverse(top,this,UVM_PHASE_ENDED);
#0; // LET ANY WAITERS WAKE UP
//---------
// CLEANUP:
//---------
// kill this phase's threads
state_chg.m_prev_state = m_state;
if(m_premature_end) m_state = UVM_PHASE_JUMPING;
else m_state = UVM_PHASE_CLEANUP ;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
if (m_phase_proc != null) begin
m_phase_proc.kill();
m_phase_proc = null;
end
#0; // LET ANY WAITERS WAKE UP
if (phase_done != null)
phase_done.clear();
end
//------
// DONE:
//------
m_premature_end = 0 ;
if(m_jump_fwd || m_jump_bkwd) begin
if(m_jump_fwd) begin
clear_successors(UVM_PHASE_DONE,m_jump_phase);
end
m_jump_phase.clear_successors();
end
else begin
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/DONE","Completed phase",this,UVM_LOW)
state_chg.m_prev_state = m_state;
m_state = UVM_PHASE_DONE;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
m_phase_proc = null;
#0; // LET ANY WAITERS WAKE UP
end
#0; // LET ANY WAITERS WAKE UP
if (phase_done != null)
phase_done.clear();
//-----------
// SCHEDULED:
//-----------
if(m_jump_fwd || m_jump_bkwd) begin
void'(m_phase_hopper.try_put(m_jump_phase));
m_jump_phase = null;
m_jump_fwd = 0;
m_jump_bkwd = 0;
end
// If more successors, schedule them to run now
else if (m_successors.size() == 0) begin
top.m_phase_all_done=1;
end
else begin
// execute all the successors
foreach (m_successors[succ]) begin
if(succ.m_state < UVM_PHASE_SCHEDULED) begin
state_chg.m_prev_state = succ.m_state;
state_chg.m_phase = succ;
succ.m_state = UVM_PHASE_SCHEDULED;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(succ, state_chg))
#0; // LET ANY WAITERS WAKE UP
void'(m_phase_hopper.try_put(succ));
if (m_phase_trace)
`UVM_PH_TRACE("PH/TRC/SCHEDULED",{"Scheduled from phase ",get_full_name()},succ,UVM_LOW)
end
end
end
endtask
class uvm_build_phase extends uvm_topdown_phase;
virtual function void exec_func(uvm_component comp, uvm_phase phase);
comp.build_phase(phase);
endfunction
local static uvm_build_phase m_inst;
static const string type_name = "uvm_build_phase";
static function uvm_build_phase get();
if(m_inst == null)
m_inst = new();
return m_inst;
endfunction
protected function new(string name="build");
super.new(name);
endfunction
virtual function string get_type_name();
return type_name;
endfunction
endclass
virtual class uvm_topdown_phase extends uvm_phase;
...
endclass
function void uvm_phase::add(uvm_phase phase,
uvm_phase with_phase=null,
uvm_phase after_phase=null,
uvm_phase before_phase=null);
uvm_phase new_node, begin_node, end_node, tmp_node;
uvm_phase_state_change state_chg;
if (phase == null)
`uvm_fatal("PH/NULL", "add: phase argument is null")
if (with_phase != null && with_phase.get_phase_type() == UVM_PHASE_IMP) begin
string nm = with_phase.get_name();
with_phase = find(with_phase);
if (with_phase == null)
`uvm_fatal("PH_BAD_ADD",
{"cannot find with_phase '",nm,"' within node '",get_name(),"'"})
end
if (before_phase != null && before_phase.get_phase_type() == UVM_PHASE_IMP) begin
string nm = before_phase.get_name();
before_phase = find(before_phase);
if (before_phase == null)
`uvm_fatal("PH_BAD_ADD",
{"cannot find before_phase '",nm,"' within node '",get_name(),"'"})
end
if (after_phase != null && after_phase.get_phase_type() == UVM_PHASE_IMP) begin
string nm = after_phase.get_name();
after_phase = find(after_phase);
if (after_phase == null)
`uvm_fatal("PH_BAD_ADD",
{"cannot find after_phase '",nm,"' within node '",get_name(),"'"})
end
if (with_phase != null && (after_phase != null || before_phase != null))
`uvm_fatal("PH_BAD_ADD",
"cannot specify both 'with' and 'before/after' phase relationships")
if (before_phase == this || after_phase == m_end_node || with_phase == m_end_node)
`uvm_fatal("PH_BAD_ADD",
"cannot add before begin node, after end node, or with end nodes")
// If we are inserting a new "leaf node"
if (phase.get_phase_type() == UVM_PHASE_IMP) begin
uvm_task_phase tp;
new_node = new(phase.get_name(),UVM_PHASE_NODE,this);
new_node.m_imp = phase;
begin_node = new_node;
end_node = new_node;
// The phase_done objection is only required
// for task-based nodes
if ($cast(tp, phase)) begin
if (new_node.get_name() == "run") begin
new_node.phase_done = uvm_test_done_objection::get();
end
else begin
new_node.phase_done = uvm_objection::type_id::create({phase.get_name(), "_objection"});
end
end
end
// We are inserting an existing schedule
else begin
begin_node = phase;
end_node = phase.m_end_node;
phase.m_parent = this;
end
// If 'with_phase' is us, then insert node in parallel
/*
if (with_phase == this) begin
after_phase = this;
before_phase = m_end_node;
end
*/
// If no before/after/with specified, insert at end of this schedule
if (with_phase == null && after_phase == null && before_phase == null) begin
before_phase = m_end_node;
end
if (m_phase_trace) begin
uvm_phase_type typ = phase.get_phase_type();
`uvm_info("PH/TRC/ADD_PH",
{get_name()," (",m_phase_type.name(),") ADD_PHASE: phase=",phase.get_full_name()," (",
typ.name(),", inst_id=",$sformatf("%0d",phase.get_inst_id()),")",
" with_phase=", (with_phase == null) ? "null" : with_phase.get_name(),
" after_phase=", (after_phase == null) ? "null" : after_phase.get_name(),
" before_phase=", (before_phase == null) ? "null" : before_phase.get_name(),
" new_node=", (new_node == null) ? "null" : {new_node.get_name(),
" inst_id=",
$sformatf("%0d",new_node.get_inst_id())},
" begin_node=", (begin_node == null) ? "null" : begin_node.get_name(),
" end_node=", (end_node == null) ? "null" : end_node.get_name()},UVM_DEBUG)
end
// INSERT IN PARALLEL WITH 'WITH' PHASE
if (with_phase != null) begin
begin_node.m_predecessors = with_phase.m_predecessors;
end_node.m_successors = with_phase.m_successors;
foreach (with_phase.m_predecessors[pred])
pred.m_successors[begin_node] = 1;
foreach (with_phase.m_successors[succ])
succ.m_predecessors[end_node] = 1;
end
// INSERT BEFORE PHASE
else if (before_phase != null && after_phase == null) begin
begin_node.m_predecessors = before_phase.m_predecessors;
end_node.m_successors[before_phase] = 1;
foreach (before_phase.m_predecessors[pred]) begin
pred.m_successors.delete(before_phase);
pred.m_successors[begin_node] = 1;
end
before_phase.m_predecessors.delete();
before_phase.m_predecessors[end_node] = 1;
end
// INSERT AFTER PHASE
else if (before_phase == null && after_phase != null) begin
end_node.m_successors = after_phase.m_successors;
begin_node.m_predecessors[after_phase] = 1;
foreach (after_phase.m_successors[succ]) begin
succ.m_predecessors.delete(after_phase);
succ.m_predecessors[end_node] = 1;
end
after_phase.m_successors.delete();
after_phase.m_successors[begin_node] = 1;
end
// IN BETWEEN 'BEFORE' and 'AFTER' PHASES
else if (before_phase != null && after_phase != null) begin
if (!after_phase.is_before(before_phase)) begin
`uvm_fatal("PH_ADD_PHASE",{"Phase '",before_phase.get_name(),
"' is not before phase '",after_phase.get_name(),"'"})
end
// before and after? add 1 pred and 1 succ
begin_node.m_predecessors[after_phase] = 1;
end_node.m_successors[before_phase] = 1;
after_phase.m_successors[begin_node] = 1;
before_phase.m_predecessors[end_node] = 1;
if (after_phase.m_successors.exists(before_phase)) begin
after_phase.m_successors.delete(before_phase);
before_phase.m_successors.delete(after_phase);
end
end // if (before_phase != null && after_phase != null)
// Transition nodes to DORMANT state
if (new_node == null)
tmp_node = phase;
else
tmp_node = new_node;
state_chg = uvm_phase_state_change::type_id::create(tmp_node.get_name());
state_chg.m_phase = tmp_node;
state_chg.m_jump_to = null;
state_chg.m_prev_state = tmp_node.m_state;
tmp_node.m_state = UVM_PHASE_DORMANT;
`uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(tmp_node, state_chg))
endfunction
Currently I just went to this step to understand the steps of uvm_phase. I need to to go to more details on these functions/tasks to understand more.
No comments:
Post a Comment