uvm_config_db and uvm_resource_db
In short: uvm_config_db and uvm_resource_db are two ways to pass settings and handles across a UVM testbench without wiring them through every constructor. uvm_config_db is the everyday choice: it stores a value against a path and a name, and a component lower down reads it back. uvm_resource_db is the lower layer underneath it, used when you do not care about hierarchy and just want a shared named value.
When you build a UVM testbench, the interface, the number of agents, or a mode flag often needs to reach a component that sits several levels deep. Passing these through every new() call would be painful. UVM gives you a shared database so the top can set a value and any component below can get it by name.
A simple way to picture it
Think of a hotel front desk that holds parcels. A courier drops a parcel at the desk and writes two things on it: which room it is for, and a label like “phone charger”. Later a guest walks up and asks for the parcel for their room with that label. The desk hands it over. The guest never had to meet the courier. uvm_config_db works the same way: the setter leaves a value tagged with a target path and a name, and the getter later asks for it by that path and name.
What is uvm_config_db?
uvm_config_db is a type-parameterised database built on top of the resource database. You store a value with set and read it with get. Both calls carry a context and an instance path, so UVM knows which part of the hierarchy the value is meant for.
// Store a value
uvm_config_db#(T)::set(uvm_component cntxt,
string inst_name,
string field_name,
T value);
// Read a value
bit found;
found = uvm_config_db#(T)::get(uvm_component cntxt,
string inst_name,
string field_name,
ref T value);
The pair cntxt plus inst_name forms the full target path. If cntxt is the test and inst_name is "env.agent*", the value reaches every agent inside the environment. get returns 1 when it finds a match, so always check that bit before you trust the value.
A worked example: passing a virtual interface
The most common use is handing a virtual interface from the top module down to the driver and monitor. The top sets it once, and every component that needs it reads it in build_phase.
// Top module: set the interface handle
module top;
apb_if apb_vif();
initial begin
uvm_config_db#(virtual apb_if)::set(null, "uvm_test_top.env.agt*",
"vif", apb_vif);
run_test("apb_test");
end
endmodule
// Driver: get the interface in build_phase
class apb_driver extends uvm_driver #(apb_seq_item);
virtual apb_if vif;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual apb_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "virtual interface not set for driver")
endfunction
endclass
Notice the setter uses null as context with a full string path, while the getter uses this with an empty instance name because the driver is asking for its own value. Both styles are valid. The uvm_fatal guard means the test stops early with a clear message if the handle was never set, instead of failing later with a confusing null-handle error.
What is uvm_resource_db?
uvm_resource_db is the storage layer that uvm_config_db sits on top of. It stores values by a scope and a name, but it does not use the component hierarchy the way config_db does. You reach for it directly when a value is global in nature and does not belong to one branch of the tree, such as a register model handle or a shared clock period.
// Write a resource
uvm_resource_db#(int)::set("global", "clk_period_ns", 10, this);
// Read it back anywhere
int period;
if (!uvm_resource_db#(int)::read_by_name("global", "clk_period_ns",
period, this))
`uvm_warning("NORES", "clk_period_ns not found")
uvm_config_db versus uvm_resource_db, side by side
| Point | uvm_config_db | uvm_resource_db |
|---|---|---|
| Built on | Wraps uvm_resource_db | The base storage layer |
| Uses hierarchy | Yes, path and name decide who sees it | No, uses a scope string only |
| Wildcards in path | Yes, such as env.agt* | Not in the same hierarchy sense |
| Typical use | Interfaces, config objects, mode flags for a branch | Global shared values with no owner |
| Precedence | Later set from higher in the tree wins | Last write for a scope and name |
| Everyday choice | Almost always this one | Only when you need the raw layer |
For nearly all testbench work you should reach for uvm_config_db. It respects the hierarchy, which is what you want when a value is meant for one agent and not another. Use uvm_resource_db only when hierarchy does not matter.
Set and get timing: why build_phase matters
Configuration flows top down during build_phase. A parent runs its build_phase before its children, so a value set by the test is available by the time the environment and agents build. If you try to get a value before the parent has set it, the get returns 0.
- Set from the top module before
run_test, or in thebuild_phaseof a parent. - Get in the
build_phaseof the component that needs it. - Always test the return bit of
getand fail loudly if it is 0. - For a value that changes per test, set it in the test
build_phaseso it overrides any default.
Common mistakes to avoid
- Forgetting to check the return value of
get, then using a null or stale handle. - A path mismatch between set and get, for example setting on
agtbut getting onagent. The names must line up. - Setting the value after the getter already ran, so the get sees nothing.
- Using the wrong type parameter, such as setting an
intand getting abit. The types must match exactly. - Reaching for
uvm_resource_dbwhen a hierarchicaluvm_config_dbset would have been clearer.
Keep learning
Once configuration passing is clear, the next steps sit close by. See how a virtual interface is passed with uvm_config_db, how the pieces fit in a typical UVM testbench architecture, and browse more in the UVM category or the interview questions.
Frequently asked questions
A common use of the config database is passing a handle down the hierarchy. See exactly that in why we need a virtual interface, where the interface is set once and read deep inside the testbench.
What is the difference between uvm_config_db and uvm_resource_db?
uvm_config_db is built on top of uvm_resource_db and respects the component hierarchy through a path and name, so a value can target one branch. uvm_resource_db is the raw storage layer that uses only a scope string, with no hierarchy.
When should I use uvm_resource_db instead of uvm_config_db?
Use uvm_resource_db only for values that have no natural owner in the tree, such as a global clock period or a shared handle. For anything tied to a component branch, uvm_config_db is clearer and safer.
Why does my uvm_config_db get return 0?
The most common causes are a path or name mismatch between set and get, a type parameter that does not match, or a get that runs before the set. Check that both calls use the exact same field name and type.
Where should I call set and get?
Set from the top module before run_test or in a parent build_phase, and get in the build_phase of the component that needs the value. This order matches how configuration flows top down.
Can I use wildcards in the path?
Yes. With uvm_config_db you can set a value for env.agt* so every matching agent receives it. This is handy when several agents share the same setting.
Should I always check the return value of get?
Yes. get returns 1 on success and 0 on failure. Guard it with an if and raise uvm_fatal or uvm_warning so a missing value is caught early rather than causing a null handle later.
Part of the learning path UVM methodology
