Part 2 · Phases & Lifecycle · Intermediate

end_of_elaboration Checks: Topology Audit and Validation

Canonical end_of_elaboration usage — print_topology, connection audits, agent counts, and bottom-up structural validation.

Last structural checkpoint

end_of_elaboration_phase is the final build-time audit . Every component exists, every connect call has run — now validate that the assembly matches intent.

systemverilog
function void end_of_elaboration_phase(uvm_phase phase);
  super.end_of_elaboration_phase(phase);

  // Global topology audit — do this at test or env level
  `uvm_info("ELAB", "=== Component Topology ===", UVM_LOW)
  uvm_top.print_topology();

  // Local structural validation
  if (cfg.num_agents != agents.size())
    `uvm_error("ELAB", $sformatf("expected %0d agents, have %0d",
      cfg.num_agents, agents.size()))

  if (cfg.enable_scoreboard && sb == null)
    `uvm_fatal("ELAB", "scoreboard enabled in cfg but sb not built")
endfunction
diagram
[PHASE][UVM] end_of_elaboration bottom-up flow

leaf components validate local state
   agents check drv/sqr presence vs active mode
     env checks agent count, sb/cov presence
       test prints global topology summary

Key takeaways

  • print_topology is the single highest-value elaboration diagnostic.

  • Assert cfg-driven counts match built topology.

  • Bottom-up order lets children self-check before parent aggregates.

Common pitfalls

  • Only printing topology without asserting invariants.

  • Fatal on optional components disabled in cfg.

  • Doing topology print at UVM_NONE — lost in noisy logs.


Validation patterns

Layer checks from agent internals up to env integration for maximum debug signal.

Agent-level checks

systemverilog
class my_agent extends uvm_agent;
  function void end_of_elaboration_phase(uvm_phase phase);
    super.end_of_elaboration_phase(phase);
    if (mon == null)
      `uvm_fatal("ELAB", $sformatf("%s: monitor not built", get_full_name()))
    if (cfg.is_active == UVM_ACTIVE && (drv == null || sqr == null))
      `uvm_fatal("ELAB", $sformatf("%s: active but drv/sqr missing", get_full_name()))
    if (cfg.is_active == UVM_PASSIVE && (drv != null || sqr != null))
      `uvm_warning("ELAB", $sformatf("%s: passive but drv/sqr exist", get_full_name()))
  endfunction
endclass
diagram
[PHASE] agent elaboration checklist

[ ] mon exists always
[ ] active  drv and sqr exist
[ ] passive  drv and sqr null
[ ] vif handle non-null
[ ] cfg object non-null

Env-level aggregation

  • Compare cfg.agent_en bitmap against agents[] membership.

  • Verify scoreboard imps exist when analysis connect expected.

  • Check virtual sequencer handles for every active agent.

systemverilog
function void end_of_elaboration_phase(uvm_phase phase);
  super.end_of_elaboration_phase(phase);
  foreach (cfg.agent_en[i])
    if (cfg.agent_en[i] && !agents.exists(i))
      `uvm_error("ELAB", $sformatf("agent[%0d] enabled but missing", i))
  if (v_sqr.tx_sqr == null && agents[TX].cfg.is_active == UVM_ACTIVE)
    `uvm_error("ELAB", "v_sqr.tx_sqr not mapped")
endfunction
diagram
[PHASE][UVM] elaboration severity guide

uvm_info   topology print, audit banners
uvm_warning  suspicious but non-fatal (passive with drv)
uvm_error  mismatch worth failing regression
uvm_fatal  guaranteed broken run if continued

Common pitfalls

  • Duplicating same assert in end_of_elaboration and connect — pick one owner.

  • Error flood from loop asserts — summarize counts instead.

  • Checking TLM bind internals — UVM does not expose connect graph easily.