UVM-21: UVM Reporting & Messaging — VLSI Trainers
VLSI Trainers UVM Series · UVM-21
UVM Series · UVM-21

UVM Reporting & Messaging

The complete UVM message system — the four severity macros, verbosity levels and the filter matrix, setting verbosity per component and globally, report hooks and overrides, message counts and thresholds, ID-based filtering, and best practices for log-friendly testbenches.

📋 The Four Severity Macros

UVM provides four severity levels for messages. Each has a default action — what the simulation does when that severity fires. Only `uvm_info messages are filtered by verbosity; the other three always print.

Four UVM Message Severity Levels `uvm_info UVM_INFO Default action: Print to transcript Filtered by verbosity Simulation continues `uvm_warning UVM_WARNING Default action: Print + increment count Never filtered Simulation continues `uvm_error UVM_ERROR Default action: Print + increment count Never filtered Simulation continues* `uvm_fatal UVM_FATAL Default action: Print + $finish immediately Never filtered Simulation STOPS vlsitrainers.com
Figure 1 — The four UVM severity levels. Only `uvm_info is filtered by verbosity. `uvm_warning and `uvm_error always print and increment their respective counters but allow simulation to continue. `uvm_fatal always prints and immediately stops simulation. *`uvm_error simulation stops when the error count reaches the maximum threshold.
// ── Syntax for all four macros ────────────────────────────
// `uvm_info   (id, message, verbosity)
// `uvm_warning(id, message)
// `uvm_error  (id, message)
// `uvm_fatal  (id, message)

`uvm_info   ("DRV", $sformatf("Driving addr=0x%03h", addr), UVM_HIGH)
`uvm_warning("MON", "PREADY held low for > 16 cycles")
`uvm_error  ("SB",  $sformatf("MISMATCH exp=%0h act=%0h", exp, act))
`uvm_fatal  ("CFG", "No virtual interface in config_db!")

// ── Equivalent functional form (usable in classes and modules)
// When no 'this' context is available (e.g. inside covergroups)
uvm_report_info   ("ID", "message", UVM_MEDIUM);
uvm_report_warning("ID", "message");
uvm_report_error  ("ID", "message");
uvm_report_fatal  ("ID", "message");

📋 Verbosity Levels and the Filter Matrix

