← Design Verification Interviews

Interview Question · Debug

A Config Database Get That Found Nothing

L1 JuniorL2 Mid-Leveluvmconfigurationdebug

The Question

The interviewer asks

The driver stops with this fatal error, yet the top module does set the interface. Config tracing was on. What is wrong?

log
UVM_INFO uvm/base/uvm_config_db_implementation.svh(485) @ 0: reporter [CFGDB/SET] Configuration scope='uvm_test_top.env.agent.*' name='vif' (type PARAMTYPEDTYPE 'T') set accessor= = (PARAMTYPEDTYPE 'T') 3815468544
UVM_INFO @ 0: reporter [RNTST] Running test smoke_test...
UVM_INFO uvm/base/uvm_config_db_implementation.svh(485) @ 0: reporter [CFGDB/GET] Configuration scope='uvm_test_top.env.agt.drv' name='vif' (type PARAMTYPEDTYPE 'T') read accessor=uvm_test_top.env.agt.drv = null (failed lookup)
UVM_FATAL main.sv(14) @ 0: uvm_test_top.env.agt.drv [NOVIF] no virtual interface for uvm_test_top.env.agt.drv
Reveal the Model Answer

A get matches only when three things agree: the type parameter, the scope and the field name. It returns 0 and never says which one differed. The trace lines show the cause here. The set used the scope uvm_test_top.env.agent.*, but the driver is uvm_test_top.env.agt.drv. Compare each set with the failing get, string by string.

One Setting Arrives, One Is LostArrows point from the code that stores a setting into uvm_config_db, and from the table to the code that reads it. A get travels against the arrow; the value, if found, travels with it.
One setting arrives, one is lostArrows point from the code that stores a setting into `uvm_config_db`, and from the table to the code that reads it. A `get` travels against the arrow; the value, if found, travels with it. module tb module stores vif test incr_test stores count table uvm_config_db scope, field, type,value component env.agent get(this, "", "vif",vif) sequence seq get(null,get_full_name(),"count", count) component drv and mon drive and watch thepins set vifset countvifcountvif handed down
  1. Before run_test0 ns (illustrative)

    The top module stores the interface handle with the scope uvm_test_top.env.agent, then calls run_test.

    Follow the calls, values and waits
    1. data vif = bus: tb module → uvm_config_db
  2. The test builds0 ns (illustrative)

    The test stores count=5 with the scope uvm_test_top.env.agnet.sqr.*. The scope is misspelled, and nothing checks a scope when it is stored.

    Follow the calls, values and waits
    1. data count = 5: incr_test → uvm_config_db
  3. The agent builds0 ns (illustrative)

    The agent looks up its own path, uvm_test_top.env.agent. Path, field and type all match, so get returns 1 and the agent passes the handle to its driver and monitor.

    Follow the calls, values and waits
    1. call get vif: env.agent → uvm_config_db
    2. data vif: uvm_config_db → env.agent
    3. data vif: env.agent → drv and mon
  4. The sequence starts0 ns (illustrative)

    In body() the sequence looks up uvm_test_top.env.agent.sqr.seq. No scope matches that path, so get returns 0 and count keeps its default, 3.

    Follow the calls, values and waits
    1. call get count: seq → uvm_config_db
    2. return no match: uvm_config_db → seq
  5. The report phase60 ns (illustrative)

    The scoreboard reports 3 checked. check_config_usage() lists the entry nobody read, and its scope shows the typo.

Read the diagram as text
  • tb module: stores vif
  • incr_test: stores count
  • uvm_config_db: scope, field, type, value
  • env.agent: get(this, "", "vif", vif)
  • seq: get(null, get_full_name(), "count", count)
  • drv and mon: drive and watch the pins
  • tb module → uvm_config_db: set vif
  • incr_test → uvm_config_db: set count
  • uvm_config_db → env.agent: vif
  • uvm_config_db → seq: count
  • env.agent → drv and mon: vif handed down

A scope is a string. Only a lookup that matches it, or check_config_usage(), shows whether it is right.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Junior)

A good junior answer lists the three things a get must match: type, scope and field name. It checks each one of the set against the get.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

