UVM
end_of_elaboration_phase
The zero-time phase after connect where the complete, connected structure first exists — topology inspection, connection validation, and shifting structural-bug detection left.
UVM Phasing · Module 5 · Page 5.4
The Engineering Problem
build_phase constructed the tree and connect_phase wired it. end_of_elaboration_phase is the phase that runs next — and it occupies a uniquely useful position: it is the first point at which the complete, fully-connected structure exists, and simulation has not yet started. The tree is whole, every connection is made, and no time has passed. That combination is what makes the phase valuable.
The engineering point is what that vantage point is for. Because the entire connected structure exists but nothing has run, end_of_elaboration_phase is the natural place to inspect the environment (print the topology), validate it (confirm required components and connections are present), and do any final adjustments that need the fully-wired structure. It is, literally, the end of elaboration — the boundary between building/wiring and running. And it solves a real, expensive problem: structural mistakes (a missing connection, an absent component) that would otherwise surface as baffling run-time symptoms can instead be caught here, at zero time, before a single cycle runs. This chapter is about that vantage point and how to use it.
What is
end_of_elaboration_phase, why is its position — after the structure is fully built and connected, before simulation starts — uniquely useful, and how do you use it to inspect and validate the environment before the run?
Motivation — why a phase between connect and run
A dedicated phase at the end of elaboration, after everything is wired, earns its place:
- It's the first moment the whole connected structure exists. During build, the tree is still being constructed; during connect, it's being wired (and bottom-up, so not all connections exist until connect completes). Only at
end_of_elaboration_phaseis the environment both fully built and fully connected — the first point you can inspect or validate the finished structure. - It catches structural bugs at zero time, before the run. A forgotten connection or a missing component produces, at run time, a silent or baffling symptom (a scoreboard that sees nothing, a null handle deep in a sequence). A check here — confirming the connection or component exists — surfaces the same bug instantly, at elaboration, before any cycle runs. That moves an expensive run-time debug to a cheap elaboration-time assertion.
- It's the home of topology inspection.
uvm_top.print_topology()dumps the complete, connected hierarchy, andend_of_elaboration_phaseis exactly when that picture is meaningful — the structure is final. Reviewing it once here confirms the environment is shaped as intended. - It's the last chance for structure-dependent setup. Any final adjustment that needs the fully-wired environment (rare, but real) belongs here — after connect (so connections exist) and before the run (so it's in place before behaviour starts).
The motivation, in one line: end_of_elaboration_phase exists because there is genuine value in a zero-time checkpoint after the environment is fully built and connected and before it runs — for inspecting, validating, and finalising the complete structure, and especially for catching structural mistakes before they become run-time mysteries.
Mental Model
Hold end_of_elaboration_phase as the pre-flight inspection:
end_of_elaboration_phaseis the pre-flight walk-around before the engines start. The aircraft has been assembled (build_phase) and all its systems connected (connect_phase) — it is complete and wired, sitting on the tarmac, but it has not yet moved (the run hasn't started). This is the moment the crew walks around the finished aircraft and checks it: is every part present, is every connection made, does the configuration look right? Nothing is being built or wired now — that's done; this is inspection and validation of the finished, static machine, the last opportunity to catch a problem on the ground rather than discovering it in the air. Once the walk-around passes, the engines start (the run phase begins) and the aircraft is committed.
So in an end_of_elaboration_phase, you don't build or wire (that's done) — you look and check: print the topology to see the finished structure, assert that required components and connections exist, and make any last structure-dependent adjustment. It's the ground inspection before the flight, valuable precisely because the machine is complete but not yet committed.
Visual Explanation — end_of_elaboration in the phase sequence
end_of_elaboration_phase sits after build and connect — the point where the structure is both complete and wired — and before start_of_simulation and the run. Its position defines its purpose.
The phase's purpose follows directly from its position. By the time end_of_elaboration_phase runs, both prior construction phases are complete: build_phase made every component exist, and connect_phase made every connection. So this is the earliest moment the environment is a finished, wired whole — and since run_phase hasn't started, it's a static whole you can examine without anything changing underneath you. That's why it hosts inspection (the topology is final and meaningful), validation (you can assert the finished structure is correct), and finalisation (any last adjustment that needed the connected tree). It is the deliberate checkpoint between elaboration (build + connect, making the environment) and simulation (the run, exercising it) — which is exactly what its name says.
RTL / Simulation Perspective — inspecting and validating the structure
A typical end_of_elaboration_phase does no construction or wiring — it checks the finished environment: print the topology, and assert that the components and connections you depend on are present.
class my_env extends uvm_env;
`uvm_component_utils(my_env)
my_agent agent; my_scoreboard sb;
function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
// INSPECT: the whole tree is built AND connected now — print the finished hierarchy
uvm_top.print_topology();
// VALIDATE: confirm the structure is as required (catch missing pieces at zero time)
if (agent == null) `uvm_fatal("ELAB", "agent was not built");
if (sb == null) `uvm_fatal("ELAB", "scoreboard was not built");
// (e.g., assert a required handle/connection is in place before the run starts)
// FINAL structure-dependent adjustment that needed the connected tree (rare) ...
endfunction
endclassNotice what this phase does not do: no create, no connect, no waiting or driving. By end_of_elaboration_phase, construction and wiring are finished, so the work here is inspection and validation. uvm_top.print_topology() dumps the complete, connected hierarchy — meaningful precisely because the structure is now final — letting you confirm at a glance that the environment is shaped as intended. The uvm_fatal guards turn structural assumptions into checked invariants: if a component you depend on wasn't built (or a connection wasn't made), you find out here, at zero time, with a clear message — rather than discovering it as a null handle or a silent scoreboard cycles into the run. This is the phase's signature use: validate the finished structure before committing to the run, and (rarely) make a last adjustment that required the fully-wired tree. Like build and connect, it's a zero-time function, so nothing time-consuming belongs here.
Verification Perspective — the value of validating before the run
The deepest value of end_of_elaboration_phase is shifting structural-bug detection left — from run time (expensive, symptomatic) to elaboration time (cheap, direct). A structural mistake checked here is caught before a single cycle runs.
The two paths are the same bug with very different costs. Without an elaboration check, a missing connection or absent component doesn't announce itself — it lies dormant until the run phase, then manifests as a symptom distant from its cause: a scoreboard that receives nothing all run long, or a null handle deep inside a sequence, which you then debug backward to discover a forgotten connect(). With a check in end_of_elaboration_phase — asserting the connection or component is present — the same mistake is reported at its source, at zero time, with a message that names exactly what's missing, before any cycle runs. This is "shift-left" for structure: because end_of_elaboration_phase is the first point the finished environment exists and the last before it runs, it's the natural gate at which to validate that the structure is correct. A few assertions here turn a class of expensive run-time mysteries into instant elaboration-time errors.
Runtime / Execution Flow — the last zero-time step before the run
end_of_elaboration_phase is the final part of elaboration — the zero-time construction sequence — after which start_of_simulation and then the run begin. Mapping the boundary clarifies what's finished and what's about to start.
The boundary is the lesson. Everything up to and including end_of_elaboration_phase is elaboration — the zero-time process of bringing the environment into existence, wiring it, and validating it. Everything after (the run) is simulation — where time advances and behaviour happens. end_of_elaboration_phase is the last elaboration phase, the final moment to act on the finished structure before the commitment of the run; start_of_simulation_phase (the next chapter) is a thin final banner just before time starts. This is why the phase is named what it is: it marks the end of elaboration. Practically, it means anything that must be true of the structure — every component present, every connection made, the topology correct — should be ensured (or asserted) by the end of this phase, because once the run starts, you're committed to whatever was built and wired. Make the environment through elaboration; check it at its end; then run.
Waveform Perspective — the last sliver before time advances
On a timeline, end_of_elaboration_phase is the final zero-time sliver of elaboration, right before the run region where pins move — the last static moment of the environment before it's exercised.
end_of_elaboration is the last zero-time elaboration sliver before the run
10 cyclesThe phase track shows EOE as the last cell of the zero-time elaboration region, immediately before RUN where the pins finally move. This placement is the whole story: end_of_elaboration_phase is the final static instant of the environment — fully built, fully wired, validated — before the run commits it to motion. No pin moves during elaboration because these are zero-time function phases that only construct, wire, and check; all activity is in the run that follows. The waveform reinforces the boundary from Figure 3: a thin elaboration sliver (build/connect/eoe) at the start, then a wide run span. end_of_elaboration_phase is the last moment in that opening sliver — the place to look at and validate the finished machine before the engines start.
DebugLab — the forgotten connection that ran for a week
A missing connection found after days of run-time debugging — an elaboration check would have caught it instantly
An SoC environment ran for days of regression with a scoreboard that, it was eventually noticed, had checked nothing — a cross-block monitor-to-scoreboard connection had never been made. The bug surfaced only as a run-time symptom (zero transactions checked, discovered late), and tracing it back through the run to the missing connect() took an expensive debugging session. The environment built and ran "fine"; it just silently verified less than intended.
A missing connection that was never validated at elaboration. The cross-block connection was simply forgotten in connect_phase, and because nothing checked the structure before the run, the gap stayed invisible until its run-time symptom was noticed and chased back:
connect_phase: (the cross-block mon→sb connection was never written) ← the bug
run_phase: scoreboard receives nothing → "0 checked" — a symptom far from the cause
debug: days tracing the run-time symptom back to the missing connect()
prevention: in end_of_elaboration_phase, assert the connection exists:
if (!sb.is_connected_to(target_mon)) `uvm_fatal("ELAB","mon→sb not connected");
→ reported at ZERO TIME, at the source, before the run ever startsThe connection bug itself is ordinary (a forgotten connect()); what made it expensive was that nothing validated the structure at elaboration, so it could only be discovered through its run-time consequences. end_of_elaboration_phase is exactly the place a structural check would have caught it — at zero time, naming the missing connection, before the run.
The tell is a structural bug discovered late, via a run-time symptom, that a static check could have surfaced immediately. Diagnose (and prevent) by validating structure at elaboration:
- Ask whether the structure was validated before the run. If a missing connection or component is only found by its run-time effect, there was no elaboration-time check. The fix is to add one in
end_of_elaboration_phase. - Review the topology at end_of_elaboration.
uvm_top.print_topology()shows the finished, connected hierarchy; a missing component or an obviously wrong shape is visible here, before the run. - Assert critical connections and components. Anything the verification depends on (a scoreboard's input connection, a required agent) should be asserted present in
end_of_elaboration_phase, so its absence is a zero-time fatal, not a run-time mystery.
Validate the finished structure at the end of elaboration:
- Add structural checks in
end_of_elaboration_phase. Assert that required components exist and that critical connections are made — turning structural assumptions into checked, zero-time invariants reported before the run. - Inspect the topology once. Print and review
uvm_top.print_topology()at elaboration to confirm the environment is shaped and connected as intended; it's the cheapest structural sanity check available. - Shift structural detection left. Treat
end_of_elaboration_phaseas the gate where "is the environment built correctly?" is answered — so structural bugs are caught at elaboration, not chased through the run.
The one-sentence lesson: a structural bug (a missing connection or component) is cheap to catch at elaboration and expensive to chase at run time — validate the finished, connected structure in end_of_elaboration_phase, so the mistake is a zero-time fatal at its source rather than a run-time symptom far away.
Common Mistakes
- Not validating the structure at elaboration. Skipping structural checks means missing connections or components surface only as run-time symptoms — expensive to trace. Assert required components and connections in
end_of_elaboration_phase. - Doing construction or wiring here.
buildconstructs andconnectwires;end_of_elaboration_phaseis for inspection, validation, and final adjustment — not for creating components or making connections (those belong in their phases). - Time-consuming work in end_of_elaboration. It's a zero-time function phase; waiting or driving belongs in
run_phase. Only structural inspection/validation/finalisation here. - Ignoring
print_topology. The complete, connected hierarchy is meaningful exactly here; not reviewing it once forgoes the cheapest structural sanity check. - Forgetting
super.end_of_elaboration_phase. As with other phase overrides, callsuperto preserve base-class behaviour. - Expecting it to be top-down. Like connect and cleanup,
end_of_elaboration_phaseis bottom-up; don't assume a parent's elaboration work is done when a child's runs.
Senior Design Review Notes
Interview Insights
end_of_elaboration_phase is the zero-time phase that runs after connect_phase and before simulation starts, and it's used for inspecting, validating, and making final adjustments to the complete, connected environment. Its defining property is its position: by the time it runs, build_phase has constructed every component and connect_phase has made every connection, so this is the first point at which the structure is both fully built and fully wired — and since the run hasn't started, it's a static whole you can examine without anything changing. So the typical work here is: print the topology (uvm_top.print_topology()) to inspect the finished hierarchy; assert that required components and connections are present, to catch structural mistakes; and perform any last structure-dependent setup that needed the connected tree. It does not build or wire (those are done) and does not consume time (it's a function phase). Its greatest practical value is shifting structural-bug detection left — a missing connection or component asserted here is caught at zero time, with a clear message, before the run, instead of surfacing later as a baffling run-time symptom.
Exercises
- Use the phase. Write an
end_of_elaboration_phasefor an env that prints the topology and asserts its agent and scoreboard exist, with fatal messages naming any missing piece. - Shift left. A missing monitor-to-scoreboard connection was found after a long run-time debug. Write the check you'd add in
end_of_elaboration_phaseto catch it at zero time, and explain why this phase is the right place. - Phase boundaries. State what is finished by the time
end_of_elaboration_phaseruns (from build and connect) and what hasn't started yet, and why that combination makes it ideal for inspection. - Right job. For each, name the correct phase: (a) create the agents; (b) connect the monitor to the scoreboard; (c) print the complete topology and assert connections; (d) drive stimulus.
Summary
end_of_elaboration_phaseis the zero-time, bottom-up phase afterconnect_phase— the first point at which the structure is both fully built and fully connected, with simulation not yet started. It is the boundary between elaboration and simulation.- Its purpose is inspection, validation, and final structure-dependent setup: print the complete topology (
uvm_top.print_topology()), assert that required components and connections are present, and make any last adjustment that needed the connected tree. - Its greatest value is shifting structural-bug detection left: a missing connection or component asserted here is caught at zero time, at its source, before the run — instead of surfacing as an expensive run-time symptom (a silent scoreboard, a null handle).
- It does not construct (that's build), wire (that's connect), or consume time (it's a function phase); the work is to look at and check the finished, static environment before the run commits it.
- The durable rule of thumb: treat
end_of_elaboration_phaseas the pre-flight inspection — the last zero-time moment when the environment is complete and wired but not yet running — and use it to print the topology and assert the structure is correct, so structural mistakes are caught at elaboration, not chased through the run.
Next — start_of_simulation_phase: the structure is built, wired, and validated; one thin zero-time phase remains before time advances. start_of_simulation_phase is the final pre-run step — typically for announcing configuration and printing banners — the last breath before the run begins.