Part 8 · Checking & Coverage · Intermediate

PASS/FAIL, Max Quit Count, and Debug Playbook

report_phase PASS/FAIL from report server, quit limits, and regression triage steps.

PASS/FAIL workflow

UVM does not automatically print PASS/FAIL. Your test's report_phase must query the report server and print the result. The standard check: UVM_ERROR + UVM_FATAL == 0 → PASS; anything else → FAIL.

diagram
Legend: [UVM]

  PASS/FAIL WORKFLOW

  run_phase
     │
     ├─ scoreboard mismatch   `uvm_error("SCB_MISMATCH", ...)   count++
     ├─ RAL mirror fail       `uvm_error("RAL_MIRROR", ...)      count++
     ├─ VIP benign error      catcher demotes to warning           no error count
     └─ null vif              `uvm_fatal("NOVIF", ...)            count++ + sim stops
     │
  check_phase
     │
     └─ unmatched expected    `uvm_error("SCB", ...)              count++
     │
  report_phase
     │
     ├─ svr.get_severity_count(UVM_ERROR)   N
     ├─ svr.get_severity_count(UVM_FATAL)   M
     │
     ├─ N + M == 0    `uvm_info("RESULT", "*** TEST PASSED ***", UVM_NONE)
     └─ N + M >  0    `uvm_info("RESULT", "*** TEST FAILED ***", UVM_NONE)
     │
  Regression tool reads RESULT line + exit code  batch PASS/FAIL

report_phase implementation

systemverilog
function void report_phase(uvm_phase phase);
  super.report_phase(phase);
  uvm_report_server svr = uvm_report_server::get_server();

  int errors = svr.get_severity_count(UVM_ERROR)
             + svr.get_severity_count(UVM_FATAL);
  int warnings = svr.get_severity_count(UVM_WARNING);

  `uvm_info("RESULT", $sformatf(
    "Errors=%0d Warnings=%0d", errors, warnings), UVM_NONE)

  if (errors == 0)
    `uvm_info("RESULT", "*** TEST PASSED ***", UVM_NONE)
  else
    `uvm_info("RESULT", $sformatf("*** TEST FAILED (%0d errors) ***",
      errors), UVM_NONE)

  // Per-ID breakdown for triage
  `uvm_info("RESULT", $sformatf("SCB_MISMATCH: %0d",
    svr.get_id_count("SCB_MISMATCH")), UVM_NONE)
endfunction
systemverilog
// Max quit count — stop sim after N errors (prevent log explosion)
function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  set_report_max_quit_count(50);
endfunction
// Or: simv +UVM_MAX_QUIT_COUNT=100

Debug playbook

Regression triage steps

  1. Reproduce failing seed at UVM_MEDIUM — note error IDs and counts from RESULT line.

  2. Query get_id_count("SCB_MISMATCH") — how many distinct failure types?

  3. Raise verbosity on failing component only: +uvm_set_verbosity=...env.scb,_ALL_,UVM_HIGH,run.

  4. Add strategic uvm_info at UVM_HIGH in scoreboard write_act — not global UVM_FULL.

  5. check_phase: inspect unmatched expected count — DUT dropped responses?

  6. report_phase: print match_count, coverage %, and per-ID error breakdown.

  7. VIP noise: catcher for known IDs or set_report_id_verbosity(VIP_ID, UVM_NONE).

  8. Fix root cause, re-run at UVM_MEDIUM to confirm PASS.

diagram
DEBUG DECISION TREE [UVM]

  Test FAILED — where to look first?
       │
       ├─ SCB_MISMATCH count > 0?
       │     └─ Raise scb verbosity to UVM_HIGH, rerun single seed
       │
       ├─ RAL_MIRROR count > 0?
       │     └─ Check predictor wiring and auto_predict setting
       │
       ├─ SCB count > 0 (unmatched expected)?
       │     └─ check_phase drain — DUT dropped responses
       │
       ├─ NOVIF / NOCONFIG fatal?
       │     └─ config_db path mismatch — print in build_phase
       │
       └─ Zero errors but test looks wrong?
             └─ Check for catchers demoting real errors to warnings

Key takeaways

  • Never print PASS when UVM_ERROR count > 0.

  • check_phase errors count toward FAIL same as run_phase errors.

  • Print per-ID error breakdown in report_phase — essential for regression triage.

Common pitfalls

  • Custom pass flag (test_passed bit) ignoring report server counts.

  • Catchers demoting real bugs without review — test passes with DUT bugs.

  • UVM_FULL in regression — use UVM_HIGH on failing component only.

  • Printing PASS before report_phase — premature result before check_phase drain.