← Design Verification Interviews

Interview Question · Code Reading

Who Wins in the Config Database

L1 JuniorL2 Mid-Leveluvmconfiguration

The Question

The interviewer asks

The env sets depth to 16 for its agent. The test, above it, sets 4. What does the agent read?

systemverilog
// In the env:
function void build_phase(uvm_phase phase);
  uvm_config_db #(int)::set(this, "agt", "depth", 16);
  agt = cfg_agent::type_id::create("agt", this);
endfunction
// In the test, above the env:
function void build_phase(uvm_phase phase);
  uvm_config_db #(int)::set(this, "env.agt", "depth", 4);
  env = cfg_env::type_id::create("env", this);
endfunction
// The agent reads depth in its build_phase. What does it get?
Reveal the Model Answer

It reads 4. During the build phase, a set made from higher in the hierarchy wins over one made lower down. The test is above the env, so the test's value wins. This lets a test change an environment default without editing the environment. When both sets come from the same component, or after build, the latest set wins.

Two Settings for the Same Agent Field During Build
012build steptestenvagentsetting madecount=5count=9-setter depth12-agent would read5later, but lower: losesget returns 5
  1. Cycle 0

    The test builds first and stores count=5 for the agent. The test sits one level below the root (depth 1).

  2. Cycle 1

    The environment builds next and stores count=9 for the same path. It comes later, but from two levels below the root (depth 2), lower in the tree.

  3. Cycle 2

    The agent's get matches both entries and returns the one made higher in the tree: 5.

The environment's setting comes later, but it was made lower in the tree. So the agent reads the test's value.

The interview's env and test, with an agent that prints what it read.

RUNVerilator + UVM 2020.3.1 · simulator service
Edit the code, then run it
Expected among the UVM messages: uvm_test_top.env.agt depth=4

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Junior)

A good junior answer gives 4. It explains this by the test sitting higher in the component tree than the environment.

Cross-Questions

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

WhyWhat IfProve ItCompareScale It

  1. Who Wins in the Config Database
  2. WhyWhy the Higher Set WinsL1 Junior

    Why did UVM choose "higher in the tree wins" during build?

    Reveal the Model Answer

    The environment is written once and reused by many tests, so its sets are defaults. The test is the most specific description of one scenario, so it must be able to override them. Making the shallower setter win gives the test that power without editing shared code.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "It is because the test builds first."

    Order alone would make the env's later set win. The library ranks build-phase sets by the setter's depth.

    Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_config_db_implementation.svh set(), precedence by cntxt depth

  3. What IfConfig Precedence After BuildL2 Mid-Level

    What if the env sets a value again during run_phase, after the test set it in build? Who wins now?

    Reveal the Model Answer

    The env's new set wins. Depth gives precedence only while the build phase runs. After build, every set gets the same precedence, so the most recent set wins. A component that reads the value again then sees the env's value.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "The test always wins, even in the run phase."

    Depth decides only during build. After that the most recent set wins, wherever it came from.

    Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_config_db_implementation.svh set(), precedence by cntxt depth

  4. What IfChanging Configuration During RunL2 Mid-Level

    Asked if they mention run_phase

    What if a test changes depth with uvm_config_db::set in the middle of run_phase?

    Reveal the Model Answer

    The database holds the new value, and the latest set wins. But the agent read depth once in build, so its variable does not change. A component that must react has to call get again, or wait with uvm_config_db::wait_modified(). For run-time control, a shared config object or an event is usually clearer.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Setting it updates the agent's variable."

    A get copies the value at that moment. Nothing pushes later changes into the component.

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

  5. CompareOne Config Object vs Many FieldsL2 Mid-Level

    Compare setting ten separate fields for an agent with setting one agent configuration object.

    Reveal the Model Answer

    Ten fields mean ten string lookups, ten chances to misspell a name and no single place that lists the agent's options. One config object is typed, holds the virtual interface and the active or passive choice, and needs one get. The test builds it, fills it and sets it once for the agent's path.

    One Handle in, Two Handles OutOne configuration object per agent, passed down one layer at a time. Each arrow is one set or one get; a get returns a handle and leaves the entry in place.
    One handle in, two handles outOne configuration object per agent, passed down one layer at a time. Each arrow is one `set` or one `get`; a `get` returns a handle and leaves the entry in place. test chip_test Createschip_env_cfg and oneincr_agent_cfg perport config store config db: "env" Entry cfg =chip_env_cfg handle env chip_env Knows only its ownchildren config store config db:"port_a","port_b" Entries cfg.port_aand cfg.port_b agent port_a lane 0, UVM_ACTIVE agent port_b lane 1,UVM_PASSIVE set for "env"get returns handleset, relative namesgetget
    1. Test build_phase

      The test fills chip_env_cfg and its two agent objects, then sets the parent object once, for "env".

      Follow the calls, values and waits
      1. data chip_env_cfg handle: chip_test → config db: "env"
    2. Env build_phase: get

      The environment gets the parent object.

      Follow the calls, values and waits
      1. data chip_env_cfg handle: config db: "env" → chip_env
    3. Env build_phase: set

      It sets cfg.port_a for "port_a" and cfg.port_b for "port_b", names relative to itself.

      Follow the calls, values and waits
      1. data cfg.port_a handle: chip_env → config db: "port_a", "port_b"
      2. data cfg.port_b handle: chip_env → config db: "port_a", "port_b"
    4. Agent build_phase

      Each agent gets its own object, copies is_active from it and builds its children.

      Follow the calls, values and waits
      1. data cfg.port_a handle: config db: "port_a", "port_b" → port_a
      2. data cfg.port_b handle: config db: "port_a", "port_b" → port_b
    5. A run-time change5–10 ns (illustrative)

      The test clears checks_on in port_b's object at 5 ns. port_b reads 0 at 10 ns, with no new set or get.

    Read the diagram as text
    • chip_test: Creates chip_env_cfg and one incr_agent_cfg per port
    • config db: "env": Entry cfg = chip_env_cfg handle
    • chip_env: Knows only its own children
    • config db: "port_a", "port_b": Entries cfg.port_a and cfg.port_b
    • port_a: lane 0, UVM_ACTIVE
    • port_b: lane 1, UVM_PASSIVE
    • chip_test → config db: "env": set for "env"
    • config db: "env" → chip_env: get returns handle
    • chip_env → config db: "port_a", "port_b": set, relative names
    • config db: "port_a", "port_b" → port_a: get
    • config db: "port_a", "port_b" → port_b: get

    No layer names a grandchild. Renaming port_b changes only the environment.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Config objects are slower because they are classes."

    One lookup of a handle is cheaper than many string lookups, and the fields are then read directly.

    Source Accellera, UVM 1.1 User's Guide, §4.5.4 Using a Configuration Class (PDF p72)

  6. Scale ItThe Config Database in a Large BenchL3 Senior

    Build time of your SoC bench has grown to minutes, and profiling points at uvm_config_db. What do you change?

    Reveal the Model Answer

    Every get searches the entries whose scope might match, and broad wildcards like * match every lookup. Scope sets to the exact paths that need them. Replace many scalar sets with one object per agent. Get each value once in build, never in a per-item loop.

    Self-Check

    Tick each key point you covered in your answer.

    Wrong Altitude

    "Use * everywhere so nothing is ever missed."

    A * scope enters every lookup in the bench. It also hands the value to components that should never see it.

    Source Verification Academy, UVM Cookbook, Configuring a Test Environment (PDF p132-140)

  7. Prove ItSolve U15.2.1: The Poison Test with a Short LedgerSimulator-graded

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

    Open Problem U15.2.1

