Part 7 · Environment & Tests · Intermediate

Env Composition Debug: Symptom-First Integration Triage

Debugging environment composition failures using ordered boundary checks from build, connect, activity policy, and checker ingestion.

Triage order

Debug composition in fixed order: creation, configuration, connectivity, activity policy, then checker ingestion. Ordered triage avoids random fixes.

diagram
[ENV][UVM][CHECK] triage matrix

symptom: null handle fatal
  -> missing create or bad factory override

symptom: monitor logs but no scoreboard hits
  -> connect graph missing

symptom: vseq starts but no drive
  -> sequencer handle or active policy issue

symptom: intermittent checker mismatch
  -> race/ordering or mutable transaction bug
systemverilog
task env_composition_smoke(env_top env_h);
  if (env_h == null) `uvm_fatal("SMOKE", "env null")
  if (env_h.sb == null) `uvm_fatal("SMOKE", "scoreboard null")
  if (env_h.v_sqr == null) `uvm_fatal("SMOKE", "virtual sqr null")
  if (env_h.ap_link_count == 0) `uvm_fatal("SMOKE", "no analysis links")
  `uvm_info("SMOKE", "env composition baseline passed", UVM_LOW)
endtask

Key takeaways

  • Ordered boundary checks localize failures quickly.

  • Most composition failures are wiring or policy mismatches, not DUT bugs.

  • One smoke test should gate all larger regressions.

Common pitfalls

  • Jumping straight to waveform debug without topology validation.

  • Treating intermittent failures as randomness instead of policy drift.

  • Skipping negative tests for missing config and missing links.


Applied Patterns

Build a deterministic debug packet that every failing seed prints so failures can be compared side by side.

diagram
[ENV] debug packet

required fields:
  test name
  seed
  active/passive matrix
  created component count
  analysis link count
  scoreboard ingest counters
  coverage sample counters
  first error timestamp

goal:
  reduce each failure to one broken boundary
systemverilog
function void print_debug_packet();
  `uvm_info("ENV_PKT",
    $sformatf("seed=%0d created=%0d links=%0d sb_hits=%0d cov_hits=%0d",
      $get_initial_random_seed(), created_cnt, ap_link_count, sb_hits, cov_hits),
    UVM_LOW)
endfunction
  • Standard debug packets make cross-seed comparison practical.

  • Counters should be cheap enough to leave enabled by default.

  • Escalate only after baseline packet fields are validated.


Integration Drilldown

Use a compact fail-injection suite that breaks one boundary at a time and validates error messages.

diagram
[CHECK] fail-injection suite

inject A: remove one ap.connect
inject B: force passive on driving agent
inject C: drop env cfg object
inject D: disable scoreboard subscriber

expected:
  each injection maps to one explicit fatal

Key takeaways

  • Fail-injection keeps diagnostics honest as the env evolves.

Common pitfalls

  • Allowing vague fatals that require deep wave spelunking.