UVM
UVM Architecture Checklist
The condensed sign-off list for a UVM testbench's architecture — construction and hierarchy, configuration, TLM connectivity, and phasing — each item the methodology rule it operationalizes, run before declaring an environment structurally sound.
UVM Design Review Checklist · Module 31 · Page 31.1
The final module distills the methodology into actionable checklists — the sign-off lists you actually run before a review. This first one is the UVM architecture checklist: the concrete items to confirm in a testbench's structure — how it is constructed, configured, connected, and phased — before you declare the environment sound. A checklist is not a substitute for understanding (the prior modules built that); it is the operationalization of understanding, so the rules you know are systematically confirmed rather than left to memory under deadline pressure. It is organized into categories — construction and hierarchy, configuration, connectivity, and phasing — each a small set of must-confirm items.
1. Why a Checklist: Operationalizing Understanding
You have learned why a UVM environment is built the way it is; a checklist ensures you apply it every time. Under deadline pressure, even experienced engineers forget an item — a component built with new, an unconnected analysis port, a config that never reaches its target — and a checklist makes the review systematic: every environment gets the same pass, turning "I think it is right" into "I confirmed each item." The architecture checklist catches the structural mistakes — the ones that make an environment build the wrong tree, leave a scoreboard silently unconnected, or break factory overrides — before review or simulation does.
2. Construction and Hierarchy
The first category is how the component tree comes into existence — the items that keep it overridable, correctly named, and zero-time.
- Every component is created with
type_id::create, nevernew. Routing construction through the factory is what makes a component's type overridable; a singlenewsilently breaks factory overrides. The single most common structural mistake. - Every component (and object) is registered with
`uvm_component_utils/`uvm_object_utils. Registration gives the class atype_idso the factory can create and override it; without ittype_id::createcannot resolve. - Every component is parented correctly (
create("name", this)passesthis). The parent chain plus the name produces the hierarchical path that configuration, messaging, and lookup all use; a wrong parent misplaces the component in the address space. super.build_phase(phase)(andsuperfor other phases) is called in overridden phase methods, so base-class setup is not skipped.build_phasedoes only construction and configuration — zero-time. No waiting, driving, or connecting in build; time-consuming work belongs inrun_phase, connections inconnect_phase.
3. Configuration
The second category is how configuration reaches its targets — the items that keep it delivered, scoped, and non-silent.
- Configuration travels through config objects, not scattered individual sets. A bundled config object is cohesive, composes hierarchically, and has fewer string-matched paths to get wrong than dozens of individual
config_dbsets. - Every
config_db::setis scoped to reach its target, relative tothis. A wrong scope means the child'sgetmisses it and the component comes up unconfigured; the path must address the intended subtree. - Every
config_db::getis guarded (if (!...get(...)) uvm_fatal(...)). An unguarded failing get leaves the handle null and crashes later at first use, far from the cause; guard it so a missing config is reported at build. - No hardcoded absolute hierarchical paths in config scoping. Hardcoding a path ties the component to one location and kills reuse; use relative or wildcarded scopes so the component works wherever it is placed.
sethappens beforeget(top-down ordering is honored). A parent sets a child's config and the child gets it in its later build; relying on the top-down order, not manual sequencing, is what makes configure-from-above work.
4. Connectivity (TLM)
The third category is how the components are wired — the items that keep connections made, in the right phase, and not silently absent.
- All connections are made in
connect_phase, notbuild_phase. Connect runs after the whole tree is built, so every port and export exists; connecting in build races against not-yet-built components. - Every analysis port has its subscriber connected. An unconnected analysis port is legal and silent — the monitor writes into the void and the scoreboard checks nothing, passing green. Confirm each monitor's port reaches its scoreboard and coverage.
- The driver's
seq_item_portis connected to the sequencer'sseq_item_export(and guarded onis_active). This is the handshake wire; a passive agent has no driver/sequencer, so the connect must be guarded or it is a null-handle crash. - The monitor reconstructs transactions independently and broadcasts on its analysis port. A monitor that forwards the driver's item instead of observing the pins makes the scoreboard check intent against itself; independence is what makes the check meaningful.
- Required TLM ports (put/get/imp) are connected. Unlike analysis ports, required ports fatal at end-of-elaboration if unconnected — but confirm them, because the failure mode is opposite (loud, not silent).
5. Phasing and Control
The fourth category is timing and control — the items that keep work in the right phase and the run phase correctly bracketed.
- Phase placement is correct:
build_phaseconstructs and fetches config,connect_phasewires,run_phasedoes all timed driving and observing. Misplaced work — driving in build, connecting in build, constructing in run — is a phase-misuse. - Objections are raised and dropped correctly. The test raises an objection so
run_phasestays alive, runs stimulus, and drops it when done; a missing raise ends the test in zero time (a green pass that did nothing), a missing drop hangs it. - No cross-level references to not-yet-built grandchildren in
build_phase. A parent builds before its children, so a grandchild does not exist yet; cross-level wiring waits forconnect_phase. end_of_elaboration_phasechecks the assembled topology where useful. The phase for confirming the built tree is correct before stimulus starts (e.g.,print_topology, connection checks).
6. Common Misconceptions
7. Sign-off Insight
8. Interview Questions
That every component is created through the factory with type_id::create rather than new, because the factory is what makes a component's type overridable, and a single new silently breaks that. When you create with type_id::create, the factory returns the registered type by default or an overridden type if a test registered one, so the whole environment is specializable from above without editing it — swap in an error-injecting driver, an extended monitor, a derived item, purely by registering an override. If a component is built with new, construction never consults the factory, so any override of that component is silently ignored, and the classic symptom is a registered override that does nothing, which is baffling until you find the new at the creation site. It tops the checklist because it is both the most common structural mistake and one whose failure mode is silent and confusing, and because it underpins everything the factory provides, which is the whole reuse and specialization story of UVM. The check is concrete: scan every component construction for new and confirm it is type_id::create with the parent passed, and confirm the class is registered with uvm_component_utils so it has a type_id. The understanding to convey is that factory creation is the load-bearing item — it keeps the environment overridable — and that new is the structural mistake to never make, which is exactly what an interviewer wants to hear named first.
Because an unconnected analysis port is legal and silent: analysis ports are designed to tolerate zero subscribers, so a monitor whose port is never connected just writes into the void with no error, the scoreboard's write is never called, and the test passes green having checked nothing. That silence is the danger. Unlike a required port — a put or get — which fatals at end of elaboration if left unconnected, an analysis port produces no warning, no error, no indication that the connection is missing. So a forgotten monitor-to-scoreboard connection does not fail loudly; it produces a green result from a scoreboard that received no transactions and therefore compared nothing, which looks exactly like a passing test. You can ship a testbench that verifies nothing and never know. The checklist item is therefore to confirm, explicitly, that every analysis port reaches its intended subscriber — every monitor's port connected to the scoreboard and any coverage collector — and to never trust a green scoreboard you have not confirmed is connected, ideally by printing the topology or checking the scoreboard actually received transactions. The contrast with required ports is worth stating: required ports fail loud, analysis ports fail silent, so they demand opposite vigilance. The understanding to convey is the silent-tolerance of analysis ports and the green-passing-check-of-nothing failure mode, which is why connection confirmation is a must-check item rather than something you assume worked.
It confirms that each kind of work happens in its correct phase — construction and configuration in build_phase, connections in connect_phase, and all timed driving and observing in run_phase — and that the run phase is correctly bracketed by objections. Phase placement is the core check: build_phase is zero-time and only constructs children through the factory and fetches configuration, so any time-consuming work or pin driving there is a misuse; connect_phase runs after the whole tree is built and is where ports are wired, so connections belong there and not in build where children may not exist yet; and run_phase is the only phase that consumes simulation time, where drivers drive, monitors sample, and sequences run. The checklist also confirms objection discipline: the test raises an objection so run_phase stays alive while stimulus runs and drops it when done, because the phase ends when the objection count returns to zero — a missing raise ends the test in zero time having driven nothing, often a green pass that hides the problem, and a missing drop hangs the test forever. Finally it confirms no cross-level references to not-yet-built grandchildren in build, since a parent builds before its children, so such wiring waits for connect. The understanding to convey is the build-construct, connect-wire, run-drive placement plus the raise-stimulus-drop objection bracket, and that misplaced work or a missing objection are the phasing mistakes the checklist catches.
A checklist does not replace understanding; it operationalizes it — it turns the methodology rules you understand into a repeatable pass that systematically confirms them, so they are applied every time rather than left to memory under pressure. You need the understanding to use the checklist well: each item is meaningful only because you know why it matters — why new breaks overrides, why an unconnected analysis port is silent, why a config get must be guarded — and that understanding is what lets you recognize a subtle violation that a literal reading might miss and what tells you how to fix a failed item. What the checklist adds is consistency and coverage of the known mistakes: even experienced engineers forget an item under deadline pressure, and a checklist makes every environment get the same systematic pass, turning I think it is right into I confirmed each item, and scaling that consistency across a team. Its limits are worth stating honestly: it operationalizes understanding rather than substituting for it, it covers known mistakes not novel ones, it complements verification rather than replacing it, and it demands honest checking — a checklist run carelessly proves nothing. So the relationship is that understanding is the foundation and the checklist is the operational layer on top, making the application of that understanding reliable and repeatable. The understanding to convey is operationalization-not-replacement, with the checklist as a consistency tool that depends on and applies understanding rather than standing in for it.
I check the highest-impact structural items first: that every component is created with type_id::create and registered with the utils macro, that every analysis port is connected to its subscriber, that configuration is delivered and guarded, and that phase placement and objections are correct. I start with factory creation because a single new breaks overrides silently and is the most common structural defect, so I scan construction sites for new versus create and confirm registration. Next I trace the connectivity, especially the analysis ports, because an unconnected one is a silent green-passing failure — I confirm each monitor's port reaches the scoreboard and coverage, since this is where an environment can appear to work while checking nothing. Then configuration: I check that config is delivered through config objects with scopes that reach their targets and that gets are guarded, because an unguarded missing config crashes far from its cause. Then phasing: construction in build, wiring in connect, timed work in run, and the test bracketing run with a raised-and-dropped objection, because a missing objection produces a zero-time green pass. I also look at active/passive correctness and whether the agents are built for reuse, which the reuse checklist covers in depth. The order is by impact and by silent-failure risk: the items whose violation is both common and quiet — factory creation and analysis-port connections — come first, because they are the ones that let a broken environment look fine. The understanding to convey is a prioritized, impact-ordered pass that front-loads the common silent failures, which is how an experienced engineer reviews an unfamiliar environment efficiently.
9. Summary
The UVM architecture checklist operationalizes the curriculum's understanding into a repeatable pre-review pass that confirms a testbench's structure is sound — turning "I think it is right" into "I confirmed each item." It is organized into four categories. Construction and hierarchy: factory creation (type_id::create, never new — the top item), registration with the utils macro, correct parenting, super calls, and a zero-time build_phase. Configuration: delivery through config objects, scopes that reach targets relative to this, guarded gets, no hardcoded paths, and honored top-down ordering. Connectivity: connections in connect_phase, every analysis port subscribed (the silent-failure item), the guarded driver-sequencer wire, independent monitors, and connected required ports. Phasing and control: build/connect/run placement, the raise-stimulus-drop objection bracket, and no premature cross-level references.
The disciplines: run it before every review and after every change (edits reintroduce structural bugs); check the highest-impact items explicitly (factory creation and analysis-port connections are the most common silent defects); and treat each item as an index into the curriculum (a failed item points at the module explaining why). A checklist is the right tool because architectural correctness is a many-independent-items problem prone to omission under pressure — it makes you consistent, not smarter, and scales quality across a team — with the honest limits that it operationalizes rather than replaces understanding, covers known not novel mistakes, and demands honest checking.
10. What Comes Next
You can now sign off a testbench's structure; next, signing off its reusability:
Next — Reuse Checklist: the architecture checklist confirmed the environment is built correctly; the reuse checklist confirms it can be reused — configuration-driven behavior, active/passive capability, factory construction, freedom from environmental assumptions, and monitor purity — the properties that let an agent drop into a new environment or integration level unchanged.