Verbosity controls which `uvm_info messages appear in the transcript. Each component has a verbosity setting; a message is printed only if its verbosity value is ≤ the component’s current verbosity setting. Lower verbosity = more important = always shown first.

Message verbosityShown at UVM_LOWUVM_MEDIUM (default)UVM_HIGHUVM_FULLUVM_DEBUG
UVM_NONE (0)
UVM_LOW (100)
UVM_MEDIUM(200)
UVM_HIGH (300)
UVM_FULL (400)
UVM_DEBUG (500)
Counter-intuitive: UVM_HIGH means “only show when verbosity is high.” A message tagged UVM_HIGH is a detail message — it requires the component’s verbosity setting to be at UVM_HIGH or above before it appears. UVM_NONE messages always appear. Think of the verbosity tag as the level of detail the message represents, and the component’s setting as the maximum detail threshold.

Usage guidelines

Verbosity tagUse forWhen you want to see it
UVM_NONECritical infrastructure messages — used sparingly. Always visible.Always. Cannot be filtered.
UVM_LOWTest-level summaries, pass/fail results, major milestonesNormal regression runs
UVM_MEDIUMPer-transaction progress, scoreboard matches, phase transitionsDefault — most debug sessions
UVM_HIGHPer-item detail, driver cycle-by-cycle, monitor every sampleWhen debugging a specific failure
UVM_FULLInternal state dumps, sequence internals, full register valuesDeep debugging a protocol issue
UVM_DEBUGMinute implementation details rarely needed by end usersInfrastructure development only

📋 Setting Verbosity

Verbosity can be set globally, per component, or per message ID — from inside the testbench code or from the simulator command line without recompilation.

// ── Globally — all components ─────────────────────────────
// From start_of_simulation_phase or end_of_elaboration_phase
uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH);

// ── Per component — just this one ────────────────────────
m_driver.set_report_verbosity_level(UVM_HIGH);

// ── Per component + all children ─────────────────────────
m_env.m_agent.set_report_verbosity_level_hier(UVM_FULL);

// ── Command line: global verbosity (no recompile) ────────
// +UVM_VERBOSITY=UVM_HIGH

// ── Command line: specific component ─────────────────────
// +uvm_set_verbosity=uvm_test_top.m_env.m_agent.m_drv,_ALL_,UVM_HIGH,run_phase
// Format: component_path, id, verbosity, phase (or "")  

// ── Query current verbosity ───────────────────────────────
int v = get_report_verbosity_level();
Use command-line verbosity control for debug — never modify source to change verbosity. The whole point of the verbosity system is that you can dial up detail on any component without touching testbench code. Use +UVM_VERBOSITY=UVM_HIGH for global detail or the per-component plusarg for surgical debugging. This keeps the source clean and allows regression scripts to control output volume.

📋 Message Format and IDs

Every UVM message automatically includes the severity, simulation time, component path, and the ID string. Understanding the format helps decode regression log files quickly.

// ── What a typical UVM message looks like in the transcript
// UVM_INFO  @ 1450ns: uvm_test_top.env.agent.drv [DRV] Driving addr=0x004
// ─────────   ──────   ────────────────────────── ───   ──────────────────
// severity   time      component path              ID    message text
//
// UVM_ERROR @ 1500ns: uvm_test_top.env.sb [SB] MISMATCH exp=0xDEAD act=0xBEEF

// ── Good ID naming convention ─────────────────────────────
// Use component abbreviation as ID — easy to grep in logs
`uvm_info("DRV",  "...", UVM_HIGH)    // driver
`uvm_info("MON",  "...", UVM_MEDIUM)  // monitor
`uvm_info("SB",   "...", UVM_LOW)     // scoreboard
`uvm_info("SEQ",  "...", UVM_MEDIUM)  // sequence
`uvm_info("CFG",  "...", UVM_LOW)     // config
`uvm_info("TEST", "...", UVM_LOW)     // test

// ── Include class name in ID for precise location ─────────
`uvm_info({get_type_name(), "::run_phase"},
           "Starting driver", UVM_HIGH)
// → [apb_driver::run_phase] Starting driver

// ── Filter by ID from command line ───────────────────────
// +uvm_set_verbosity=uvm_test_top.env.agent.drv,DRV,UVM_HIGH,run
// Only shows UVM_HIGH DRV messages from the driver component

📋 uvm_report_enabled()

Some debug operations are expensive — calling item.print(), formatting a long string, or computing a diagnostic value. If these are guarded by a verbosity check, they are skipped unless the current verbosity level would display the result.

// ── Guard expensive operations with verbosity check ───────
task run_phase(uvm_phase phase);
  apb_seq_item item;
  forever begin
    seq_item_port.get_next_item(item);

    // Only call item.print() if UVM_HIGH would be displayed
    if (uvm_report_enabled(UVM_HIGH))
      item.print();   // skipped if verbosity < UVM_HIGH

    drive_transfer(item);
    seq_item_port.item_done();
  end
endtask

// ── Avoid expensive $sformatf when it won't be printed ────
if (uvm_report_enabled(UVM_FULL)) begin
  string dump = build_register_dump();  // only computed if needed
  `uvm_info("REG", dump, UVM_FULL)
end

📋 Error Count Thresholds

By default, UVM stops the simulation when 5 `uvm_error messages fire — the max_quit_count. This prevents a runaway test from generating thousands of error messages and filling log files. The threshold can be configured:

// ── Set max error count before stopping ───────────────────
// Default = 5. Set to 0 for unlimited (never stop on errors)
// Call from start_of_simulation_phase or build_phase
uvm_root::get().set_report_max_quit_count(20);   // stop after 20 errors
uvm_root::get().set_report_max_quit_count(0);    // never stop on errors

// ── Command line ──────────────────────────────────────────
// +UVM_MAX_QUIT_COUNT=20,YES

// ── Query current error and warning counts ────────────────
int err_count  = uvm_report_server::get_server().get_severity_count(UVM_ERROR);
int warn_count = uvm_report_server::get_server().get_severity_count(UVM_WARNING);

