Part 2 · Phases & Lifecycle · Intermediate
Pre-Time-Zero Contract: What Is Legal Before run_phase
Strict contract for function phases before run — zero time, frozen structure, allowed diagnostics, and common violations.
The zero-time boundary
From build through start_of_simulation, simulation time must not advance . These function phases set up structure and documentation; run_phase is the first common task phase that may consume time.
[PHASE][UVM] function phase timeline (0 time)
build_phase ──────────── construct tree
connect_phase ────────── wire TLM
end_of_elaboration ───── validate tree
start_of_simulation ──── document intent
───────────────────────────────────────── time = 0, structure frozen
run_phase ────────────── time may advance// ILLEGAL in any pre-run function phase:
function void start_of_simulation_phase(uvm_phase phase);
super.start_of_simulation_phase(phase);
#(100ns); // ERROR — consumes time
wait(vif.rst_n == 1'b1); // ERROR — waits for event
seq.start(env.v_sqr); // ERROR — run_phase activity
endfunctionKey takeaways
Function phases before run are zero-time by contract.
Structure is frozen after build — connect only wires it.
Stimulus, waits, and delays belong exclusively to run_phase.
Common pitfalls
Waiting for PLL lock in start_of_simulation.
Forking threads in end_of_elaboration that consume time.
Using run_phase callbacks registered to fire before time 0.
Contract enforcement in review
Use this checklist in code review and CI lint rules to catch phase violations before they reach regressions.
Per-phase allowed operations
[PHASE][UVM] pre-run contract matrix
Phase Create Connect Assert Print Wait
─────────────────────────────────────────────────────────────
build_phase YES NO YES YES NO
connect_phase NO YES YES YES NO
end_of_elaboration NO NO YES YES NO
start_of_simulation NO NO YES YES NO
run_phase NO* NO YES YES YES
* run_phase: no new uvm_components — structure frozenMigration guide for violations
Identify #delay or wait in function phase — move to run_phase task.
Identify sequence.start in elaboration — move to run_phase.
Identify create in connect/elaboration — move to build_phase.
Identify pin drive before run — move to driver run_phase or interface init.
Add elaboration assert where violation was masking missing component.
[PHASE] common violation sources
legacy SV testbench init block code copied into start_of_simulation
reset task called from end_of_elaboration "for early readiness"
config randomize after build "to save time"Interface initial blocks may drive static reset — separate from UVM phases.
DUT reset sequencing belongs in driver/monitor run_phase or SV interface.
Document any intentional exception with a comment and review ticket.
Common pitfalls
Assuming pre_run reset is OK because 'hardware needs it'.
Using package init blocks that consume time before UVM phases.
Mixing module initial and UVM phase responsibilities without docs.