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.

diagram
[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 starts
systemverilog
class 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
endclass

Key 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

systemverilog
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
diagram
[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 effect

Config 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.

diagram
[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.