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
    • UVM Factory: Registration, Overrides and Debug
      • The Factory: Swapping Classes Without Editing the Env
      • Registration Macros: What uvm_component_utils Writes for You
      • The type_id::create Pattern
      • Override Resolution: Who Wins
      • Override Timing, Safety and Debug
      • Factory Advanced: Parameterized, Abstract and By-Name
      • Command-Line Overrides
      • Overriding Items and Sequences
    • config_db and Resources
  • 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
Loading lesson

‹UVM Factory: Registration, Overrides and Debug
  1. Topics
  2. UVM Verification
  3. Factory & Configuration
  4. UVM Factory: Registration, Overrides and Debug
  5. Override Resolution: Who Wins

Part 3/Factory & ConfigurationIntermediate

Override Resolution: Who Wins

The one home for the factory's lookup rules: instance overrides are searched first and the first match wins, then type overrides, then the result is resolved again (chaining).

On this page

    The interviewer draws two boxes. "The test sets a type override from axis_driver to drv_a, then an instance override at *.in_agt.drv to drv_b, then another instance override at uvm_test_top.env.in_agt.drv to drv_c. What gets built at uvm_test_top.env.in_agt.drv?" Most candidates say drv_c, because it is the most specific path. It is drv_b. This lesson is the one place in the course where the lookup rules are taught; every other lesson links here.

    The idea: a short checklist, run at every create

    Think of a hotel front desk with two binders. The first binder holds instance notes ("the guest in room 3 gets the suite"), in the order they were written. The clerk reads from the top and acts on the first note that matches the room; later notes are never read. Only if no instance note matches does the clerk open the second binder, the type notes ("anyone booked as standard gets deluxe"), where each booking type has at most one live entry. Whatever the binders say, the clerk then checks the binders again for the new room type, in case it has its own note. That second look is chaining.

    Path specificity is not part of the checklist. A broad instance pattern written first beats a narrow one written later. This surprises people because config_db also ignores specificity, for a different reason; its rules live in config_db resolution order.

    The picture

    Flowchart: check instance overrides in order for a first match, else the type override, else build the requested type; then resolve the winner again for chaining.
    The factory's lookup for one create call. Instance overrides are checked first, in the order they were registered, and the first match wins. Type overrides are checked only if no instance override matches. The result is then resolved again, which is how chains A to B to C work.

    Build it: the rules one at a time

    Rule 1: the instance path is formed at create time

    For a component, the path is the parent's full name, a dot, and the child's name: the agent's create("drv", this) inside uvm_test_top.env.in_agt is resolved for uvm_test_top.env.in_agt.drv. For an object, the path is the context string plus the name (or just the name with no context). Instance override patterns are glob-matched against this string, so * and ? work.

    Rule 2: instance overrides first, first match wins

    set_inst_override_by_type(original, override, full_inst_path) appends to an ordered list. The lookup walks the list from the start and stops at the first entry whose original type and path both match. There is no replace flag on instance overrides. So register the most specific instance overrides first, then the broader ones.

    design.sv
    1
    2
    3
    4
    5
    6
    // snippet: in a test's build_phase, before the env creates its children
    // The narrow override first, so it is found first.
    axis_driver::type_id::set_inst_override(drv_c::get_type(), "env.in_agt.drv", this);
    axis_driver::type_id::set_inst_override(drv_b::get_type(), "env.*.drv", this);
    // type_id::set_inst_override(type, path, this) prefixes the path with this
    // component's full name: "uvm_test_top.env.in_agt.drv".

    Rule 3: type overrides only when no instance override matches

    set_type_override_by_type(original, override, replace = 1) keeps one live entry per original type. A second type override for the same type replaces the first when replace is 1 (the default); with replace = 0 the existing entry is kept and the new one is ignored. A type override applies to every path, but any matching instance override beats it, whenever each was registered.

    Rule 4: the winner is resolved again

    After choosing a winner, the factory looks up overrides for the winner's type at the same path. So axis_driver → axis_truncating_driver plus axis_truncating_driver → axis_trunc_logging_driver builds the logging one wherever an axis_driver is requested. A cycle (A → B, B → A) is detected and reported as OVRDLOOP. Chains are useful when one test adds a refinement on top of a base test's override, without knowing about it.

    Rule 5: overrides are global for the rest of the run

    The factory is a single object for the whole simulation. An override applies to every matching create from the moment it is registered, in every part of the bench, including objects created during run_phase. A type override on axis_item therefore changes the items the monitors create too, not only the stimulus. There is no call to remove an override, so a test that needs a substitution only in one place uses an instance override with a path, not a type override and a hope.

    The opening question, resolved

    Order set

    Override

    Matches uvm_test_top.env.in_agt.drv?

    Outcome

    1

    type: axis_driver → drv_a

    yes (every path)

    checked last

    2

    instance *.in_agt.drv → drv_b

    yes

    first instance match: drv_b wins

    3

    instance uvm_test_top.env.in_agt.drv → drv_c

    yes

    never reached

    Swap the order of the two instance overrides and drv_c wins. Remove both and drv_a wins. Nothing about how narrow a path is changes the answer.

    Watch it run

    The factory explains its own decision. debug_create_by_type runs the same lookup without building anything and prints every override it considered, with the one it chose marked. In a test you would call:

    design.sv
    // snippet: in the test's end_of_elaboration_phase
    uvm_factory::get().debug_create_by_type(axis_driver::get_type(), "uvm_test_top.env.in_agt", "drv");
    uvm_factory::get().print();   // registered overrides (and user types)

    Run on a scratch copy of the bench with drv_a, drv_b and drv_c added and the three overrides registered in the table's order, print() shows the registered overrides in order, and the topology shows what was built:

    Diagram
    #### Factory Configuration (*)
    
    Instance Overrides:
    
      Requested Type  Override Path                Override Type
      --------------  ---------------------------  -------------
      axis_driver     *.in_agt.drv                 drv_b
      axis_driver     uvm_test_top.env.in_agt.drv  drv_c
    
    Type Overrides:
    
      Requested Type  Override Type
      --------------  ---------------------------
      axis_driver     drv_a
    
    UVM_INFO dbg_tb.sv(2000) @ 0: uvm_test_top [OVR] in_agt.drv is drv_b
    • The instance overrides are listed in registration order, which is the order the lookup walks: drv_b is first and wins, exactly as the table predicts.

    • The type override is listed separately; it would apply only to a path no instance override matches.

    Do not trust debug_create_by_type alone. On the Accellera 1800.2-2020.3.2 library this course runs, the same call for uvm_test_top.env.in_agt.drv printed the factory encountered no relevant overrides and will produce an object of type 'drv_a', while the factory really built drv_b. In its debug pass the library keeps searching after the instance match and lets the type override replace it, and the report lists no overrides at all. Confirm with print() and the topology (or get_type_name() on the built component). The UVM 1.2 report was not checked here.

    The bench's own evidence is simpler: dma_truncate_test registers one type override, there are no instance overrides, so Rule 3 applies at uvm_test_top.env.in_agt.drv and the log line comes from the derived class:

    Diagram
    UVM_INFO dma_tb.sv(520) @ 275000: uvm_test_top.env.in_agt.drv [TRUNC] TLAST forced on beat 3

    What breaks: the instance override that a base test had already beaten

    A team had a base test that registered set_inst_override_by_type(axis_driver::get_type(), slow_driver::get_type(), "*") to slow every stream driver. A derived test added an instance override for uvm_test_top.env.in_agt.drv to an error-injecting driver. The error driver never appeared. The derived test's build_phase called super.build_phase first, so the base test's broad "*" entry was already first in the list, and the first match won.

    Two fixes, both legitimate. Register the derived test's narrow override before calling super.build_phase, so it is earlier in the list; or make the error driver extend slow_driver and add a type override slow_driver → err_driver, so chaining refines the base test's choice. The second is more robust, because it does not depend on call order across a test hierarchy.

    "A type override and an instance override both match. Which wins? And two instance overrides?"

    A weak answer: "The most specific one wins, so the instance override, and between two instance overrides the one with the more exact path."

    A strong answer: "Instance overrides are checked first, so any matching instance override beats a type override. Among instance overrides there's no specificity rule: they're searched in registration order and the first match wins, so you register narrow ones first. Type overrides have one entry per type; a second one replaces the first by default. Then the winner is looked up again, so overrides chain. When in doubt I call debug_create_by_type for the path."

    Follow-ups: How do you override only one of two identical agents? (an instance override on that agent's path) and What happens with A to B and B to A? (an OVRDLOOP error, and A is built).

    Check yourself A test sets set_type_override_by_type(axis_driver, drv_a) and later set_type_override_by_type(axis_driver, drv_b, 0). What gets built for in_agt.drv?

    drv_a. The second call has replace = 0, so the existing entry for axis_driver is kept and the new one is ignored (UVM reports it at medium verbosity). With the default replace = 1, drv_b would replace it.

    Check yourself Overrides: type axis_driver → drv_x, then type drv_x → drv_y, then instance *.in_agt.drv: axis_driver → drv_z. What is built at uvm_test_top.env.in_agt.drv, and at a hypothetical uvm_test_top.env.aux_agt.drv?

    At in_agt.drv: the instance override matches first, so the winner is drv_z; it has no override of its own, so drv_z is built. At aux_agt.drv: no instance match, the type override gives drv_x, and resolving again finds drv_x → drv_y, so drv_y is built through the chain.

    Check yourself Why is "register specific instance overrides first" fragile in a deep test hierarchy, and what is more robust?

    Order depends on where each test calls super.build_phase relative to its own overrides, which a derived-test author may not control. Chaining is order-independent: derive the new class from the base test's override class and type-override that class, so the base choice is refined rather than raced.

    Next: the rules assume the override is registered before the create runs, and that the new class's code actually executes. Override timing, safety and debug covers both, with a real bench bug.

    Related topics

    • The type_id::create pattern

    • Override timing, safety and debug

    • Factory advanced

    • config_db resolution order

    Previous

    48 / 280

    Next: Override Timing, Safety and Debug

    Up next

    Up nextOverride Timing, Safety and Debug

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The Factory: Swapping Classes Without Editing the Env
    • Registration Macros: What uvm_component_utils Writes for You
    • Factory Advanced: Parameterized, Abstract and By-Name