What IfProve ItBreak ItCompare

  1. A Config Database Get That Found Nothing
  2. Prove ItTracing the Config DatabaseL1 Junior

    Show how you would trace every set and get in the config database.

    Reveal the Model Answer

    Run with +UVM_CONFIG_DB_TRACE, or call uvm_config_db_options::turn_on_tracing() before run_test. Each set and each get prints a line with its scope and field. At the end, check_config_usage() lists sets that no component ever read, which is how typos usually show up.

    Self-Check

    Tick each key point you covered in your answer.

    Tool as Truth

    "Raise the verbosity to UVM_DEBUG to see config lookups."

    Verbosity alone does not print them. Config tracing is a separate switch.

    Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_cmdline_processor.svh, +UVM_CONFIG_DB_TRACE

  3. What IfReading a Set and Get That Do Not MeetL1 JuniorL2 Mid-Level

    What if the trace shows the set and the get, but they never meet? What do you compare?

    Reveal the Model Answer

    Compare the scope strings first: a missing level, a typo or a wrong wildcard shows at once. Then compare the field names. Last, compare the types, because the database is keyed by type too. A set of int is not found by a get of bit [31:0].

    Self-Check

    Tick each key point you covered in your answer.

    Missed Corner

    "The same field name means the get will find it."

    The type parameter must match as well. A different type is a different entry, so the get misses.

    Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_config_db.svh

  4. What IfSetting the Interface in Another Initial BlockL2 Mid-Level

    What if one initial block sets the interface and a different initial block calls run_test?

    Reveal the Model Answer

    Both blocks start at time 0, and the standard does not fix their order. The bench may work on one simulator and fail on another, or after an unrelated edit. Put the set before run_test in the same block, so the order is written in the code.

    Self-Check

    Tick each key point you covered in your answer.

    Tool as Truth

    "Initial blocks run in the order they appear in the file."

    Many tools happen to do that, but the language leaves the order of processes at the same time undefined.

    Source IEEE 1800-2017 §4.7

  5. Break ItA Wildcard That Gave Two Agents One BusL2 Mid-Level

    How can set(null, "*", "vif", bus0) break a bench with two agents on two buses, without any error?

    Reveal the Model Answer

    The * scope matches every component, so both agents get bus0. Neither get fails, so nothing reports a problem. The second agent drives and watches the wrong bus, and its checks see the first bus's traffic. Set each interface for its own agent path.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "The second set for the other agent will override it."

    Only if it comes later from the same context, or from higher up. A broad set from the top can still win.

    Source Verification Academy, UVM Cookbook, Precedence Rules (PDF p140)

  6. Prove ItSolve 6.4.1: Give Each Driver Its Own BusSimulator-graded

    Show it, don't just say it: this Silicon Lab problem is graded by the simulator.

    Open Problem 6.4.1

  7. CompareConfig DB vs Resource DBL3 Senior

    Compare uvm_config_db with uvm_resource_db. Why do most benches use only the first?

    Reveal the Model Answer

    Both store values in the same resource pool. uvm_config_db adds the component tree: scopes are built from a context component, and build-phase precedence follows the hierarchy. uvm_resource_db takes raw scope strings and has no hierarchy rules. Benches use config_db because its rules match how tests override environments.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "They are two separate databases."

    config_db is a layer over the resource pool, so a value set through one can be seen through the other.

    Source Accellera, UVM 1.1 User's Guide, §4.5.3 Choosing between uvm_resource_db and uvm_config_db (PDF p72)

What People Get Wrong

Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.

Misconception

"Any integer type matches a value set as int."

The lookup uses the exact type parameter. int and bit [7:0] are different types, so the get fails and the default stays.

Run It

The test sets width as an int; the agent reads it as bit [7:0].

RUNVerilator + UVM 2020.3.1 · simulator service
Edit the code, then run it
Expected among the UVM messages: get returned 0, width=32 FAIL: the test set an int but the agent asked for bit [7:0], so get found nothing and the default stayed
See the Fix
`timescale 1ns/1ns
`include "uvm_macros.svh"
import uvm_pkg::*;
class bus_agent extends uvm_agent;
  `uvm_component_utils(bus_agent)
  bit [7:0] width = 32;
  function new(string name, uvm_component parent); super.new(name, parent); endfunction
  function void build_phase(uvm_phase phase);
    bit found;
    int w;
    found = uvm_config_db #(int)::get(this, "", "width", w);   // the fix: the same type as the set
    if (found) width = 8'(w);
    $display("get returned %0d, width=%0d", found, width);
    if (!found) $display("FAIL: the test set an int but the agent asked for bit [7:0], so get found nothing and the default stayed");
    else $display("PASS: the types match and the agent got the test's width");
  endfunction
endclass
class env_t extends uvm_env;
  `uvm_component_utils(env_t)
  bus_agent agt;
  function new(string name, uvm_component parent); super.new(name, parent); endfunction
  function void build_phase(uvm_phase phase); agt = bus_agent::type_id::create("agt", this); endfunction
endclass
class width_test extends uvm_test;
  `uvm_component_utils(width_test)
  env_t env;
  function new(string name, uvm_component parent); super.new(name, parent); endfunction
  function void build_phase(uvm_phase phase);
    uvm_config_db #(int)::set(this, "env.agt", "width", 8);
    env = env_t::type_id::create("env", this);
  endfunction
endclass
module tb;
  initial run_test("width_test");
endmodule

Prints: get returned 1, width=8 PASS: the types match and the agent got the test's width

Misconception

"If nothing matches, get reports an error."

get returns a bit and reports nothing. The message in the log is the bench's own fatal call.

Source IEEE 1800.2-2020 §C.4.2.2.2 get (uvm-core base/uvm_config_db.svh)

Buzzword Without Mechanism

"It's a config_db problem."

That names the area, not the cause. The useful answer says which of type, scope or field differed, and how the trace showed it.

Learn It, Then Prove It