What are UVM phases and why are they used?
UVM phases are a fixed, ordered execution sequence that every UVM component moves through together, so a testbench built from independently written components still starts up, runs and shuts down in a predictable order. They divide into build-time phases (build, connect, end_of_elaboration, start_of_simulation), the time-consuming run phase, and cleanup phases (extract, check, report, final). UVM stands for Universal Verification Methodology, the Accellera-standardised SystemVerilog class library now published as IEEE 1800.2.
Why UVM needs phases at all
A UVM testbench is assembled from components that different engineers wrote at different times — an agent from a VIP vendor, a scoreboard from the verification lead, a coverage collector from an intern. None of them knows about the others. Yet every one of them has to be constructed before any of them can be connected, and every one has to be connected before any of them starts driving traffic.
Phases are the mechanism that guarantees this. Instead of each component running its own new()-and-go logic, the UVM base class library calls a fixed set of virtual methods on every component in the hierarchy, in a defined order, and does not move on to the next phase until every component has finished the current one. Your job as a component author is simply to override the phase methods you care about and leave the rest alone.
This is also why phase-order bugs are among the most common failures a beginner hits: putting a uvm_config_db::get() in the wrong phase, or building a child component after the connect phase has already run, produces a null-handle crash that looks mysterious until you know the ordering rules.
The nine UVM phases in order
UVM defines nine standard phases. Eight of them are functions — they execute in zero simulation time — and exactly one, run_phase, is a task that consumes time.
Phase order and traversal direction
1. build_phase — function, top-down
2. connect_phase — function, bottom-up
3. end_of_elaboration_phase — function, bottom-up
4. start_of_simulation_phase — function, bottom-up
5. run_phase — task, runs in parallel across all components
6. extract_phase — function, bottom-up
7. check_phase — function, bottom-up
8. report_phase — function, bottom-up
9. final_phase — function, top-down
1. build_phase — top-down
The only phase that runs top-down, and it has to be. A parent must exist and must have created its children before those children can build their children. This is where you call type_id::create() for every sub-component, retrieve configuration with uvm_config_db::get(), and set configuration for children with uvm_config_db::set().
Because it is top-down, a parent’s set() is always visible to a child’s get(). Reverse that assumption and you get a null handle.
2. connect_phase — bottom-up
By the time connect runs, the entire component tree exists. This phase is bottom-up because a parent needs its children’s ports to already be constructed before it can wire them together. All TLM port/export/analysis connections belong here — monitor.item_collected_port.connect(scoreboard.analysis_export) and the like. Never create components here.
3. end_of_elaboration_phase — bottom-up
The last chance to inspect or adjust the assembled testbench before simulation starts. Typical uses: calling uvm_top.print_topology(), checking that a required virtual interface was actually set, and issuing a fatal if the configuration is inconsistent. Catching a missing interface here produces a clear error message instead of a null-pointer dereference thousands of cycles later.
4. start_of_simulation_phase — bottom-up
Runs immediately before time zero advances. Use it for banner printing, displaying the resolved configuration, and setting initial values that must be visible from the first clock edge.
5. run_phase — the only time-consuming phase
Every component’s run_phase task is forked and runs concurrently. This is where drivers pull items from the sequencer and wiggle pins, monitors sample the interface, and the test body starts sequences. Because it is a task, it must be declared as one:
task run_phase(uvm_phase phase);
phase.raise_objection(this, "starting main stimulus");
my_seq = base_sequence::type_id::create("my_seq");
my_seq.start(env.agent.sequencer);
phase.drop_objection(this, "stimulus complete");
endtask6–8. extract, check and report — bottom-up
extract_phase gathers final state out of components — remaining scoreboard queue depths, final coverage numbers. check_phase asserts on that state: an unempty scoreboard queue at the end of a test is a real failure and this is where you flag it. report_phase prints the summary. Keeping these three separate matters because check should never have to re-derive data that extract already collected.
9. final_phase — top-down
The last thing that runs. Close file handles, flush logs, release any resource you allocated outside the UVM factory.
The run-phase sub-phases (the twelve runtime phases)
UVM also defines a set of finer-grained runtime sub-phases that execute in parallel with run_phase. They exist so that independently written components can agree on when during the test their activity belongs, without any of them knowing about the others:
- pre_reset_phase — anything that must happen before reset is asserted.
- reset_phase — assert and hold reset; drivers put the interface into its idle state.
- post_reset_phase — reset released, waiting for the DUT to settle.
- pre_configure_phase — prepare configuration data.
- configure_phase — program the DUT’s registers, typically over a register-model frontdoor.
- post_configure_phase — wait for the configuration to take effect.
- pre_main_phase — final readiness checks.
- main_phase — the actual stimulus. This is where most sequences run.
- post_main_phase — let the last transactions drain.
- pre_shutdown_phase, shutdown_phase, post_shutdown_phase — drain queues, wait for outstanding responses, allow the DUT to reach a quiescent state.
A practical rule: use run_phase or the sub-phases, not both, for the same activity. Mixing them is legal but makes the objection bookkeeping very hard to reason about. Most production testbenches pick one convention and hold to it.
Phase objections: how UVM knows when to stop
Because run_phase is the only time-consuming phase, UVM needs a way to decide when it is finished. That mechanism is the objection. Any component can raise an objection to say “do not end this phase yet”; the phase ends when the total objection count for that phase drops back to zero.
task main_phase(uvm_phase phase);
phase.raise_objection(this);
// stimulus that must complete before the phase can end
repeat (100) begin
seq = write_read_sequence::type_id::create("seq");
seq.start(env.agent.sequencer);
end
phase.drop_objection(this);
endtaskTwo failure modes account for most objection bugs:
- Nobody raises an objection. The phase ends at time zero and the test “passes” instantly with no stimulus. If your test finishes suspiciously fast, check this first.
- Somebody raises and never drops. The simulation hangs until the timeout fires. Setting
phase.phase_done.set_drain_time(this, 100ns)gives outstanding transactions a defined window to complete rather than papering over the problem with an arbitrarily long test.
The convention that avoids most trouble: raise and drop objections in the test (or in the sequence that owns the end-of-test decision), not in every driver and monitor. Components that merely react to traffic should not be voting on when the test ends.
Common UVM phase interview questions
Why is build_phase top-down while connect_phase is bottom-up?
Construction has to proceed from parent to child, because a child cannot exist until its parent creates it. Connection has to proceed from child to parent, because a parent can only wire up ports that its children have already constructed.
Which UVM phase consumes simulation time?
Only run_phase and its runtime sub-phases. All other phases are functions and execute in zero time.
What happens if no component raises an objection in run_phase?
The phase’s objection count is already zero, so UVM ends the phase immediately and the simulation finishes at time zero without running any stimulus.
Can components be created in connect_phase?
They should not be. The hierarchy is considered complete once build_phase finishes; creating components later means their own build_phase never runs and their configuration is never applied.
What is the UVM full form?
Universal Verification Methodology — a standardised SystemVerilog class library and methodology for building reusable, constrained-random verification environments, standardised by Accellera and published as IEEE 1800.2.
For the wider verification picture, see our ASIC Design Verification Hub and the complete UVM roadmap for freshers.
Boost Your VLSI Placement Preparation
UVM phasing is a core part of our verification training programs. Acquire hands-on experience under the guidance of expert mentors at ChipXpert.
Share your question in comments or talk to our mentor team for batch guidance.
Need Fee, Duration, or Demo Class Details?
Talk to our admin team for the latest batch plan and career guidance.
Contact Admin TeamAsk the Admin Team
Drop your basic question in comments: eligibility, prerequisites, tools, fee range, and placement support.
Our team reviews and responds regularly.

