Part 2 · Phases & Lifecycle · Intermediate
Why build_phase Is Top-Down
The ordering guarantee behind top-down build: parent existence, child creation, config propagation, and override registration timing.
The dependency chain
A child component needs a parent handle at construction time. UVM enforces that every parent's build_phase completes its create() calls before any child's build_phase begins.
[PHASE][UVM] top-down traversal
Step 1: test.build_phase()
creates env
Step 2: env.build_phase()
creates agent, sb, cov
Step 3: agent.build_phase()
creates drv, mon, sqr
Step 4: drv.build_phase() (leaf — no children)
Step 5: mon.build_phase()
Step 6: sqr.build_phase()
Rule: parent N must finish build before child N+1 startsclass my_test extends uvm_test;
my_env env;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// test exists; env parent is 'this'
env = my_env::type_id::create("env", this);
// env.build_phase now runs before test build_phase returns
endfunction
endclassKey takeaways
Top-down build exists so parents can create children with valid parent pointers.
Config set by the test reaches children because the test builds first.
Factory overrides in the test apply before the env creates agents.
Common pitfalls
Assuming sibling agents build left-to-right — only parent-before-child is guaranteed.
Creating components in run_phase to 'fix' build order — wrong phase entirely.
Expecting children to exist when the parent's build_phase has not called create() yet.
Top-down enables config and overrides
The same top-down order that enables create() also enables config_db propagation and factory override registration at the test level.
Override-before-create pattern
class err_test extends base_test;
function void build_phase(uvm_phase phase);
// test builds first (top-down) — register override BEFORE env exists
apb_driver::type_id::set_type_override(err_apb_driver::get_type());
super.build_phase(phase); // base creates env → agent → driver via factory
endfunction
endclass[PHASE][UVM] override timing
test.build_phase (top-down entry):
1) set_type_override(err_driver)
2) super.build_phase → creates env
3) env.build_phase → creates agent
4) agent.build_phase → create("drv") picks err_driver
If override comes AFTER super.build_phase:
original driver already created — override has no effectConfig push timing
Test sets cfg in build_phase before creating env.
Env gets cfg and passes slices to agents via config_db::set.
Agents get cfg in their own build_phase from the path the env set.
[PHASE] config flow (build-time)
top module:
uvm_config_db::set(null, "*", "vif", vif)
test.build_phase:
uvm_config_db::set(this, "env*", "cfg", cfg)
env.build_phase:
uvm_config_db::get(this, "", "cfg", cfg)
uvm_config_db::set(this, "agt*", "cfg", agt_cfg)
agent.build_phase:
uvm_config_db::get(this, "", "cfg", cfg)
uvm_config_db::get(this, "", "vif", vif)Common pitfalls
Setting config after the target component already built — get returns false.
Relying on constructor side effects instead of build_phase ordering.
Fighting top-down order by manually calling child build from parent constructor.