Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
  • Factory & Configuration15
    • UVM Factory: Registration, Overrides and Debug
    • config_db and Resources
      • The set/get Contract: Four Arguments That Must Agree
      • Instance Paths and Wildcards: Who Can See a Setting
      • config_db Resolution: Who Wins at Build and After
      • Config Objects: One Typed Handle Instead of Twenty Knobs
      • config_db Performance and Anti-Patterns
      • Auto-Config and Field Macros on Components
      • Configuring Sequences
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

‹config_db and Resources
  1. Topics
  2. UVM Verification
  3. Factory & Configuration
  4. config_db and Resources
  5. config_db Resolution: Who Wins at Build and After

Part 3/Factory & ConfigurationIntermediate

config_db Resolution: Who Wins at Build and After

The one home for config_db precedence: during build, precedence is 1000 minus the setter's depth, so higher components win; between equals and after build, the last set wins; path specificity never decides. With the lookup diagram and the debug tools.

On this page

    A loopback test wants the DMA's output agent active for once. In the test's build_phase, the author sets is_active to UVM_ACTIVE on env.out_agt through uvm_config_db, then worries: the env sets UVM_PASSIVE for the same agent, later, in its own build_phase. Surely the later set wins? It does not. The test wins, every time, wherever the line goes. This lesson is the only place in the course where the precedence rules are taught; other lessons link here.

    The idea: during build, seniority beats recency

    Think of an office where instructions are pinned on a board during the morning planning session. Each note carries the writer's rank. When two notes conflict, the higher-ranked writer wins, no matter who pinned last: the director's note beats the team lead's, even if the team lead pinned theirs an hour later. Between two notes of the same rank, the newer one wins. After planning ends, rank stops mattering: everything pinned during the working day has the same rank, so the newest note always wins.

    In UVM the rank is precedence, and it is computed from the setter's position in the hierarchy. During build_phase, a set gets precedence 1000 - depth, where depth is the setter context's distance from the top: uvm_root (or a null context) has depth 0, uvm_test_top depth 1, the env depth 2, an agent depth 3. Outside build_phase every set gets the default precedence 1000. A get collects every setting that matches its key, picks the highest precedence, and breaks ties by taking the most recent set.

    Notice what is missing: how specific the path is. A wildcard env.* from the test beats an exact out_agt from the env. Path form only decides whether a set matches at all (reach).

    The picture

    Diagram: build-time sets get 1000 minus setter depth (top 1000, test 999, env 998, agent 997); sets outside build get 1000; get picks the highest precedence and breaks ties by the most recent set.
    The config_db lookup. During build, a set's precedence comes from the setter's depth, so a higher component wins whatever the order. Sets made before or after build (the top module before run_test, any component in run_phase) get 1000. Ties go to the most recent set. Path specificity is not part of the rule.

    Build it: the rules applied to the bench

    Case 1: the test overrides the env's choice

    design.sv
    1
    2
    3
    4
    5
    // snippet: in a loopback test's build_phase (position relative to super does not matter)
    uvm_config_db#(uvm_active_passive_enum)::set(this, "env.out_agt", "is_active", UVM_ACTIVE);
    // test depth 1 -> precedence 999
    // later, dma_env::build_phase: set(this, "out_agt", "is_active", UVM_PASSIVE)
    // env depth 2 -> precedence 998. The agent reads UVM_ACTIVE.

    The env's set happens after the test's (the env builds after the test), yet the test wins: 999 beats 998. This is the design intent. The env states a default for its own children; any test above it can override that default without editing the env.

    Case 2: the top module beats the test

    The top module's interface sets run in an initial block before run_test, outside any phase, so they get 1000. A test that tries to swap an interface during build gets 999 and loses. To let tests choose interfaces, add one hop: the top publishes each interface under a source name, and the env passes the chosen one on under the name the drivers read.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // snippet: letting a test choose the interface
    // top, before run_test (precedence 1000, but nobody else sets these names)
    uvm_config_db#(virtual axis_if)::set(null, "uvm_test_top.env", "s_vif_a", s_ax_a);
    uvm_config_db#(virtual axis_if)::set(null, "uvm_test_top.env", "s_vif_b", s_ax_b);
    // test build_phase: pick one by name (a plain string knob, no clash with the top)
    uvm_config_db#(string)::set(this, "env", "in_vif_name", "s_vif_b");
    // env build_phase: read the choice, fetch that interface, re-set it for the agent
    if (!uvm_config_db#(string)::get(this, "", "in_vif_name", name)) name = "s_vif_a";
    if (!uvm_config_db#(virtual axis_if)::get(this, "", name, vif)) `uvm_fatal("NOVIF", name)
    uvm_config_db#(virtual axis_if)::set(this, "in_agt.*", "vif", vif);

    Case 3: same setter, or after build: last set wins

    Two sets from the same component have the same depth, so the later one wins, whatever their paths. And every set made outside build_phase gets 1000, so a run-time set from anywhere beats a build-time set and then follows last-set-wins. That is how a test changes a knob in the middle of run_phase for a sequence that reads config later (Configuring sequences).

    Settings that match the getter

    Precedences

    Winner

    env sets out_agt PASSIVE; test sets env.out_agt ACTIVE (both in build)

    998 vs 999

    Test: ACTIVE

    test sets env.* gap=5; env sets in_agt.drv gap=2 (both in build)

    999 vs 998

    Test: 5 (wildcard beats exact)

    test sets env.apb.drv gap=1, then env.* gap=5 (both in build)

    999 vs 999

    Later set: 5

    top sets vif before run_test; test sets vif in build

    1000 vs 999

    Top

    test sets knob=1 in build; agent sets knob=4 in run_phase

    999 vs 1000

    Agent: 4

    test sets knob=1 in run_phase, later knob=2 in run_phase

    1000 vs 1000

    Later set: 2

    uvm_resource_db sits under config_db but has no notion of hierarchy: every resource gets the default precedence, a plain set is queued behind existing resources, and set_override puts a resource at the front of the queue, so among resources of equal precedence it is the one found. Components use config_db so that depth-based precedence applies. Reach for uvm_resource_db directly only for data that has no place in the component tree, such as a table or a handle shared by the whole bench and by sequences, set once under a scope string both sides agree on (for example a lookup table set with uvm_resource_db#(lut_t)::set("*", "crc_lut", lut) and read anywhere with read_by_name). The interview version: config_db is resource_db plus hierarchical scopes and depth-based precedence.

    Watch it run

    In the shipped bench no two settings collide, and the env's PASSIVE set is the only is_active setting for out_agt. The evidence is the topology at the start of every run, where out_agt has a monitor and no driver, and the passing log:

    Diagram
    +UVM_TESTNAME=dma_smoke_test
    UVM_INFO dma_tb.sv(411) @ 655000: uvm_test_top.env.sb [SB] 8 words matched, 0 mismatched
    UVM_ERROR :    0

    When collisions do happen, three tools show the decision. +UVM_CONFIG_DB_TRACE prints a CFGDB/SET line for every set and a CFGDB/GET line for every get, naming the scope, the field, the type, the accessor and the value. print_config(1, 1) on a component lists every setting that reaches it and its children, and with the audit argument, who read them. uvm_config_db#(T)::dump() prints the whole resource pool, whatever T is, with each resource's precedence.

    design.sv
    1
    2
    3
    4
    5
    // snippet: precedence debugging from the test
    function void end_of_elaboration_phase(uvm_phase phase);
      env.out_agt.print_config(1, 1);      // settings visible to out_agt and below, with readers
      uvm_config_db#(int)::dump();         // the entire resource pool, not just int
    endfunction

    What breaks: the agent default that a test could not override

    A team's agents read a coverage_enable knob at the start of run_phase. Tests set it to 0 in build_phase for a fast regression, and it was ignored on half the agents. Someone "fixed" it by moving the test's set later in the test's build_phase. It changed nothing, because order was never the issue.

    The rule explains both halves. Some agents made sure the knob had a value by setting their own default in build_phase (set(this, "", "coverage_enable", 1)): the test's set (999) beat that self-set (997), so those agents obeyed the test. In the other agents, the default was set by the parent env with a broad pattern in its connect_phase, which is outside build, so it carried precedence 1000 and beat the test. The fix was the pattern this course recommends: a component never sets config to create a default. It initializes the variable, calls a non-fatal get, and keeps its default on a miss. Only components above set values for those below, and they do it during build.

    "The agent sets a value for its driver in build_phase, and the test sets a different value for the same driver. Who wins?"

    A weak answer: "The most specific path wins, and if they're the same, the last set. The agent is closer to the driver, so the agent."

    A strong answer: "The test. During build_phase, a set's precedence is 1000 minus the setter context's depth: top or null is 1000, the test 999, the env 998, the agent 997. Highest wins regardless of order or how specific the path is. Ties, meaning the same depth, go to the most recent set. Outside build every set gets 1000, so a run-time set wins and the newest one after that. To debug I use +UVM_CONFIG_DB_TRACE, print_config and dump."

    Follow-ups: Why can't the test replace the interface the top module set? (the top's set is 1000, outside any phase) and What if the env makes its set in connect_phase? (it gets 1000 and beats the test's 999).

    Check yourself The agent at depth 3 sets uvm_config_db#(int)::set(this, "*", "rate", 500) in build. The test sets set(this, "env.*", "rate", 2000) in build. What does the agent's monitor read?

    2000. Both sets match the monitor's full name. The test's precedence is 999 and the agent's is 997, so the test wins, even though the agent's set is closer to the monitor and happens later.

    Check yourself The env sets gap for its driver in build_phase (998). In run_phase, a virtual sequence calls uvm_config_db#(int)::set(null, "uvm_test_top.env.in_agt.drv", "gap", 0). The driver re-reads gap before each packet. What does it see after the virtual sequence's set?

    0. The run-time set is made outside build, so it gets precedence 1000 and beats the env's 998. If anything sets gap again later at run time, the newest of those sets wins.

    Check yourself A colleague says: "precedence is about specificity, the exact path always beats a wildcard". Give a bench example that disproves it.

    The test sets set(this, "env.*", "gap", 5) and the env sets set(this, "in_agt.drv", "gap", 2), both in build. The driver reads 5: the test's wildcard set (999) beats the env's exact set (998). Specificity is not part of the lookup.

    Next: loose knobs multiply collisions. Config objects bundles them into one typed handle, as dma_rand_test does with its job description.

    Related topics

    • Instance paths and wildcards

    • Config objects

    • Factory override resolution (a different rule)

    • Test base classes

    Previous

    55 / 280

    Next: Config Objects: One Typed Handle Instead of Twenty Knobs

    Up next

    Up nextConfig Objects: One Typed Handle Instead of Twenty Knobs

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The set/get Contract: Four Arguments That Must Agree
    • config_db Performance and Anti-Patterns
    • Auto-Config and Field Macros on Components