Part 3 · Factory & Configuration · Intermediate
Overrides Debug Patterns: Print, Paths, and Conflict Triage
Deterministic override debug workflow, factory.print interpretation, path mismatch isolation, and regression checks for override policy.
Override debug boundary order
Triage override failures in order: timing, requested base type, scope selection, path match, precedence, then Liskov/connectivity.
[FACTORY][UVM] override triage matrix
override seems ignored:
-> registered before create?
-> env still requests correct base type?
-> instance path exactly matches get_full_name()?
wrong agent got override:
-> type override too broad?
-> path points to sibling agent?
connect_phase fails after override:
-> derivative broke port/parameter contract?function void report_overrides();
uvm_factory f = uvm_factory::get();
f.print(1);
endfunction
function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
report_overrides();
`uvm_info("OVERRIDE_CHK",
$sformatf("tx=%s rx=%s",
env.agt_tx.drv.get_type_name(),
env.agt_rx.drv.get_type_name()), UVM_NONE)
endfunctionKey takeaways
factory.print() plus get_type_name() resolves most override mysteries.
Path mismatch is the leading root cause for instance override misses.
Connect failures after override often indicate Liskov structural breakage.
Common pitfalls
Changing both override policy and env hierarchy in one debug iteration.
Assuming print presence guarantees effective substitution.
Skipping seed replay after override policy changes.
Deterministic override debug toolkit
Keep lightweight override diagnostics in base_test for every scenario regression.
Instrumentation primitives
virtual function void apply_factory_overrides();
override_apply_count++;
`uvm_info("OVERRIDE_APPLY",
$sformatf("test=%s count=%0d", get_type_name(), override_apply_count),
UVM_LOW)
endfunction
function void log_override_targets();
if (!uvm_config_db#(bit)::get(this, "", "override_debug", override_debug))
override_debug = 0;
if (override_debug)
factory.print(1);
endfunction[FACTORY] recommended override counters
- override_apply_count
- type_override_count
- inst_override_count
- override_path_mismatch_suspects
- elab_type_mismatch_countReproduction checklist
Capture factory.print() after apply_factory_overrides().
Run one deterministic seed twice; compare get_type_name() outputs.
For partial misses, print full names of all sibling targets.
If connect fails, diff base vs derivative port members.
Fix one scope issue at a time (type OR instance, not both).
[FACTORY][UVM] override debug pass criteria
expected override entries in factory.print
AND
all target nodes report expected derivative type
AND
connect_phase/run_phase pass without topology editsConflict patterns
base_test and child_test both apply type overrides — document winner.
Multiple instance overrides on same path without replace=1.
Debug test leaves global type override active for later tests in same sim (if not isolated).
[UVM] common conflict fix
centralize all overrides in apply_factory_overrides()
define order:
1) base_test policy
2) child scenario deltas
log final effective policy onceKey takeaways
Override debug should be boring and repeatable — checklist driven.
Isolate one variable per iteration: timing, scope, path, precedence.
Persistent counters/logs in base_test reduce regression triage time.
Common pitfalls
Removing override debug hooks once one scenario passes.
Fixing override bugs by hardcoding derivatives in env.
Ignoring factory debug because behavior 'looks close enough'.