Part 10 · Advanced Topics · Intermediate
VIP Callback API Design
Guidelines for VIP authors to expose robust callback hook APIs that are stable, composable, and verification-friendly.
Why VIP callback API quality matters
When VIP authors expose callbacks well, users customize behavior by composition instead of forking source. When callback APIs are vague or sparse, projects copy and modify driver internals, creating long-term maintenance cost.
A good VIP callback API defines hook timing, mutability rules, ordering expectations, and error handling guarantees. It treats callbacks as first-class extension surfaces with versioned contracts.
[UVM][ADV] VIP author objective
Provide enough hooks so users do not fork VIP
while preserving:
- protocol correctness ownership
- deterministic execution semantics
- forward compatibility across releases[TEST] user experience impact
Strong callback API:
add callback class -> solve scenario quickly
Weak callback API:
clone VIP driver -> patch internals -> diverge from upstreamCallback API is product surface area, not optional accessory.
Quality hooks reduce support burden and integration churn.
Stable hook contracts increase VIP adoption and trust.
Designing hook taxonomy
VIP should expose hooks at semantic milestones, not random code points. A practical taxonomy includes transaction lifecycle hooks, timing hooks, error/report hooks, and observation hooks.
[DRV][ADV] recommended driver hook taxonomy
Transaction lifecycle:
pre_txn(ref tr), post_txn(tr)
Beat/channel hooks:
pre_beat(ref tr, beat_idx), post_beat(tr, beat_idx)
Timing hooks:
pre_wait_ready(tr), post_wait_ready(tr, cycles_waited)
Error/report hooks:
on_violation(tr, reason), on_retry(tr, retry_idx)[UVM] monitor hook taxonomy
pre_sample()
post_sample(raw_signals)
pre_decode(raw, ref tr)
post_decode(tr)
on_protocol_error(raw, reason)
Keep monitor hooks primarily observation-centricName hooks by intent and timing to reduce ambiguity.
Expose both coarse and fine-grained hooks only where justified.
Avoid overhooking every internal helper - API becomes noisy and unstable.
Contract clarity: mutability and constraints
Each hook should specify whether transaction mutation is allowed. For mutation-enabled hooks, document legal field changes and when those changes are consumed by host logic.
Also define boundaries: callbacks must not directly drive pins, must not modify host internal FSM state unless explicitly supported, and must not block indefinitely.
[UVM][ADV] hook contract template
Hook: pre_txn(host, ref tr)
Timing: before packing/drive scheduling
Mutation: allowed on payload, id, user sideband
Forbidden: direct vif pin drive, illegal length > MAX_LEN
Latency: function hook, no time-consuming operations
Error handling: host logs warning and continues on callback errorclass vip_driver_cb extends uvm_callback;
// Contract: may mutate tr fields listed in VIP user guide.
virtual function void pre_txn(vip_driver drv, ref vip_item tr);
endfunction
// Contract: observation-only, no mutation expected.
virtual function void post_txn(vip_driver drv, vip_item tr);
endfunction
endclassSeparate mutation hooks from observation hooks for cleaner mental model.
Document field-level mutability instead of broad 'can edit transaction' language.
Include timing behavior limits in hook docs to prevent simulation hazards.
Execution model and callback stack governance
VIP should define callback order semantics and provide helper utilities to inspect active chains. Users need this to reason about composed policies across large environments.
class vip_driver extends uvm_driver #(vip_item);
`uvm_component_utils(vip_driver)
`uvm_register_cb(vip_driver, vip_driver_cb)
function void dump_cb_chain();
vip_driver_cb cb;
cb = uvm_callbacks#(vip_driver, vip_driver_cb)::get_first(this);
while (cb != null) begin
`uvm_info("VIP_CB", {"active: ", cb.get_name()}, UVM_LOW)
cb = uvm_callbacks#(vip_driver, vip_driver_cb)::get_next(this);
end
endfunction
endclass[ADV] callback governance practices
- registration order defines execution order
- users can inspect chain via dump utility
- host may expose callback_enable knob for debug A/B
- release notes call out hook contract changes explicitly[TEST][DRV] large-env callback composition
project policy cb
+
subsystem stress cb
+
testcase-specific cb
Need deterministic layering and observability to debug interactionsProvide chain dump helpers in VIP to speed integration debugging.
Treat order changes as behavior changes - mention in release notes.
Minimize hidden callback-side global state for composability.
Walkthrough: authoring a callback-friendly driver API
This walkthrough shows a compact but robust callback API design for a hypothetical packet driver.
class pkt_driver_cb extends uvm_callback;
virtual function void pre_pkt(pkt_driver drv, ref pkt_item tr); endfunction
virtual task pre_beat(pkt_driver drv, pkt_item tr, int beat_idx); endtask
virtual function void post_pkt(pkt_driver drv, pkt_item tr); endfunction
endclass
class pkt_driver extends uvm_driver #(pkt_item);
`uvm_component_utils(pkt_driver)
`uvm_register_cb(pkt_driver, pkt_driver_cb)
task drive_item(pkt_item tr);
`uvm_do_callbacks(pkt_driver, pkt_driver_cb, pre_pkt(this, tr))
for (int i = 0; i < tr.n_beats; i++) begin
`uvm_do_callbacks(pkt_driver, pkt_driver_cb, pre_beat(this, tr, i))
drive_one_beat(tr, i);
end
`uvm_do_callbacks(pkt_driver, pkt_driver_cb, post_pkt(this, tr))
endtask
endclass[UVM][ADV] why this API works
pre_pkt:
coarse transaction mutation hook
pre_beat:
fine timing/beat hook for stress
post_pkt:
observation and accounting hook
Together:
enough power for users without exposing fragile internals[TEST] consumer-side usage
add checksum_fault_cb
add beat_pause_cb
run stress sequence
inspect scoreboard + callback audit logs
No VIP source fork requiredKey takeaways
VIP callback APIs should be explicit, stable, and semantically organized.
Document hook timing, mutability, ordering, and constraints as a formal contract.
Expose utilities for callback chain introspection to aid integration debugging.
Well-designed hooks eliminate most user pressure to fork VIP internals.
Common pitfalls
Too few hooks - users fork VIP internals for common scenarios.
Too many low-level hooks - API churn and fragile dependence on implementation details.
Undocumented mutation rules - callbacks accidentally violate host invariants.
Silent order changes between VIP versions - regression behavior shifts unexpectedly.