Skip to content

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.

The four categories of the UVM architecture checklist: construction, configuration, connectivity, phasingConstruction + hierarchyfactory create (not new), uvm_component_utils, correct parenting, zero-time buildfactory create (not new), uvm_component_utils, correct parenting, zero-time buildConfigurationconfig objects, scoped set before get, guarded gets, no hardcoded pathsconfig objects, scoped set before get, guarded gets, no hardcoded pathsConnectivity (TLM)connect_phase wiring, every analysis port subscribed, driver-sequencer wireconnect_phase wiring, every analysis port subscribed, driver-sequencer wirePhasing + controlbuild/connect/run placement, objection discipline, no premature cross-level refsbuild/connect/run placement, objection discipline, no premature cross-level refs
Figure 1 — the four categories of the UVM architecture checklist. Construction and hierarchy: factory creation, registration, parenting, and zero-time build. Configuration: config objects, scoped set/get, guarded gets, no hardcoded paths. Connectivity: connections in connect_phase, every analysis port subscribed, the driver-sequencer wire, independent monitors. Phasing: correct build/connect/run placement, objection discipline, no premature cross-level references. Each item maps to a methodology rule from the curriculum, so a failed item is also an index into the module that explains why.

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, never new. Routing construction through the factory is what makes a component's type overridable; a single new silently 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 a type_id so the factory can create and override it; without it type_id::create cannot resolve.
  • Every component is parented correctly (create("name", this) passes this). 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) (and super for other phases) is called in overridden phase methods, so base-class setup is not skipped.
  • build_phase does only construction and configuration — zero-time. No waiting, driving, or connecting in build; time-consuming work belongs in run_phase, connections in connect_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_db sets.
  • Every config_db::set is scoped to reach its target, relative to this. A wrong scope means the child's get misses it and the component comes up unconfigured; the path must address the intended subtree.
  • Every config_db::get is 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.
  • set happens before get (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, not build_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_port is connected to the sequencer's seq_item_export (and guarded on is_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_phase constructs and fetches config, connect_phase wires, run_phase does 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_phase stays 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 for connect_phase.
  • end_of_elaboration_phase checks 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.