These uvm_config_db examples show, case by case, which set() calls a component can and cannot see. The rules are short to state but easy to misapply, so the examples use one small testbench, a single field name, and the +UVM_CONFIG_DB_TRACE output that shows exactly what each call looked up.

The method signatures and the precedence rules are covered in UVM Config Database. This page is about building intuition for scopes, so you can predict a result before running the simulation.

8 min read | Intermediate Level

What You'll Learn

  • Work out the scope a set() call creates from its arguments
  • Predict which components a scope reaches, using a results table
  • Read +UVM_CONFIG_DB_TRACE output to debug a failed lookup
  • Avoid lookups that only work by accident

The Rules in Brief

  • A set(cntxt, inst_name, field_name, value) stores the setting with the scope {cntxt full name, ".", inst_name}. If cntxt is null, inst_name alone is the scope.
  • inst_name and field_name may be glob-style or regular-expression patterns.
  • A get(this, "", field_name, value) looks up the calling component's own full name.
  • During the build phase, settings from higher in the hierarchy win, and settings from the same level follow "last setting wins".

Turning on the Trace

The quickest way to understand a config_db problem is to make the simulator print every set() and get(). Add the switch to the command line of any simulator.

$> irun <all_other_options> +UVM_CONFIG_DB_TRACE

Each [CFGDB/SET] line shows the scope and field that were stored, and each [CFGDB/GET] line shows the scope and field a component looked up, and whether the lookup succeeded.

The Example Testbench

All examples use a test containing one environment with two agents. Every component reads a string field named Friend in its build_phase.

Case 1: An Absolute Scope on Both Sides

The test stores the string with a null context and the scope "uvm_test_top", and the environment reads it back with exactly the same absolute scope.


