Part 2 · Phases & Lifecycle · Intermediate
Ordering Bug Patterns: Build, Connect, Run Placement
Common ordering mistakes — null connect handles, config_db races, TLM wiring before create, and run_phase activity in build.
Build/connect ordering
UVM guarantees build_phase runs top-down and connect_phase runs bottom-up. Violations usually come from testbench code fighting the schedule — not from UVM itself.
[PHASE][UVM] ordering guarantees vs common breaks
GUARANTEED:
parent build before child build (top-down)
all builds done before any connect (bottom-up connect)
COMMON BREAKS:
config_db::set after child already read in build
connect to component never created (active/passive branch)
get() in connect for handle set in sibling's buildPattern: null handle in connect_phase
// BUG: agent not created when is_active==UVM_PASSIVE
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (cfg.is_active == UVM_ACTIVE)
driver = driver_c::type_id::create("driver", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
driver.seq_item_port.connect(sequencer.seq_item_export);
// NULL when passive — crash
endfunction// FIX: guard connect
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (driver != null)
driver.seq_item_port.connect(sequencer.seq_item_export);
endfunctionprint_topology shows whether the component exists.
Active/passive create branches are the #1 null-connect cause.
Factory override registered too late — child already built.
Pattern: config_db race
// BUG: child build runs before parent set()
function void build_phase(uvm_phase phase);
super.build_phase(phase); // children build here — child get() fails
uvm_config_db#(int)::set(this, "*", "mode", 1);
endfunction// FIX: set before super.build_phase
function void build_phase(uvm_phase phase);
uvm_config_db#(int)::set(this, "*", "mode", 1);
super.build_phase(phase);
endfunctionSymptom → fix table
Null in connect → component not created; check active/passive branch.
config_db get failed → set() after super.build_phase; reorder.
Override ignored → register before super.build_phase creates target.
TLM no traffic → connect_phase never called super; child ports unbound.
Key takeaways
Null connect = missing create or guarded branch without connect guard.
set() config_db before super.build_phase for child visibility.
print_topology is the fastest build/connect sanity check.
Common pitfalls
Fixing null connect with delay instead of create/guard.
Assuming sibling build order — not guaranteed without explicit config.