Skip to content

UVM

Scope Rules

How a config_db get resolves against multiple sets — glob scope matching, walking the hierarchy, and the precedence rule (higher-in-hierarchy setter wins, then last set) that lets a test override an env's defaults.

Configuration Database · Module 7 · Page 7.3

The Engineering Problem

The previous chapter (Module 7.2) assumed a set's scope simply "reaches" the getter, and left the precise rules for later. This chapter is that precision. In a real testbench, many set calls exist — an env sets defaults for its agents, a base test sets some values, a derived test overrides others — and a single get may match several of them. Two questions then decide everything: which sets match a given get (the matching rules — globs and hierarchy), and when several match, which one wins (the precedence rule).

The problem is that the precedence rule is not what most engineers assume. Coming from CSS or routing tables, people expect the most specific pattern to win — a precise path should beat a broad wildcard. UVM does not work that way. Its precedence is by the position of the setting component in the hierarchy: a set from a component higher in the tree (closer to the root — the test) beats a set from a component lower down (the env), regardless of how specific each pattern is, and only among sets of equal hierarchical precedence does the last set win. This single rule is the entire reason the config DB works as a top-down control mechanism — it's why a test can override an env's defaults — but it surprises anyone expecting specificity to decide. This chapter is the matching and precedence rules: how a get's path is matched against set globs, how the hierarchy is walked, and the precedence order that resolves conflicts.

How does a config_db get resolve when multiple set calls match it — how do glob scopes match a getter's path, and what is the precedence rule (higher-in-hierarchy setter wins, then last set) that decides which set takes effect?

Motivation — why precedence is by hierarchy, not specificity

The precedence rule looks arbitrary until you see what it's for. The config DB exists so that a higher-level component can configure a lower-level one it doesn't directly control (Module 7.1). That goal dictates the precedence rule:

  • Override must flow top-down, so the higher setter must win. The whole point is that a test can override what an env configures by default. The test is higher than the env. So a set from the test must beat a set from the env — precedence has to favor the component higher in the hierarchy, or override would be impossible.
  • Specificity can't decide, because the env's settings are often more specific. An env typically sets precise, per-instance configuration (agent0, agent1); a test often sets a broad default (*). If specificity won, the env's precise settings would beat the test's broad override — the exact opposite of what's needed. So precedence must ignore specificity.
  • Timing can't be the primary rule, because top-down build sets the test first. build_phase is top-down: the test's set runs before the env's. If last-wins were primary, the env (running later) would override the test — again backwards. So order can only be a tiebreaker among equal-hierarchy sets, never the primary rule.
  • Hence: hierarchy first, order second. The only rule consistent with top-down override is "the higher-in-hierarchy setter wins; among equals, the last set wins." Everything about config DB precedence follows from making top-down override work.
  • Matching is separate from precedence. Before precedence even applies, a set must match the get — its scope glob must cover the getter's path, and field and type must agree. Precedence only adjudicates among the sets that matched.

The motivation, in one line: config DB precedence is by hierarchy (not specificity, not primarily order) because its job is to let higher components override lower ones — the rule is the mechanism of top-down control, not an arbitrary tie-break.

Mental Model

Hold scope rules as a chain of command delivering orders by area:

Sets are orders addressed to an area; a get obeys all orders addressed to its location but follows the one from the highest-ranking officer — not the most detailed order. Each set is an order pinned to a notice board, addressed to an area (a glob like "everyone under env" or "the whole base"). A component reading configuration (get) looks at its own location and collects every order whose area covers it. If only one covers it, it obeys that. If several do, it does not pick the most detailed or most specific order — it obeys the order from the officer highest in the chain of command. The general (the test, at the top) outranks the captain (the env, lower down), so the general's order stands even if the captain's order was more specific to this exact spot. Only when two orders come from officers of the same rank does the most recent one win. This is why a general can override a captain's standing orders across the whole unit with one broad command — rank beats detail — and it's why a soldier who assumes "the most specific order wins" will follow the wrong one.

