The UVM config database, uvm_config_db, is a central store for settings that testbench components need, such as virtual interface handles, mode switches and configuration objects. One part of the testbench calls set() with a value, a name and a scope, and any component inside that scope can retrieve it with get(). It is a typed layer built on top of the more general uvm_resource_db.
Without it, every setting would have to be passed by hand through each level of the hierarchy, and a test could not change a driver's behavior without editing every component in between. With it, the test sets a value once and the component that needs it reads it directly.
9 min read | Intermediate Level
What You'll Learn
- Store and retrieve values with
set()andget() - Work out exactly which components a scope string reaches
- Predict which setting wins when several match
- Use
exists(),wait_modified()and the convenience typedefs
Syntax
uvm_config_db is a parameterized class, and every method is static, so you call it with the :: operator and the type in #().
uvm_config_db #(T)::set (uvm_component cntxt, string inst_name, string field_name, T value);
uvm_config_db #(T)::get (uvm_component cntxt, string inst_name, string field_name, inout T value); // returns bit
uvm_config_db #(T)::exists (uvm_component cntxt, string inst_name, string field_name, bit spell_chk = 0);
uvm_config_db #(T)::wait_modified (uvm_component cntxt, string inst_name, string field_name); // task
Tis the type of the value:int, a virtual interface type, or a configuration class handle. Aset()and aget()only match if they use exactly the same type.cntxtis the component the call is made from, normallythis. Code outside the component hierarchy, such as the top-level module, passesnull.inst_nameis a path relative tocntxt. Forset()it may contain wildcards. Forget()it is usually"", meaning "the calling component itself".field_nameis the name the value is stored under, and it must match betweenset()andget().
set() and get() in Practice
// tb_top (a module, so cntxt is null): share the interface with everything below the test
initial begin
uvm_config_db #(virtual apb_if)::set(null, "uvm_test_top.*", "apb_vif", apb_if0);
run_test();
end
// Test: turn on coverage in one agent
uvm_config_db #(int)::set(this, "m_env.m_apb_agent", "cov_enable", 1);
// Driver: read the interface meant for this component
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db #(virtual apb_if)::get(this, "", "apb_vif", vif))
`uvm_fatal("NOVIF", "apb_vif not found in config_db")
endfunction
get() returns 1 if a matching setting is found and copies the value into the last argument. It returns 0 and leaves the variable untouched otherwise. Always check that return value for anything the component cannot work without.
How Scopes Match
Every set() stores its value with a scope. When cntxt is a component, the scope is the component's full name, a dot, and inst_name. When cntxt is null, inst_name alone is the complete scope. Scopes may use glob wildcards, where * matches any sequence of characters.
A get(this, "", ...) looks up the caller's own full name and finds the settings whose scope matches it.
- A.
"uvm_test_top.*"matches every component below the test, but not the test itself, because the pattern requires a dot and at least something after it. - B. Called from inside m_apb_agent with
"*", the scope becomesuvm_test_top.m_env.m_apb_agent.*, which reaches only the agent's children. - C. A scope with no wildcard matches one exact path, so only m_env can get
cfg.
Quick Check
Q: From inside m_env, which call makes a value visible to m_apb_agent and everything below it, but not to other agents?
Show Answer
set(this, "m_apb_agent*", "field", value). The scope becomes uvm_test_top.m_env.m_apb_agent*, which matches the agent itself and every path that starts with its name. Using "m_apb_agent.*" instead would leave out the agent itself.
Which Setting Wins?
More than one set() can match the same component. The rules depend on when the settings are made.
- During the build phase, a setting made from higher in the hierarchy has higher precedence. A test's
set()therefore overrides an environment'sset()for the same field, even though the environment's call runs later. Settings made from the same level follow "last setting wins". - After the build phase, every setting has the same precedence, so the last one made wins, regardless of where it came from.
The build-time rule is what lets a test override an environment's defaults. The environment can set sensible values for its children, and any test that sets the same field gets its own value instead.
If a component seems to read the wrong value, call print_config() on it, or run with +UVM_CONFIG_DB_TRACE, which prints every set and get with the scope and field involved.
exists() and wait_modified()
exists() returns 1 if a value for the field is visible from the given scope, without reading it. That is useful for optional settings, where the component falls back to a default if nothing was set.
if (!uvm_config_db #(int)::exists(this, "", "num_trans"))
`uvm_info("CFG", "num_trans not set, using the default of 10", UVM_LOW)
wait_modified() is a task that blocks until a new setting is applied to the field. It lets a component react to a value another component changes during the run.
// In the agent
virtual task run_phase(uvm_phase phase);
forever begin
uvm_config_db #(int)::wait_modified(this, "", "loop_count");
void'(uvm_config_db #(int)::get(this, "", "loop_count", loop_count));
`uvm_info("CFG", $sformatf("loop_count is now %0d", loop_count), UVM_MEDIUM)
end
endtask
// In the environment
virtual task main_phase(uvm_phase phase);
phase.raise_objection(this);
for (int i = 1; i <= 3; i++) begin
#100;
uvm_config_db #(int)::set(this, "m_apb_agent", "loop_count", i);
end
phase.drop_objection(this);
endtask
The #100 between updates matters. wait_modified() wakes once per change, so several set() calls in the same time step without a delay would be seen as one.
Convenience Typedefs
UVM defines short names for the most common specializations.
typedef uvm_config_db #(uvm_bitstream_t) uvm_config_int;
typedef uvm_config_db #(string) uvm_config_string;
typedef uvm_config_db #(uvm_object) uvm_config_object;
typedef uvm_config_db #(uvm_object_wrapper) uvm_config_wrapper;
uvm_config_int is the type that automatic configuration of `uvm_field_int fields uses, and the documented way to set an agent's is_active knob. Note that it is not the same entry as uvm_config_db #(int), because the types differ.
Good Practices
- Group related settings into a configuration object and pass that single handle, instead of many separate fields. See Configure Components.
- Make build-time
set()calls inbuild_phase, in the parent, before the child that reads them runs its ownbuild_phase. - Use
uvm_config_dbfor anything with a place in the component hierarchy, and keep the lower-leveluvm_resource_dbfor data shared outside it. The differences are covered in Understanding the Resource Database. - The old
set_config_int(),set_config_string()andset_config_object()methods ofuvm_componentare legacy wrappers. Useuvm_config_dbdirectly in new code.
Common Mistakes
Mistake #1: Expecting "uvm_test_top.*" to include the test
The pattern requires a dot after uvm_test_top, so the test itself cannot get the value. If the test needs it too, use "*" or set it a second time with scope "uvm_test_top".
Mistake #2: Mixing int and uvm_config_int
Wrong: uvm_config_int::set(...) followed by uvm_config_db#(int)::get(...)
Right: the same type on both sides
Why? uvm_config_int stores a uvm_bitstream_t, which is a different type from int. The database treats them as separate entries, so the get() finds nothing.
Mistake #3: Using a wildcard in get()
The inst_name of a get() is part of the name being looked up, not a pattern. A call such as get(this, "*", ...) searches for a component literally named *, which may happen to match a broad set() scope but does not mean "search everywhere". Use "" to look up the calling component's own settings.
Mistake #4: Setting from a lower level and expecting it to win during build
During the build phase, an environment's set() cannot override a test's set() for the same field and scope, because the higher level has precedence. If the environment's value seems ignored, check whether the test is setting the same field.
Summary
In this article, you learned:
uvm_config_db #(T)::set()stores a typed value with a scope and a field name, andget()retrieves it and returns 1 on success- The scope is the context's full name plus
inst_name, orinst_namealone when the context isnull "path.*"reaches everything below a path but not the path itself, and a scope without wildcards matches exactly one component- During build, higher-level settings take precedence; afterwards, the last setting wins
exists()checks for a value,wait_modified()waits for a change, anduvm_config_intis a distinct type fromint