Part 10 · Advanced Topics · Intermediate
Callback vs Virtual vs Config
Decision framework for choosing callbacks, inheritance overrides, or config_db/settings based on variability, timing, and ownership.
Three extension mechanisms, different intent
UVM environments commonly use three mechanisms to vary behavior: callbacks, virtual method overrides via inheritance, and configuration knobs via config_db/fields. They are complementary, not interchangeable.
Choosing incorrectly often creates technical debt: using inheritance for per-test policy leads to subclass explosion; using callbacks for static constants obscures intent; using config values for timing-sensitive logic can become brittle.
[UVM][ADV] mechanism intent map
callbacks:
runtime pluggable behavior at explicit hook points
virtual override:
structural behavior change in component implementation
config:
static/dynamic parameters consumed by existing logic[TEST] quick chooser
Need optional policy per scenario? -> callback
Need fundamentally different algorithm? -> virtual override
Need parameter value (depth, timeout)? -> configStart from ownership: who should control this behavior and when?
Use the least powerful mechanism that cleanly solves the need.
Avoid mixing mechanisms for one concern unless design explicitly requires it.
Decision table
Use this table when deciding how to implement a variation request.
Variation request Callback Virtual Override Config
──────────────────────────────────────────────────────────────────────────────────────────
Inject occasional bad CRC YES Maybe No
Change driver arbitration algorithm No YES Maybe
Tune timeout cycles No No YES
Add per-test transaction audit hook YES Maybe No
Switch monitor decode strategy entirely No YES Maybe
Enable/disable existing feature flag Maybe No YES
Add temporary delay window in one test YES No Maybe
Change packet packing format globally No YES Maybe[UVM][ADV] decision dimensions
Axis 1: variability frequency
- per test? callbacks/config
- per product line? virtual/config
Axis 2: behavioral depth
- small hook-time tweak? callback
- full core algorithm swap? virtual
Axis 3: timing interaction
- needs hook around protocol action? callbackCallbacks excel at modular runtime policy insertion.
Virtual overrides suit deep component redesign.
Config settings should parameterize existing behavior, not replace logic.
Walkthrough comparisons
Case A - Add occasional checksum faults
Best fit: callback . Reason: per-test optional behavior, timed around drive path, no need to fork driver class.
[TEST] checksum fault case
Requirement:
only some tests inject CRC errors at configurable rates
callback solution:
crc_error_cb.pre_drive mutates item conditionally
virtual override cost:
new derived driver + factory override plumbing per environment
config-only gap:
value exists but no execution hook to act on itCase B - Replace monitor decode algorithm
Best fit: virtual override . Reason: core algorithm changes end-to-end; hook-level tweaks are insufficient.
[UVM][ADV] monitor decode case
Requirement:
new protocol revision needs different frame reconstruction algorithm
callback limitation:
hooks cannot safely replace monitor's core state machine
virtual override:
derive new monitor class and override decode pipeline methodsCase C - Tune retries and timeout constants
Best fit: config . Reason: values feed existing code paths; no new behavior objects needed.
`uvm_config_db#(int)::set(this, "env.*", "retry_limit", 3);
`uvm_config_db#(int)::set(this, "env.*", "timeout_cycles", 200);[TEST] config case
requirement = numeric policy
existing host logic already consumes the policy
therefore:
set config and keep code unchangedHybrid patterns and cautions
Real environments may combine mechanisms: config enables a callback family, callback performs runtime mutation, and a virtual override provides product-line-specific baseline host behavior. Hybrid is valid when boundaries are clear.
[UVM][ADV] hybrid layering example
virtual override:
custom_axi_driver base for project timing model
config:
fault_mode = "crc"
fault_rate = 10
callback:
fault_cb reads config-derived policy and injects accordingly[TEST] anti-pattern warning
If one behavior can be changed by:
- override
- callback
- config
simultaneously without clear priority,
then debugging ownership becomes unclear.
Define explicit precedence rules.Document precedence when mechanisms overlap on same behavior path.
Keep hook contracts stable even if host internals evolve.
Treat callback as policy plug-in, not backdoor for structural rewrites.
Key takeaways
Use callbacks for optional runtime behavior around explicit hook points.
Use virtual overrides for deep structural algorithm changes.
Use config for parameterizing existing logic without new control flow.
A small decision table prevents extension-mechanism misuse and code sprawl.
Common pitfalls
Using callbacks for static constants - hides simple configuration intent.
Using inheritance for every scenario tweak - class tree explodes quickly.
Letting config indirectly trigger undocumented hook behavior - opaque side effects.
No precedence rules in hybrid designs - nondeterministic debugging.