So resolving a get is two steps: collect every set whose area covers you (matching), then obey the highest-ranking among them (precedence by hierarchy), breaking ties by recency. The misconception to unlearn is "specific beats broad" — in UVM, high beats low, full stop.

Visual Explanation — resolving a get against multiple sets

A get resolves in two stages: first match (which sets' globs cover this getter's path), then rank (among matches, which setter is highest in the hierarchy). The diagram shows both stages for a getter that several sets match.

A get collects all matching sets, then selects by precedence: higher-in-hierarchy setter wins, then last setmatch (globs covering the path) → rank (highest setter wins, then last)match (globs covering the path) → rank (highest setter wins, then last)1Getter: env.agent0.drv gets 'cfg'lookup path = uvm_test_top.env.agent0.drv, field 'cfg'.2Match: collect every set whose glob covers the pathenv's set('env.agent0.drv'), base test's set('*'), derived test'sset('*') all match.3Rank by setter hierarchy (not specificity)test (higher) outranks env (lower) — so a test set wins over theenv's precise set.4Winner: derived test's setamong the two equal-precedence test sets, the later (derived) wins.Env's specific set loses.
Figure 1 — a get resolves by match then rank. The getter (env.agent0.drv reading 'cfg') is matched against every set. Three sets match its path: the env's specific set (env.agent0.drv), the base test's broad set (*), and the derived test's broad set (*). Matching collects all three; precedence then ranks them by the setting component's hierarchy position — the test is higher than the env, so a test set wins over the env's set despite being less specific, and between the two test sets the later (derived test) wins. The env's precise set loses to the test's broad set: high beats specific.

The two stages are independent and must not be conflated. Matching (step 2) is purely about coverage: does this set's scope glob, as a pattern, cover the getter's full hierarchical path? Every set whose glob matches — whether it's a precise path like env.agent0.drv or a broad wildcard like * — is collected into the candidate set. Specificity plays no role here; a glob either covers the path or it doesn't. Ranking (step 3) then decides among the matched candidates by precedence, and precedence is the position of the setting component in the hierarchy: the test sits above the env, so any set issued from the test outranks any set issued from the env — even though the env's set named the exact driver and the test's set was a blanket *. Between the two test sets (equal precedence, both from test-level), the last one registered wins. The outcome that surprises people is right there in the figure: the env's precise env.agent0.drv set loses to the test's broad * set, because high beats specific. Internalize the two-stage shape — match by coverage, rank by hierarchy — and config DB resolution stops being mysterious.

RTL / Simulation Perspective — globs and the precedence outcome in code

The matching and precedence rules are visible directly in code: the scope strings (with their wildcards) determine matching, and which component calls set determines precedence.

multiple sets matching one get — globs and precedence
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── ENV sets a precise, per-instance default (LOWER in the hierarchy) ──
class my_env extends uvm_env;
  function void build_phase(uvm_phase phase);
    // scope glob = "uvm_test_top.env.agent0.drv" — precise, matches exactly one driver
    uvm_config_db#(my_cfg)::set(this, "agent0.drv", "cfg", env_default_cfg);
    ...
  endfunction
endclass
 
// ── TEST sets a broad override (HIGHER in the hierarchy) ──
class my_test extends uvm_base_test;
  function void build_phase(uvm_phase phase);
    // scope glob = "uvm_test_top.*" — broad wildcard, matches every component
    uvm_config_db#(my_cfg)::set(this, "*", "cfg", test_cfg);   // wins everywhere — test is higher
    super.build_phase(phase);     // builds env → env's set runs AFTER, but is LOWER precedence
  endfunction
endclass
 
// ── DRIVER gets — resolves to test_cfg, NOT env_default_cfg ──
//   lookup path "uvm_test_top.env.agent0.drv" is matched by BOTH sets above:
//     env's  "uvm_test_top.env.agent0.drv"  (precise) — matches, but LOWER precedence
//     test's "uvm_test_top.*"               (broad)   — matches, and HIGHER precedence → WINS
uvm_config_db#(my_cfg)::get(this, "", "cfg", cfg);   // cfg == test_cfg

