Part 2 · Phases & Lifecycle · Intermediate
Why connect_phase Is Bottom-Up
The ordering guarantee behind bottom-up connect: child ports first, parent assembly second, and safe fanout wiring.
Child ports must exist first
A parent connects to child ports. Bottom-up connect ensures every leaf port, export, and imp is initialized before the parent reaches into the subtree.
[PHASE][UVM] bottom-up traversal
Step 1: drv.connect_phase() (leaf — local ports ready)
Step 2: mon.connect_phase()
Step 3: sqr.connect_phase()
Step 4: agent.connect_phase() (wires drv ↔ sqr)
Step 5: sb.connect_phase() (leaf imp ready)
Step 6: env.connect_phase() (wires mon.ap → sb, cov)
Step 7: test.connect_phase() (optional top-level wiring)
Rule: child N must finish connect before parent N-1 startsclass my_agent extends uvm_agent;
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (cfg.is_active == UVM_ACTIVE)
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclassKey takeaways
Bottom-up connect mirrors the dependency direction of TLM binding.
Leaf components expose ports; parents stitch subgraphs together.
Agent connect runs before env connect so agent-internal links are done.
Common pitfalls
Env connect assuming agent-internal drv-sqr link not yet made.
Parent connect running custom child connect out of order.
Expecting sibling connect order among agents — not guaranteed.
Bottom-up enables safe fanout
Analysis fanout from monitor to multiple subscribers requires each imp to exist before the env connects the broadcast port.
Fanout wiring order
class my_env extends uvm_env;
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// agt.mon.ap exists (agent built + agent connect done)
agt.mon.ap.connect(sb.act_imp);
agt.mon.ap.connect(cov.analysis_export);
agt.mon.ap.connect(tlm_fifo.analysis_export);
endfunction
endclass[PHASE][UVM] analysis broadcast model
monitor.ap.write(txn)
├─► scoreboard.imp
├─► coverage.imp
└─► tlm_fifo.imp
Each imp must exist before ap.connect(imp)
Bottom-up connect guarantees imp components initializedVirtual sequencer mapping timing
Virtual sequencer is a component — its build_phase creates it.
Env connect_phase assigns agt.sqr handles to v_sqr fields.
This is handle assignment, not port.connect().
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
v_sqr.tx_sqr = agt_tx.sqr;
v_sqr.rx_sqr = agt_rx.sqr;
endfunction[PHASE] bottom-up + virtual sequencer
1) agt_tx.sqr exists (build)
2) agt_tx.connect wires drv-sqr (bottom-up leaf first)
3) env.connect assigns v_sqr.tx_sqr = agt_tx.sqr
4) virtual sequences can start on v_sqr.tx_sqr in run_phaseCommon pitfalls
Assigning null sequencer handle — active/passive mismatch in build.
Connecting analysis before subscriber imp is built.
Mapping v_sqr in build_phase — sequencers may not exist yet.