Part 2 · Phases & Lifecycle · Intermediate

The Common Phase List: Nine Phases and Their Jobs

The complete list of nine common UVM phases, what each is for, function vs task classification, and typical content per callback.

The nine phases in order

  1. build_phase — construct children via factory; config_db gets (top-down).

  2. connect_phase — TLM port/export/imp wiring (bottom-up).

  3. end_of_elaboration_phase — structural sanity, topology print (bottom-up).

  4. start_of_simulation_phase — banners, last config, arm watchdogs (top-down).

  5. run_phase — time-consuming stimulus and checking (parallel task).

  6. extract_phase — harvest counters, coverage snapshots (bottom-up).

  7. check_phase — evaluate pass/fail predicates (bottom-up).

  8. report_phase — format and print summary (bottom-up).

  9. final_phase — close files, flush DBs (top-down).

diagram
[UVM][PHASE] common list mnemonic

BUILD block (function):
  build -> connect -> end_of_elab -> start_of_sim

RUN block (task):
  run_phase (+ 12 runtime sub-phases in parallel)

CLEANUP block (function):
  extract -> check -> report -> final

Only run_phase and the runtime sub-phases consume simulation time. The other eight are

zero-time function phases.

Key takeaways

  • Memorize the list as three blocks: build, run, cleanup.

  • Each phase has a narrow, well-defined job — mixing jobs breaks methodology.

  • end_of_elaboration is the last safe moment for structural debug prints.

Common pitfalls

  • Driving pins in start_of_simulation — still zero-time; use run_phase.

  • Connecting TLM in extract_phase — far too late.

  • Skipping check_phase because report 'looks fine'.


Typical content per phase

build_phase

systemverilog
function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  if (!uvm_config_db#(my_cfg)::get(this, "", "cfg", cfg))
    `uvm_fatal("NOCFG", "cfg missing")
  mon = my_monitor::type_id::create("mon", this);
  if (cfg.is_active)
    drv = my_driver::type_id::create("drv", this);
endfunction

connect_phase

systemverilog
function void connect_phase(uvm_phase phase);
  super.connect_phase(phase);
  if (cfg.is_active)
    drv.seq_item_port.connect(sqr.seq_item_export);
  mon.ap.connect(scb.analysis_imp);
endfunction

check / report / final

systemverilog
function void check_phase(uvm_phase phase);
  super.check_phase(phase);
  scb.compare_ok();
endfunction

function void report_phase(uvm_phase phase);
  super.report_phase(phase);
  `uvm_info("RPT", $sformatf("checked=%0d errors=%0d",
    scb.checked, scb.errors), UVM_LOW)
endfunction

function void final_phase(uvm_phase phase);
  super.final_phase(phase);
  cov_db.flush();
endfunction
diagram
[PHASE] allowed actions quick reference

build:       create, config get, override setup
connect:     TLM connect, virtual sqr handles
end_of_elab: topology print, structural asserts
start_of_sim: banners, final cfg tweaks
run:         time, events, sequences, objections
extract:     sample counts, coverage grab
check:       pass/fail tests
report:      human-readable summary
final:       file/DB cleanup

Key takeaways

  • If an action's phase is unclear, ask which dependency it satisfies.

  • check aggregates; report presents; final releases resources.

  • run_phase owns all time-consuming behavior.

Common pitfalls

  • Heavy computation in report_phase that should be in extract.

  • Creating components in check_phase when scoreboard needs them earlier.

  • Using final_phase for pass/fail — too late, use check_phase.