The code makes both rules concrete. Globs: the env's set(this, "agent0.drv", ...) builds the scope uvm_test_top.env.agent0.drv — a literal that matches exactly one driver; the test's set(this, "*", ...) builds uvm_test_top.* — a wildcard that matches every component below the test. (UVM scope strings use glob-style wildcards: * matches any sequence of characters, ? matches a single character.) Both globs match the driver's lookup path uvm_test_top.env.agent0.drv, so both are candidates. Precedence: the winner is the test's set — not because it's broader, but because the test is higher in the hierarchy than the env. Notice the timing too: because build is top-down, the test's set actually runs before the env's set (which runs inside super.build_phase()), yet the test still wins — proving precedence is by hierarchy, not by who set last. The env's precise, later set loses to the test's broad, earlier set. This is the top-down override working exactly as designed: the test reshapes configuration the env established defaults for, without the env knowing.

Verification Perspective — the precedence rule, precisely

The precedence rule has two levels — hierarchy first, order second — and getting the order of these right is what separates correct mental models from the specificity misconception.

Precedence decision flow: compare setter hierarchy, then order; specificity is never usedyesno / equallast winswrong modelMultiple setsmatch the getIs one setter higher in the hierarchy than the others?Is one setterhigher in thehierarchythan the…Yes → the higher setter's set wins (specificity irrelevant)Yes → the highersetter's setwins(specificity…No (top candidates set from the same level): which was set last?No (topcandidatesset from thesame level):…The last setregistered wins(order is thetiebreaker)Misconception: pick the most specific pattern — UVM never does thisMisconception:pick the mostspecific pattern— UVM never doe…
Figure 2 — the precedence decision among matching sets. Given all the sets that match a get, compare their setting components' hierarchy positions. If one setter is higher (closer to the root) than the others, its set wins — specificity is irrelevant. Only if the top candidates were set from the same hierarchy level does the tiebreaker apply: the last set registered wins. The misconception (dashed) is choosing the most specific pattern — UVM never does this. Hierarchy first, order second, specificity never.

The rule is a strict two-level comparison. Level one — hierarchy: among all the sets that matched, compare the positions of the components that issued them. If one setting component is higher in the tree (closer to the root) than the rest, its set wins outright, and nothing else matters — not how specific its pattern was, not when it ran. This is the level that delivers top-down override. Level two — order (tiebreaker only): the order comparison applies only when the leading candidates were set from the same hierarchy level (for example, a base test and a derived test both setting from test scope, or two sets from the same component). In that case, the last set registered wins. The thing the rule never does is compare specificity: a precise path has no inherent advantage over a wildcard. The dashed "misconception" branch — "the most specific pattern wins" — is the model to actively unlearn, because it's intuitive (CSS, route tables, firewall rules all work that way) and it's wrong for UVM. The discipline is to reason about precedence by asking, in order: who is higher? then, only if tied, who set last? — and never who is more specific?

Runtime / Execution Flow — walking the hierarchy on a get

When a component calls get, the database resolves it by walking the matching sets and applying precedence — a process that happens at the moment of the get, against whatever sets exist at that time.

On a get: form lookup path, collect matching sets, select by precedence, return the valueform path → collect matching sets → select by precedence → returnform path → collect matching sets → select by precedence → return1Form the lookup pathgetter's full name + field — e.g. uvm_test_top.env.agent0.drv /'cfg'.2Collect matching setsscan registered sets; keep those whose glob covers the path andwhose field + type agree.3Select by precedencehighest-in-hierarchy setter wins; among equals, the last set wins.Specificity unused.4Return the selected valuethe winning set's value is written into the getter's variable; getreturns 1.
Figure 3 — how a get is resolved at the moment it's called. The component forms its lookup path (its full hierarchical name + field). The database scans the registered sets, collecting those whose scope glob matches the path and whose field and type agree. Among the matches it selects by precedence (highest setter, then last). The selected value is returned. Because this happens when the get runs, only sets registered before the get are visible — which top-down build guarantees for parent/test sets.

The resolution is a scan-and-select that runs at the moment of the get. First the getter forms its lookup path — its own full hierarchical name combined with the field it's asking for. The database then scans all registered sets and collects the candidates: every set whose scope glob covers that path and whose field name and type T agree (matching, from Module 7.2, gates entry — a set that doesn't match on field or type isn't even a candidate). Among the collected candidates it selects the winner by precedence — highest-in-hierarchy setter, then last-set tiebreaker — and returns that value. The crucial runtime consequence is that resolution sees only the sets that exist when the get runs: a set registered after this get won't be considered. Top-down build is what makes this safe for the normal pattern — a parent or test set in build_phase is registered before the child's build_phase get runs, so it's visible. But it also means a set registered later (say in run_phase) can't retroactively affect a get that already resolved in build_phase. Precedence decides among visible sets; visibility is decided by timing. Both must line up for a set to win a get.

Waveform Perspective — the higher setter wins regardless of order

The defining behavior — the higher-in-hierarchy set wins even though it ran first — is a timing/precedence interplay, and a timeline makes it concrete.

Test set (higher, earlier) beats env set (lower, later) — precedence is by hierarchy

10 cycles
Test set (higher, earlier) beats env set (lower, later) — precedence is by hierarchytest build_phase: test's set('*') registered FIRST (higher in hierarchy)test build_phase: test…env build_phase: env's set('agent0.drv') registered SECOND (lower)env build_phase: env's…driver get: both match — test's set wins by hierarchy → resolved_cfg = TESTdriver get: both match…run_phase: the driver uses the test's config, not the env'srun_phase: the driver …clkphaseBLDBLDBLDBLDRUNRUNRUNRUNRUNRUNtest_setenv_setgetresolved_cfg----TESTTESTTESTTESTTESTTESTTESTTESTt0t1t2t3t4t5t6t7t8t9
Figure 4 — top-down build registers the test's set first, the env's set second, both during build at zero time. test_set pulses first (test build_phase), env_set pulses second (env build_phase, inside super.build_phase). When the driver's get resolves, both sets match its path, but the winner is the test's (higher in the hierarchy) — resolved_cfg shows TEST, not ENV, even though the env set later. Order did not decide; hierarchy did. The value is then used in run_phase.

The waveform isolates the counter-intuitive part: the winner ran first. The test_set pulse comes before the env_set pulse — because top-down build runs the test's build_phase before the env's. Both sets match the driver's lookup path (the test's * and the env's precise agent0.drv both cover it), so both are candidates when the driver's get resolves. Yet resolved_cfg settles on TEST, not ENV, even though the env's set was registered later. If precedence were last-wins, the env would have won — but it doesn't, because precedence is hierarchy-first, and the test is higher. This is the visual proof that order is not the deciding rule: a later set from a lower component loses to an earlier set from a higher one. Only when two sets come from the same level would the later pulse win. Carry this timing picture: in the normal top-down flow, the test sets first and still wins, which is precisely the behavior that makes "configure from the top, override defaults below" work.

DebugLab — the specific set that lost to a broad one

An env's precise per-agent config that a test's blanket wildcard silently overrode

Symptom

An env configured each agent precisely: set(this, "agent0", "cfg", agent0_cfg) and set(this, "agent1", "cfg", agent1_cfg), giving each agent its own tuned configuration. A test, meanwhile, set a blanket default for convenience: set(this, "*", "cfg", default_cfg). The engineer expected the env's specific per-agent sets to win for agent0 and agent1 (they named the exact agents), with the test's * only filling in anything the env didn't configure. Instead, both agents came up with default_cfg — the env's carefully tuned per-agent configuration was completely ignored, with no error.

Root cause

UVM precedence is by the setter's hierarchy position, not pattern specificity — so the test's broad * (higher) beat the env's precise agent0/agent1 (lower):

why the broad test set beat the specific env sets
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
env  (lower):  set(this, "agent0", "cfg", agent0_cfg)  // scope uvm_test_top.env.agent0  (precise)
               set(this, "agent1", "cfg", agent1_cfg)  // scope uvm_test_top.env.agent1  (precise)
test (higher): set(this, "*",      "cfg", default_cfg) // scope uvm_test_top.*            (broad)
 
agent0 get → both "uvm_test_top.env.agent0" (env) and "uvm_test_top.*" (test) match
precedence → TEST is higher in the hierarchy than ENV → test's "*" WINS (specificity ignored)
result     → agent0.cfg = default_cfg, agent1.cfg = default_cfg  (env's tuned sets lost)
 
assumption that caused it: "the more specific scope wins" — UVM does NOT work this way
fix options:
  (a) don't use a blanket "*" in the test for a field the env configures per-instance; or
  (b) if the test must override, make it intentional and per-instance:
        set(this, "env.agent0", "cfg", t0); set(this, "env.agent1", "cfg", t1);  // explicit
  (c) verify with the resource/config dump which set won (see Diagnosis)

The engineer applied a specificity mental model — "a pattern naming the exact agent beats a blanket wildcard" — which is how CSS, routing tables, and firewall rules behave, but not how UVM config DB precedence works. In UVM, the only thing that decides among matching sets is the hierarchy position of the setting component: the test is above the env, so the test's set wins, and the fact that the env's pattern was far more specific is completely irrelevant. The blanket set(this, "*", ...) from the test therefore overrode every per-agent set the env made. This is the same family as a too-broad factory override (Module 6.7), but driven by the precedence rule rather than scope alone: even a correctly scoped specific set loses if a higher component also matches. The fixes are to not blanket-set a field that lower components configure per-instance, or — if the override is intentional — to make it explicit and per-instance from the test, and always to verify which set actually won.

Diagnosis

The tell is "my specific set was ignored in favor of a broader one from higher up." Diagnose precedence problems:

  1. Identify all sets that match the get. List every set for that field whose scope glob covers the getter's path — not just the one you expected to win. The surprise winner is usually a broad set from a higher component.
  2. Compare setter hierarchy, not pattern specificity. Rank the matching sets by where the setting component sits (test above env above agent). The highest one wins — if a blanket set from the test exists, suspect it immediately.
  3. Remember order is only a tiebreaker. If the top candidates are at the same level, the last set wins; otherwise order is irrelevant. Don't be misled by which set ran first.
  4. Dump the configuration/resource database. Use the config/resource print (e.g., the resource dump or +UVM_CONFIG_DB_TRACE) to see all matching sets and which one was selected — this shows the actual precedence outcome rather than your assumed one.
Prevention

Reason about precedence by hierarchy, and make overrides intentional:

  1. Never assume specificity wins. Internalize "higher-in-hierarchy setter wins, then last set" — specificity is never a factor. When a higher component sets a field, expect it to win over lower components regardless of pattern.
  2. Don't blanket-set fields configured per-instance below. A test's set(this, "*", field, ...) overrides every lower set for that field. Use a blanket set only for fields you genuinely want uniform; otherwise set per-instance.
  3. Make intentional overrides explicit and scoped. If a test must override a specific lower set, set it at the specific path from the test, so the intent is visible and the blast radius is bounded.
  4. Verify which set won. Use the config/resource trace to confirm the intended set actually won for each getter — precedence surprises are silent, so checking is the only way to be sure.

The one-sentence lesson: UVM config DB precedence is decided by the setting component's hierarchy position — higher always beats lower, with order only as a same-level tiebreaker and specificity never a factor — so a test's blanket set(this, "*", ...) silently overrides an env's precise per-instance sets, and the fix is to stop assuming "specific wins," scope intentional overrides explicitly, and verify which set won.

Common Mistakes

  • Assuming the most specific scope wins. UVM precedence is by setter hierarchy, never specificity; a precise env set loses to a broad test set. Reason by who is higher, not whose pattern is tighter.
  • Blanket-setting a field configured per-instance below. A test's set(this, "*", field, ...) overrides every lower set for that field. Blanket-set only fields meant to be uniform.
  • Thinking last-set always wins. Order is only a tiebreaker among equal-hierarchy sets; a later set from a lower component still loses to an earlier set from a higher one.
  • Forgetting the field and type must match before precedence applies. Precedence only adjudicates among sets that already matched on glob, field, and type — a field typo means the set isn't even a candidate.
  • Expecting a late set to affect an already-resolved get. Resolution sees only sets registered before the get runs; a run_phase set can't change a build_phase get that already resolved.
  • Using an over-broad wildcard unintentionally. * matches everything below; if you meant one subtree, scope it (env.agent0.*) so it doesn't catch unrelated components.

Senior Design Review Notes

Interview Insights

The one set by the component highest in the hierarchy wins, and among sets from the same level, the last one registered wins — specificity is never a factor. Resolving a get is two stages. First, matching: the database collects every set whose scope glob covers the getter's full hierarchical path and whose field name and type agree. Specificity plays no role in matching — a glob either covers the path or it doesn't, whether it's a precise path or a broad wildcard. Second, precedence: among the matched sets, the winner is decided by the position of the setting component in the hierarchy. A set from a component closer to the root — the test — beats a set from a lower component — the env — regardless of how specific each pattern is. Only when the top candidates were set from the same hierarchy level does the tiebreaker apply, and then the last set registered wins. The rule the config DB never uses is specificity: a precise env set does not beat a broad test set. This is by design — the whole purpose of the config DB is top-down override, so the higher component must win, which means an env's precise per-instance set can be overridden by a test's blanket wildcard. The mental shortcut is: high beats low, then last beats first, and specific never beats broad.

Exercises

  1. Rank the winners. A get at uvm_test_top.env.agent0.drv for field cfg is matched by: env's set(this,"agent0.drv",...), base test's set(this,"*",...), derived test's set(this,"*",...). List which match, then name the winner and the rule that decides.
  2. Refute the misconception. A colleague says "the env's agent0.drv set is more specific, so it beats the test's *." Explain why they're wrong and what actually wins.
  3. Scope an intentional override. A test must override only agent1's config while leaving the env's agent0 config intact. Write the test-side set that does this without a blanket *.
  4. Timing vs precedence. Explain why a test's set wins even though, under top-down build, it runs before the env's set — and give the one situation where running last would decide.

Summary

  • A get resolves in two stages: match (collect every set whose scope glob covers the getter's full path and whose field + type agree) then rank (select among the matches by precedence). Matching is by coverage, not specificity.
  • Precedence is by the setting component's hierarchy position: a set from a component higher in the tree (closer to the root — the test) beats one from lower down (the env), regardless of pattern specificity. This is why a test overrides an env's defaults.
  • Order is only a tiebreaker: among sets of equal hierarchical precedence, the last set wins. Because top-down build runs the test's set first, a hierarchy-first rule is the only one that makes override work — and a later set from a lower component still loses.
  • Specificity is never a factor — the dangerous misconception (from CSS/routing) is that a precise scope beats a broad one; in UVM a blanket set(this, "*", ...) from a test silently overrides an env's precise per-instance sets.
  • The durable rule of thumb: resolve precedence by asking "who is higher?" then, only if tied, "who set last?" — never "who is more specific?"; scope test-level sets intentionally (a * overrides everything below for that field), and verify which set won with the config/resource trace, because precedence surprises are silent.

Next — Hierarchical Configuration: with matching and precedence understood, the next chapter builds the patterns on top of them — configuring nested structures, passing configuration objects down through layers, and assembling a coherent configuration tree for a multi-agent environment.