Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
  • Factory & Configuration15
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
    • Verification Architecture and Planning
    • UVM with SVA and Formal
    • Leadership and Senior Judgment
    • Interview Bank
      • Concept Round: Phases, Objections and End of Test
      • Concept Round: Factory and config_db
      • Concept Round: TLM and Analysis
      • Concept Round: Sequences, Sequencers and Drivers
      • Concept Round: Agents, Drivers and Monitors
      • Concept Round: Register Layer and Checking
      • Closure and Sign-off Questions
      • Behavioural Round
      • Coding Round: Whiteboard Drills
      • Debug Round: Find the Bug in This Log
      • Architecture Round: Design the Verification
      • High-Frequency Question Index
      • The Senior DV Interview Loop
Loading lesson

‹Interview Bank
  1. Topics
  2. UVM Verification
  3. Senior Prep: Architecture, Leadership and Interviews
  4. Interview Bank
  5. Concept Round: Factory and config_db

Part 13/Senior PrepIntermediate

Concept Round: Factory and config_db

Eleven high-frequency questions on create versus new, type and instance overrides, config_db precedence, wildcards, +UVM_TESTNAME and command-line config, with weak and senior answers.

On this page

    This round is where interviewers separate people who have used the factory from people who have debugged it. Almost every question has a confident wrong answer that sounds right: "the more specific path wins", "the last override wins", "run_test's argument picks the test". Each of those is false in the library, and the interviewer knows it.

    A senior answer states the rule as the library implements it, says why the rule exists, and names how you would prove it on a live bench (a factory print, a config trace). The DMA bench supplies the examples: a type override that cuts packets short, an instance override that swaps one agent, and a passive agent that only stays passive if super.build_phase() runs.

    The questions

    Why type_id::create() instead of new()? Is new() illegal on a component?

    Weak answer: new() is illegal on components, so you have to use create.

    Strong answer: new() on a component is legal SystemVerilog; only uvm_root's constructor is protected. create() is the convention because it asks the factory, so overrides apply. A component built with new() is hard-wired: in dma_truncate_test, the type override of axis_driver with axis_truncating_driver would silently do nothing for that instance. The name argument should equal the handle name, because instance overrides and config paths match on it.

    Follow-up: “Does the same apply to sequence items?” Yes. An item made with new() in a sequence cannot be replaced by a test's type override; one made with type_id::create() can, from the next creation on.

    Home lesson: The type_id::create pattern

    A derived class has no registration macro. What happens when you create it or override to it?

    Weak answer: It fails to compile.

    Strong answer: It compiles. The derived class inherits its parent's type_id, so child::type_id::create() builds the parent, and get_type() returns the parent's wrapper, so an override "to the child" maps the parent to itself. No error, no warning, and the new behaviour never runs. A factory print shows it at once: the child is simply not registered.

    Follow-up: “What is the other silent override failure?” Non-virtual methods. On the DMA bench a factory-overridden scoreboard's write_* methods never ran, because the analysis imps call them through the base type and non-virtual methods bind at compile time. The bench's scoreboard methods are virtual for that reason.

    Home lesson: Registration macros

    Two instance overrides match the same path. Which one wins? And two type overrides?

    Weak answer: The last one wins, like config_db.

    Strong answer: For instance overrides, the first registered matching override wins: they are pushed in order and the lookup stops at the first match, and there is no replace flag. Type overrides have a replace argument, default 1, so a second type override for the same type replaces the first. The trap in practice: a base test registers an instance override for *.out_agt, a derived test adds a more specific one for env.out_agt, and the base's still wins because it was registered first. On the DMA bench, dma_backpressure_test swaps only env.out_agt to axis_sink_agent; env.in_agt keeps axis_agent.

    Follow-up: “Is the instance path relative?” With the form the bench uses, axis_agent::type_id::set_inst_override(axis_sink_agent::get_type(), "env.out_agt", this), the path is relative to the caller, so it means uvm_test_top.env.out_agt.

    Home lesson: How create resolves overrides

    When must an override be registered for it to take effect?

    Weak answer: Anywhere in the test; the factory applies it.

    Strong answer: Overrides are read at create time, so they must be registered before the object is created. In practice that is the test's build_phase, before the env is created: dma_truncate_test calls set_type_override and then super.build_phase(phase), with the comment that the env is created after the override. An override registered after creation changes nothing for objects that already exist; for items created per transaction it applies from then on.

    Follow-up: “Can you override from the command line?” Yes: +uvm_set_type_override=<req>,<override>[,<replace>] and +uvm_set_inst_override=<req>,<override>,<full_path>, applied in uvm_root's build_phase, before the test's build_phase creates anything. The test object itself already exists by then, so it cannot be replaced this way.

    Home lesson: Command-line overrides

    The env and the test both set the same config_db field for the agent. Which value does the agent get?

    Weak answer: The more specific path wins, or else the last set.

    Strong answer: During build_phase, the setter higher in the hierarchy wins: precedence is 1000 minus the setter's depth, so uvm_top or a null context is 1000, the test usually 999, the env 998. The test wins even if the env set later and even if the env used an exact path while the test used a wildcard; path specificity does not decide precedence. Between sets of equal precedence, and for every set made after build, the last set wins. The point of the rule: a test can override an env default without editing the env.

    Follow-up: “How do you debug a config surprise?” +UVM_CONFIG_DB_TRACE shows every set and get with its scope; print_config() and check_config_usage() show what was set and never read.

    Home lesson: Config resolution order

    You set is_active with the path "env.agt.*". Does the agent see it?

    Weak answer: Yes, the wildcard covers the agent and everything under it.

    Strong answer: No. The glob must match the getter's full name, and env.agt.* needs something after env.agt., so it matches env.agt.drv but not env.agt. Set on env.agt as well, or use env.agt* and accept that it also matches env.agt2. And the pattern decides only reach; who wins is still setter depth during build, then the last set.

    Follow-up: “How does a sequence read config, since it has no place in the tree?” With get(null, get_full_name(), ...): a running sequence's full name is its sequencer's path plus its own name, so sets scoped to that path reach it. get(m_sequencer, "", ...) reads the sequencer's own settings instead.

    Home lesson: Instance paths and wildcards

    The top calls run_test("dma_smoke_test") and the command line has +UVM_TESTNAME=dma_rand_test. Which test runs?

    Weak answer: run_test's argument; the plusarg is only a fallback.

    Strong answer: dma_rand_test. uvm_root::run_test reads +UVM_TESTNAME and overwrites the argument. That is why benches call run_test() with no argument (or a harmless default) and let the regression choose per run. A name that was never registered is a fatal at time 0, which is also what you get when a test class is in a file that was not compiled.

    Follow-up: “What if the plusarg appears twice?” The library uses the first one and warns that several were given; a wrapper script that appends its own +UVM_TESTNAME is a classic way to run the wrong test.

    Home lesson: Selecting the test with +UVM_TESTNAME

    You pass +uvm_set_config_int=uvm_test_top.env,num_jobs,5 and the env's config_db#(int)::get misses it. Why?

    Weak answer: The path is wrong; command-line config works like any set.

    Strong answer: The path may be fine. +uvm_set_config_int stores a uvm_bitstream_t, so it is seen by config_db#(uvm_bitstream_t) and by field-macro auto-config, not by config_db#(int)::get. The type is part of the key. Read it as uvm_bitstream_t (or a field macro), or use your own plusarg with $value$plusargs.

    Follow-up: “And strings?” +uvm_set_config_string stores a string, so config_db#(string)::get sees it.

    Home lesson: Command-line overrides

    Your agent's build_phase skips super.build_phase(). What breaks?

    Weak answer: Nothing; the base build_phase is empty.

    Strong answer: uvm_component::build_phase calls build(), which calls apply_config_settings() when automatic config is on; that is how field-macro fields get configured. uvm_agent::build_phase also reads is_active there. Skip super.build_phase() in your agent and is_active stays UVM_ACTIVE: on the DMA bench, the output-side agent the env set passive would build a driver for the DMA's output port.

    Follow-up: “Where should the call go?” First, before your own get() calls and conditional creation, so the base configuration is in place.

    Home lesson: Why super.build_phase() matters

    One config object per agent, or many scalar config_db entries?

    Weak answer: Many scalars; each knob can be set independently.

    Strong answer: One typed config object per agent, set once by the env or test and read once in build. It carries the virtual interface, is_active and protocol knobs; it can have constraints and be randomized; and a typo becomes a compile error instead of a silent miss. config_db lookups are string matches over the resource pool, so their cost grows with the number of entries and wildcards: never call get() per transaction in run_phase.

    Follow-up: “Can the config change during the run?” The object is a handle, so a component that reads a field when it uses it sees the change; document which fields are live. For a value that must wake a component, wait_modified() exists but is rarely the cleanest answer.

    Home lesson: config_db performance

    How do you prove which class the factory actually built?

    Weak answer: Turn on +UVM_FACTORY_TRACE.

    Strong answer: +UVM_FACTORY_TRACE does not exist. Use uvm_factory::get().print() to list registered types and overrides, debug_create_by_type() to see how one request resolves, and the topology print at end of elaboration to see the classes that were built. When an override seems ignored, the cause is almost always one of four: registered too late, new() instead of create(), a missing macro, or an earlier instance override matching first.

    Follow-up: “What does create_component_by_type take?” Four arguments, (requested_type, parent_inst_path, name, parent), and it returns uvm_component.

    Home lesson: Override debug patterns

    Rapid fire

    Check yourself The env sets max_len to 16 at the end of its build_phase; the test set it to 64 earlier in its own build_phase. What does the agent read, and would it change if the env set it in run_phase?

    64 during build: the test's set has precedence 999 against the env's 998, whatever the order. In run_phase the rule changes: the last set wins, so a get after the env's run-time set reads 16.

    Check yourself A derived test adds set_inst_override for env.out_agt to a new monitor-only agent, but the base test already overrode *.out_agt. Which agent is built?

    The base test's choice. Instance overrides are matched in registration order and the first match wins; the base test's build_phase registered its override first.

    Check yourself A test calls super.build_phase() (where the base test creates the env) and only then registers a type override for the stream driver. Does the override apply to the driver? Would an override of the env type apply?

    The driver override applies: the env object exists, but its build_phase, which creates the agents and their drivers, runs after the test's build_phase returns. An env-type override does not, because the env was already created. Register overrides before super.build_phase() so the answer never depends on who creates what.

    Next: Concept Round: TLM and Analysis: the scoreboard compared nothing; where did the transactions go?

    Previous

    269 / 280

    Next: Concept Round: TLM and Analysis

    Up next

    Up nextConcept Round: TLM and Analysis

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Concept Round: Sequences, Sequencers and Drivers
    • Concept Round: Agents, Drivers and Monitors
    • Concept Round: Register Layer and Checking