The short answer: uvm_config_db is UVM’s typed configuration database. A higher-level component or the top module calls uvm_config_db#(T)::set(context, path, field, value), and a lower-level component retrieves it in build_phase with ::get(this, “”, field, var). It’s used to pass virtual interfaces from the top module to drivers and monitors, configuration objects to agents and environments, and individual knobs. The command-line processor adds run-time control: +UVM_TESTNAME, +UVM_VERBOSITY, configuration overrides and your own plusargs.
Configuration is how a test controls an environment it didn’t build. Done well, every knob is in one place and tests are short. Done badly, settings silently fail to match and you spend an afternoon finding out why the agent is passive. This post combines my older posts on UVM configuration and the command-line processor.
- The essentials
- Passing a virtual interface
- Configuration objects
- Paths, wildcards and precedence
- The command-line processor
- Mistakes I see often
Table of Contents
Part 1: The essentials

Part 2: Passing a virtual interface
// tb_top
initial begin
uvm_config_db#(virtual bus_if)::set(null, "uvm_test_top.env.agt_in*", "vif", bus_vif);
run_test();
end
// in the driver or monitor
function void build_phase(uvm_phase phase);
if (!uvm_config_db#(virtual bus_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", {"vif not set for ", get_full_name()})
endfunction
The type parameter must match exactly on both sides, including the modport if you use one. A mismatch simply means get() returns 0.
Part 3: Configuration objects
class bus_agent_cfg extends uvm_object;
`uvm_object_utils(bus_agent_cfg)
uvm_active_passive_enum is_active = UVM_ACTIVE;
bit has_coverage = 1;
int unsigned timeout_cycles = 1000;
virtual bus_if vif;
function new(string name = "bus_agent_cfg"); super.new(name); endfunction
endclass
// in the test
function void build_phase(uvm_phase phase);
bus_agent_cfg in_cfg = bus_agent_cfg::type_id::create("in_cfg");
// here tb_top did: set(null, "uvm_test_top", "bus_vif", bus_vif)
if (!uvm_config_db#(virtual bus_if)::get(this, "", "bus_vif", in_cfg.vif))
`uvm_fatal("NOVIF", "")
in_cfg.has_coverage = 0;
uvm_config_db#(bus_agent_cfg)::set(this, "env.agt_in", "cfg", in_cfg);
env = my_env::type_id::create("env", this);
endfunction
One object per component keeps the database small and makes every setting easy to find. Many teams also build an env config object that contains the agent configs.
Part 4: Paths, wildcards and precedence
- The context argument (
thisornull) plus the path string form the full path:set(this, "env.agt_in*", ...)from the test means uvm_test_top.env.agt_in and everything under it. - During build_phase, a setting from higher in the hierarchy wins over one from lower down. After build, the last setting wins.
- Use
+UVM_CONFIG_DB_TRACEto log every set and get; it finds path typos fast.
Part 5: The command-line processor
| Plusarg | Effect |
|---|---|
| +UVM_TESTNAME=err_test | Choose which test run_test() builds |
| +UVM_VERBOSITY=UVM_HIGH | Set the global message verbosity |
| +uvm_set_verbosity=… | Change verbosity for specific components or IDs |
| +uvm_set_config_int=env.agt_in,timeout_cycles,5000 | Set an int field through the config database |
| +UVM_TIMEOUT=1000000 | Global timeout |
| +UVM_MAX_QUIT_COUNT=10 | Stop after this many errors |
// your own options
uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst();
string val;
if (clp.get_arg_value("+NUM_PKTS=", val)) num_pkts = val.atoi();
Part 6: Mistakes I see often
- Not checking the return value of get(), so a missing setting goes unnoticed.
- Setting configuration after the component has already run its build_phase.
- Type mismatches (int vs int unsigned, interface with vs without modport).
- Too many individual fields in the database instead of config objects.
Practise this on VLSI Forge
I built VLSI Forge so you can write RTL in your browser, run it on a real simulator and check every signal in the waveform. Free, nothing to install.
Design Verification problems · Daily challenge
Previous in my UVM series: The UVM factory. Next: TLM and analysis ports.
FAQ
What is uvm_config_db used for?
Passing configuration values, configuration objects and virtual interfaces down the UVM hierarchy without hard-coded handles.
Why does uvm_config_db get() fail?
Usually a path that doesn’t match, a type mismatch between set and get, or the set happening after the get. +UVM_CONFIG_DB_TRACE shows what happened.
How do I choose a test from the command line?
Call run_test() with no argument and pass +UVM_TESTNAME=my_test to the simulator.
Should I use config objects or individual fields?
Config objects. They group related settings, are easy to randomise and keep the database small.
