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

Pointuvm_config_dbuvm_resource_db
Built onWraps uvm_resource_dbThe base storage layer
Uses hierarchyYes, path and name decide who sees itNo, uses a scope string only
Wildcards in pathYes, such as env.agt*Not in the same hierarchy sense
Typical useInterfaces, config objects, mode flags for a branchGlobal shared values with no owner
PrecedenceLater set from higher in the tree winsLast write for a scope and name
Everyday choiceAlmost always this oneOnly 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 the build_phase of a parent.
  • Get in the build_phase of the component that needs it.
  • Always test the return bit of get and fail loudly if it is 0.
  • For a value that changes per test, set it in the test build_phase so 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 agt but getting on agent. 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 int and getting a bit. The types must match exactly.
  • Reaching for uvm_resource_db when a hierarchical uvm_config_db set 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.