| // |
| //---------------------------------------------------------------------- |
| // Copyright 2007-2011 Mentor Graphics Corporation |
| // Copyright 2007-2010 Cadence Design Systems, Inc. |
| // Copyright 2010 Synopsys, 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. |
| //---------------------------------------------------------------------- |
| |
| //------------------------------------------------------------------------------ |
| // |
| // Class: uvm_task_phase |
| // |
| //------------------------------------------------------------------------------ |
| // Base class for all task phases. |
| // It forks a call to <uvm_phase::exec_task()> |
| // for each component in the hierarchy. |
| // |
| // The completion of the task does not imply, nor is it required for, |
| // the end of phase. Once the phase completes, any remaining forked |
| // <uvm_phase::exec_task()> threads are forcibly and immediately killed. |
| // |
| // By default, the way for a task phase to extend over time is if there is |
| // at least one component that raises an objection. |
| //| class my_comp extends uvm_component; |
| //| task main_phase(uvm_phase phase); |
| //| phase.raise_objection(this, "Applying stimulus") |
| //| ... |
| //| phase.drop_objection(this, "Applied enough stimulus") |
| //| endtask |
| //| endclass |
| // |
| // |
| // There is however one scenario wherein time advances within a task-based phase |
| // without any objections to the phase being raised. If two (or more) phases |
| // share a common successor, such as the <uvm_run_phase> and the |
| // <uvm_post_shutdown_phase> sharing the <uvm_extract_phase> as a successor, |
| // then phase advancement is delayed until all predecessors of the common |
| // successor are ready to proceed. Because of this, it is possible for time to |
| // advance between <uvm_component::phase_started> and <uvm_component::phase_ended> |
| // of a task phase without any participants in the phase raising an objection. |
| // |
| |
| virtual class uvm_task_phase extends uvm_phase; |
| |
| |
| // Function: new |
| // |
| // Create a new instance of a task-based phase |
| // |
| function new(string name); |
| super.new(name,UVM_PHASE_IMP); |
| endfunction |
| |
| |
| // Function: traverse |
| // |
| // Traverses the component tree in bottom-up order, calling <execute> for |
| // each component. The actual order for task-based phases doesn't really |
| // matter, as each component task is executed in a separate process whose |
| // starting order is not deterministic. |
| // |
| virtual function void traverse(uvm_component comp, |
| uvm_phase phase, |
| uvm_phase_state state); |
| phase.m_num_procs_not_yet_returned = 0; |
| m_traverse(comp, phase, state); |
| endfunction |
| |
| function void m_traverse(uvm_component comp, |
| uvm_phase phase, |
| uvm_phase_state state); |
| string name; |
| uvm_domain phase_domain =phase.get_domain(); |
| uvm_domain comp_domain = comp.get_domain(); |
| |
| if (comp.get_first_child(name)) |
| do |
| m_traverse(comp.get_child(name), phase, state); |
| while(comp.get_next_child(name)); |
| |
| if (m_phase_trace) |
| `uvm_info("PH_TRACE",$sformatf("topdown-phase phase=%s state=%s comp=%s comp.domain=%s phase.domain=%s", |
| phase.get_name(), state.name(), comp.get_full_name(),comp_domain.get_name(),phase_domain.get_name()), |
| UVM_DEBUG) |
| |
| if (phase_domain == uvm_domain::get_common_domain() || |
| phase_domain == comp_domain) begin |
| case (state) |
| UVM_PHASE_STARTED: begin |
| comp.m_current_phase = phase; |
| comp.m_apply_verbosity_settings(phase); |
| comp.phase_started(phase); |
| end |
| UVM_PHASE_EXECUTING: begin |
| uvm_phase ph = this; |
| if (comp.m_phase_imps.exists(this)) |
| ph = comp.m_phase_imps[this]; |
| ph.execute(comp, phase); |
| end |
| UVM_PHASE_READY_TO_END: begin |
| comp.phase_ready_to_end(phase); |
| end |
| UVM_PHASE_ENDED: begin |
| comp.phase_ended(phase); |
| comp.m_current_phase = null; |
| end |
| default: |
| `uvm_fatal("PH_BADEXEC","task phase traverse internal error") |
| endcase |
| end |
| |
| endfunction |
| |
| |
| // Function: execute |
| // |
| // Fork the task-based phase ~phase~ for the component ~comp~. |
| // |
| virtual function void execute(uvm_component comp, |
| uvm_phase phase); |
| |
| fork |
| begin |
| uvm_sequencer_base seqr; |
| process proc; |
| |
| // reseed this process for random stability |
| proc = process::self(); |
| proc.srandom(uvm_create_random_seed(phase.get_type_name(), comp.get_full_name())); |
| |
| phase.m_num_procs_not_yet_returned++; |
| |
| if ($cast(seqr,comp)) |
| seqr.start_phase_sequence(phase); |
| |
| exec_task(comp,phase); |
| |
| phase.m_num_procs_not_yet_returned--; |
| |
| end |
| join_none |
| |
| endfunction |
| endclass |
| |