class base_env extends uvm_env;
  // Rest of the code (registration, constructor, agent handles)
  string name;

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    // Reads with an absolute scope instead of its own path
    if (uvm_config_db #(string)::get(null, "uvm_test_top", "Friend", name))
      `uvm_info("ENV", $sformatf("Found %s", name), UVM_MEDIUM)
  endfunction
endclass

class base_test extends uvm_test;
  // Rest of the code (registration, constructor, creates the environment)
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    uvm_config_db #(string)::set(null, "uvm_test_top", "Friend", "Joey");
  endfunction
endclass

In this run the environment instance was named base_env, so its full name in the log is uvm_test_top.base_env. The yellow line is the set() and the green line is the successful get().

Output
ncsim> run
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_root.svh(392) @ 0: reporter [UVM/RELNOTES]
----------------------------------------------------------------
UVM-1.2
(C) 2007-2014 Mentor Graphics Corporation
(C) 2007-2014 Cadence Design Systems, Inc.
(C) 2006-2014 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
(C) 2013-2014 NVIDIA Corporation
----------------------------------------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.recording_detail' (type logic signed[4095:0]) read by uvm_test_top.base_env = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.recording_detail' (type int) read by uvm_test_top.base_env = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration 'uvm_test_top.Friend' (type string) set by  = (string) "Joey"
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.m_agent0.recording_detail' (type logic signed[4095:0]) read by uvm_test_top.base_env.m_agent0 = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.m_agent0.recording_detail' (type int) read by uvm_test_top.base_env.m_agent0 = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.m_agent1.recording_detail' (type logic signed[4095:0]) read by uvm_test_top.base_env.m_agent1 = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.m_agent1.recording_detail' (type int) read by uvm_test_top.base_env.m_agent1 = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.Friend' (type string) read by  = (string) "Joey"
UVM_INFO testbench.sv(36) @ 0: uvm_test_top.base_env [ENV] Found Joey
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER]
--- UVM Report Summary ---

** Report counts by severity

The lookup succeeds, but look at why. The get() line reads uvm_test_top.Friend, and its "read by" field is empty because the environment passed null as the context and asked for the test's scope instead of its own. The setting is not visible to the environment's own path, uvm_test_top.base_env. The environment simply reached outside its scope to fetch it.

The other lines are UVM's own lookups of recording_detail, which every component makes during build. They fail harmlessly and show up in every trace.

Reading with get(null, "absolute.path", ...) works, but it hard-codes the hierarchy into the component. The same environment reused under a different test name or deeper in a larger testbench would stop finding its settings. Prefer get(this, "", ...) and make the set() reach the component.

Case 2: Using this as the Context

Here the test uses this with an empty inst_name. The test's full name is uvm_test_top, so the scope is the same as in Case 1.


uvm_config_db #(string)::set(this, "", "Friend", "Joey");

// Same get() in the environment as before
if (uvm_config_db #(string)::get(null, "uvm_test_top", "Friend", name))
  `uvm_info("ENV", $sformatf("Found %s", name), UVM_MEDIUM)
Output
...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration 'uvm_test_top.Friend' (type string) set by uvm_test_top = (string) "Joey"
...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.Friend' (type string) read by  = (string) "Joey"

The only visible difference is "set by uvm_test_top": with a component as the context, the trace records who made the setting.

Case 3: Agents Using the Same Shortcut

If the agents also read with the absolute scope, they find the value too, for the same reason as Case 1.


class base_agent extends uvm_agent;
  // Rest of the code (registration, constructor)
  string name;

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (uvm_config_db #(string)::get(null, "uvm_test_top", "Friend1", name))
      `uvm_info("AGENT", $sformatf("[%s] Found %s", get_name(), name), UVM_MEDIUM)
  endfunction
endclass
Output
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration 'uvm_test_top.Friend1' (type string) set by uvm_test_top = (string) "Joey"
...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.Friend1' (type string) read by  = (string) "Joey"
UVM_INFO testbench.sv(44) @ 0: uvm_test_top.base_env [ENV] Found Joey
...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.Friend1' (type string) read by  = (string) "Joey"
UVM_INFO testbench.sv(22) @ 0: uvm_test_top.base_env.m_agent0 [AGENT] [m_agent0] Found Joey
...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.Friend1' (type string) read by  = (string) "Joey"
UVM_INFO testbench.sv(22) @ 0: uvm_test_top.base_env.m_agent1 [AGENT] [m_agent1] Found Joey

Quick Check

Q: In Case 3, if the agents switch to get(this, "", "Friend1", name) and the test keeps set(this, "", "Friend1", "Joey"), do they still find it?

Show Answer

No. The setting's scope is uvm_test_top, and the agents now look up their own full names, such as uvm_test_top.base_env.m_agent0, which do not match. The test would need a scope that reaches them, such as set(this, "*", ...).

Case 4: Scoping the Setting Properly

The recommended approach is the reverse of Cases 1 to 3. Each component reads from its own path with get(this, "", ...), and the test aims each setting only at the components that need it. In this run the environment was named m_env, matching the testbench diagram.

uvm_config_db #(string)::set(this, "m_env.m_agent*", "Friend", "Joey");   // in the test: for the agents
uvm_config_db #(string)::get(this, "", "Friend", name);                   // in the env
uvm_config_db #(string)::get(this, "", "Friend", name);                   // in each agent

Scope set : uvm_test_top.m_env.m_agent*

CONFIG_DB_TRACE results:
[CFGDB/SET] Configuration 'uvm_test_top.m_env.m_agent*.Friend' (type string) set by uvm_test_top = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.Friend' (type string) read by uvm_test_top.m_env = null (failed lookup)
[CFGDB/GET] Configuration 'uvm_test_top.m_env.m_agent0.Friend' (type string) read by uvm_test_top.m_env.m_agent0 = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.m_agent1.Friend' (type string) read by uvm_test_top.m_env.m_agent1 = (string) "Joey"

Both agents match m_env.m_agent*, but the environment does not, so its lookup fails. If the environment needs the value as well, the test adds a second set() aimed at it.

uvm_config_db #(string)::set(this, "m_env.m_agent*", "Friend", "Joey");   // for the agents
uvm_config_db #(string)::set(this, "m_env",          "Friend", "Joey");   // for the env

CONFIG_DB_TRACE results:
[CFGDB/SET] Configuration 'uvm_test_top.m_env.Friend' (type string) set by uvm_test_top = (string) "Joey"
[CFGDB/SET] Configuration 'uvm_test_top.m_env.m_agent*.Friend' (type string) set by uvm_test_top = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.Friend' (type string) read by uvm_test_top.m_env = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.m_agent0.Friend' (type string) read by uvm_test_top.m_env.m_agent0 = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.m_agent1.Friend' (type string) read by uvm_test_top.m_env.m_agent1 = (string) "Joey"

Writing "m_env*" instead would reach the environment and everything inside it in one call. Keeping settings narrow avoids two problems: different components accidentally sharing a field name, and a component picking up a value that was never meant for it.

Results Table: Which set() Reaches Which Component

Each row is one set() made in the test with field name Friend. Each column is a component reading with get(this, "", "Friend", name), so it looks up its own full name.

set() in the testStored scopem_envm_agent0m_agent1
(null, "uvm_test_top")uvm_test_topNot foundNot foundNot found
(this, "")uvm_test_topNot foundNot foundNot found
(this, "*")uvm_test_top.*FoundFoundFound
(this, "m_env")uvm_test_top.m_envFoundNot foundNot found
(this, "m_env.*")uvm_test_top.m_env.*Not foundFoundFound
(this, "m_env.m_agent*")uvm_test_top.m_env.m_agent*Not foundFoundFound
(null, "uvm_test_top.m_env.m_agent1")uvm_test_top.m_env.m_agent1Not foundNot foundFound
(this, "*.m_agent1")uvm_test_top.*.m_agent1Not foundNot foundFound
(this, "m_env.m_ag*")uvm_test_top.m_env.m_ag*Not foundFoundFound

Two patterns stand out. A scope with no wildcard matches exactly one path, which is why the first two rows reach nobody below the test. And "m_env.*" leaves out m_env itself, because the pattern needs a dot and more text after m_env.

Common Mistakes

Mistake #1: Making lookups work with an absolute scope in get()

Wrong: get(null, "uvm_test_top", "Friend", name) inside the environment
Right: get(this, "", "Friend", name), with a set() whose scope reaches the environment

Why? The absolute path ties the component to one particular hierarchy. It also lets the component read settings that were aimed at a different component, which defeats the point of scoping them.

Mistake #2: Assuming "path.*" includes the path itself

A setting with scope uvm_test_top.m_env.* reaches the agents but not the environment. Use "m_env*", or a separate set(), when the environment needs the value too.

Mistake #3: Debugging scopes without the trace

Guessing why a lookup fails wastes time. +UVM_CONFIG_DB_TRACE prints the exact scope that was set and the exact name that was looked up, so a mismatch is visible at a glance.

Summary

In this article, you learned:

  • A set() stores the scope {cntxt full name, ".", inst_name}, and a null context means inst_name is the whole scope
  • A get(this, "", ...) looks up the caller's own full name, so the scope must match that name
  • Scopes without wildcards match one path, and "path.*" excludes the path itself
  • Reading with an absolute scope works but makes components depend on one hierarchy
  • +UVM_CONFIG_DB_TRACE shows every set and get, which makes scope problems easy to spot
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5
Cron Job Starts