What People Get Wrong

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

Misconception

"The closest set wins, so the env's 16 beats the test."

During build the depth of the setter decides, and shallower wins. The run prints depth=4.

Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_config_db_implementation.svh set(): build-phase precedence = default - depth of the setter

Misconception

"A specific path beats a wildcard from the same component."

From one context, the later set wins regardless of path. The twin's later env.* default overrode the earlier env.agt value.

Run It

The test sets one exception, then a wildcard default for everyone else.

RUNVerilator + UVM 2020.3.1 · simulator service
Edit the code, then run it
Expected among the UVM messages: uvm_test_top.env.agt depth=8 uvm_test_top.env.mon_agt depth=8 FAIL: both sets came from the test, so the later wildcard won; the more specific path did not
See the Fix
`timescale 1ns/1ns
`include "uvm_macros.svh"
import uvm_pkg::*;
class cfg_agent extends uvm_agent;
  `uvm_component_utils(cfg_agent)
  int depth = -1;
  function new(string name, uvm_component parent); super.new(name, parent); endfunction
  function void build_phase(uvm_phase phase);
    void'(uvm_config_db #(int)::get(this, "", "depth", depth));
    $display("%s depth=%0d", get_full_name(), depth);
  endfunction
endclass
class cfg_env extends uvm_env;
  `uvm_component_utils(cfg_env)
  cfg_agent agt, mon_agt;
  function new(string name, uvm_component parent); super.new(name, parent); endfunction
  function void build_phase(uvm_phase phase);
    agt = cfg_agent::type_id::create("agt", this);
    mon_agt = cfg_agent::type_id::create("mon_agt", this);
  endfunction
endclass
class cfg_test extends uvm_test;
  `uvm_component_utils(cfg_test)
  cfg_env 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.*", "depth", 8);     // the fix: the default first
    uvm_config_db #(int)::set(this, "env.agt", "depth", 4);   // then the exception
    env = cfg_env::type_id::create("env", this);
  endfunction
  function void end_of_elaboration_phase(uvm_phase phase);
    if (env.agt.depth != 4) $display("FAIL: both sets came from the test, so the later wildcard won; the more specific path did not");
    else $display("PASS: agt kept its own depth and mon_agt took the default");
  endfunction
endclass
module tb;
  initial run_test("cfg_test");
endmodule

Prints: uvm_test_top.env.agt depth=4 uvm_test_top.env.mon_agt depth=8 PASS: agt kept its own depth and mon_agt took the default

Missed Corner

"The same rule holds in run_phase."

After build, every set gets the same precedence, so the last one wins wherever it came from.

Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_config_db_implementation.svh set(): outside build, default precedence for all

Learn It, Then Prove It