Part 6 · Agents & Protocol IP · Intermediate
Cfg Debug Patterns: Propagation Tracing and Mismatch Isolation
Debug config issues with producer-transport-consumer-behavior checkpoints, structured dumps, and deterministic triage order.
Debug model and symptom classification
Configuration bugs look like protocol bugs unless cfg flow is observable. Instrument checkpoints so you can isolate where intent diverges from effective behavior.
[UVM][AGT][DRV][TLM] four-checkpoint model
C1 producer:
env/test values before set
C2 transport:
path/key and precedence at set/get boundaries
C3 consumer:
effective values after get + normalize
C4 behavior:
evidence in driver/monitor/checker actions[CFG] symptom map
unexpected passive mode:
likely precedence/path mismatch
driver NOVIF fatal:
missing binding or wrong cfg target
checker unexpectedly disabled:
stale cfg override or interpretation bug
seed-specific behavior drift:
random cfg not logged or hidden mutationClassify symptoms before diving into waveforms.
Checkpoint deltas identify root-cause zone quickly.
Behavior should be diagnosed against effective cfg, not intended cfg.
Structured dump and probe utilities
function string cfg_to_string(bus_agent_cfg c);
return $sformatf(
"{mode=%s timeout=%0d gap=[%0d,%0d] rsp=%0d chk=%0d tr=%0d vif=%s}",
c.is_active.name(),
c.timeout_cycles,
c.req_gap_min_cycles,
c.req_gap_max_cycles,
c.send_rsp,
c.enable_protocol_checks,
c.trace_transactions,
(c.vif == null) ? "NULL" : "SET");
endfunction
function void cfg_log(string stage, bus_agent_cfg c);
`uvm_info("CFG_DBG",
$sformatf("stage=%s path=%s cfg=%s", stage, get_full_name(), cfg_to_string(c)),
UVM_LOW)
endfunctionfunction void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(bus_agent_cfg)::get(this, "", "cfg", cfg))
`uvm_fatal("NOCFG", "cfg missing")
cfg_log("agent_get", cfg);
cfg.normalize_compat();
cfg_log("agent_norm", cfg);
uvm_config_db#(bus_agent_cfg)::set(this, "mon", "cfg", cfg);
if (cfg.is_active == UVM_ACTIVE)
uvm_config_db#(bus_agent_cfg)::set(this, "drv", "cfg", cfg);
endfunction[UVM][AGT][DRV][TLM] recommended log stages
S1 env_populated
S2 env_set_path
S3 agent_get
S4 agent_normalized
S5 child_get (drv/mon)
S6 end_of_elaboration summaryUse fixed field ordering in dumps to simplify diffing.
Include full path and stage tags in every log line.
Prefer concise structured logs over verbose free-form dumps.
Deterministic triage procedure
[UVM][AGT][DRV][TLM] triage ladder
step 1 producer check:
was cfg populated with intended values?
step 2 transport check:
did set/get paths and keys match?
step 3 consumer check:
did wrapper/children observe same effective cfg?
step 4 behavior check:
did driver/monitor behavior reflect effective cfg?
stop at first mismatch boundary[CFG] one-seed isolation recipe
1) run deterministic seed with minimal traffic
2) enable cfg stage logs only
3) trigger one request/response flow
4) compare observed behavior to effective cfg
5) patch first failed boundary, rerun same seedtask cfg_probe_tree(my_env env);
`uvm_info("CFG_PROBE", "begin cfg probe", UVM_LOW)
env.cfg_probe();
env.agt.cfg_probe();
if (env.agt.drv != null) env.agt.drv.cfg_probe();
env.agt.mon.cfg_probe();
endtaskKey takeaways
Cfg debugging is fastest when producer, transport, consumer, and behavior are all observable.
Structured stage logs provide repeatable, low-noise triage.
Deterministic triage order prevents circular debugging.
Fix the first failing boundary; downstream symptoms are usually secondary.
Common pitfalls
Debugging protocol behavior before confirming cfg propagation.
Logging only producer intent, not consumer-effective values.
No path/stage metadata in cfg logs.
Changing multiple boundaries at once and losing causal traceability.