// ── Check counts in check_phase ───────────────────────────
function void check_phase(uvm_phase phase);
  int errs = uvm_report_server::get_server().get_severity_count(UVM_ERROR);
  if (errs > 0)
    `uvm_fatal("CHK", $sformatf("%0d errors during run", errs))
endfunction
Set max_quit_count higher than 5 for complex DUTs. A testbench that finds a root cause bug may trigger many downstream errors. If the simulation stops at 5 errors, you only see the first cascade — the subsequent errors that would help identify the root cause are hidden. Set to 20–50 for detailed regression, and 0 only in dedicated error-counting mode.

📋 Report Hooks and Overrides

The report server allows overriding the default action for specific severity + ID combinations — for example, demoting expected errors to warnings, or promoting certain warnings to errors for a specific test.

// ── Override action for a specific ID ─────────────────────
// Actions: UVM_NO_ACTION, UVM_DISPLAY, UVM_COUNT, UVM_STOP, UVM_EXIT,
//          UVM_LOG (to file), UVM_RM_RECORD

// Demote UVM_ERROR for ID "SB" to just display (no count, no stop)
set_report_severity_id_override(UVM_ERROR, "SB", UVM_WARNING);

// Silence UVM_WARNING from monitor (expected during reset)
set_report_id_action(UVM_WARNING, "MON", UVM_NO_ACTION);

// Make a specific info message always print regardless of verbosity
set_report_severity_action(UVM_INFO, UVM_DISPLAY | UVM_COUNT);

// Redirect all errors to a log file AND display
int fd = $fopen("errors.log", "w");
set_report_severity_action(UVM_ERROR, UVM_DISPLAY | UVM_LOG);
set_report_default_file(fd);

// ── Per-component overrides ───────────────────────────────
m_driver.set_report_severity_action(UVM_WARNING, UVM_NO_ACTION);
// Silence all warnings from this driver

📋 Best Practices

PracticeReason
Use consistent IDs per component ("DRV", "MON", "SB")Makes grep-based log filtering fast and reliable in regressions
Reserve UVM_LOW for milestones and PASS/FAILDefault runs produce clean, readable transcripts without detail clutter
Put per-cycle detail at UVM_HIGH or UVM_FULLZero performance overhead in regression; full detail available on demand
Guard item.print() and expensive formatting with uvm_report_enabled()Avoids CPU cost of building strings that will be filtered anyway
Use `uvm_error for verification failures, not `uvm_fatalAllows multiple errors to accumulate; complete mismatch picture before stopping
Use `uvm_fatal only for infrastructure failures (null handle, no vif)Unrecoverable — stopping immediately is correct; continuing would produce spurious errors
Include convert2string() in error messagesFull transaction context visible in the log — no need to add extra debug runs
Set max_quit_count in base_test, not hardcoded in componentsTests can override threshold for specific scenarios without recompile

📋 Quick Reference

ItemKey fact
`uvm_info syntax`uvm_info("ID", message, verbosity) — filtered by verbosity
`uvm_warning syntax`uvm_warning("ID", message) — always printed, never filtered
`uvm_error syntax`uvm_error("ID", message) — always printed, increments error count
`uvm_fatal syntax`uvm_fatal("ID", message) — always printed, stops simulation immediately
Default verbosityUVM_MEDIUM — shows UVM_NONE, UVM_LOW, UVM_MEDIUM messages
Verbosity logicMessage shown if message_verbosity ≤ component_verbosity. Lower = more important.
Set global verbosityuvm_root::get().set_report_verbosity_level_hier(UVM_HIGH)
Set component verbositycomponent.set_report_verbosity_level(UVM_HIGH)
Command-line global+UVM_VERBOSITY=UVM_HIGH
Command-line per-component+uvm_set_verbosity=path,id,level,phase
Guard expensive opsif (uvm_report_enabled(UVM_HIGH)) item.print()
Error count thresholduvm_root::get().set_report_max_quit_count(N) — default 5, 0=unlimited
Command-line threshold+UVM_MAX_QUIT_COUNT=20,YES
Query error countuvm_report_server::get_server().get_severity_count(UVM_ERROR)
Override severity actionset_report_severity_id_override(UVM_ERROR, "ID", UVM_WARNING)
Scroll to Top