UVM Reporting and Verbosity: A Practical Guide

Every UVM testbench talks to you through its messages. UVM reporting is the mechanism that decides what gets printed, at which detail level, whether a message counts as an error, and when the simulation should stop. Master it and a failing regression tells you exactly where to look; ignore it and you drown in thousands of lines of noise. This guide walks through the four severities, the verbosity system, the +UVM_VERBOSITY command-line switch, severity overrides, and how to count errors so your test can declare itself passed or failed.

Note on running these examples: the UVM snippets below use the UVM class library and its macros, so they compile and run only on a UVM-capable simulator such as industry-standard simulation tools, VCS, or industry-standard simulators (or free on EDA Playground). They are shown as syntax for study, not as self-contained programs. The one plain-SystemVerilog illustration near the end needs no UVM library and runs anywhere.

The four report severities

UVM offers four severities, in increasing order of seriousness. Each has a matching macro from uvm_macros.svh:

  • `uvm_info – informational. The only one that takes a verbosity argument.
  • `uvm_warning – something is suspicious but the test continues.
  • `uvm_error – a real defect; counted, and the test should ultimately fail.
  • `uvm_fatal – unrecoverable; the simulation is terminated immediately.
`uvm_info ("DRV",  "Starting the reset sequence", UVM_MEDIUM)
`uvm_warning("CFG",  "Config value out of expected range")
`uvm_error  ("SCB",  "Mismatch: expected 8'hA5, got 8'h5A")
`uvm_fatal  ("ENV",  "Null virtual interface handle")

Each macro takes an ID string and a message string; `uvm_info adds a verbosity. The ID is not decoration — it is a filter key you will use later to raise or lower detail for one component without touching the rest. Pick stable, short IDs (“DRV”, “SCB”, “MON”) and reuse them consistently.

Verbosity levels: how much detail

Verbosity controls whether an `uvm_info message is printed at all. It is a comparison: a message prints only when its verbosity is less than or equal to the component’s current verbosity threshold. UVM defines these named levels (with their integer values):

LevelValueTypical use
UVM_NONE0Always printed — final pass/fail banners.
UVM_LOW100Major milestones (test start, phase transitions).
UVM_MEDIUM200Default. Per-transaction summaries.
UVM_HIGH300Detailed per-field tracing for debug.
UVM_FULL400Very noisy internal state.
UVM_DEBUG500Everything.

The default threshold is UVM_MEDIUM. So a message tagged UVM_HIGH (300) is filtered out by default (300 > 200), while UVM_LOW and UVM_MEDIUM messages print. Tag the line accordingly: milestones get UVM_LOW, per-field debug gets UVM_HIGH.

class my_driver extends uvm_driver #(my_item);
  `uvm_component_utils(my_driver)

  task run_phase(uvm_phase phase);
    `uvm_info("DRV", "Driver up and running", UVM_LOW)
    forever begin
      seq_item_port.get_next_item(req);
      `uvm_info("DRV", $sformatf("Driving addr=%0h data=%0h",
                                 req.addr, req.data), UVM_HIGH)
      seq_item_port.item_done();
    end
  endtask
endclass

Importantly, severity and verbosity are independent axes. Warnings, errors, and fatals are not gated by verbosity — they always print. Only `uvm_info is filtered.

Setting verbosity from the command line: +UVM_VERBOSITY

You rarely want to recompile just to see more detail. The +UVM_VERBOSITY plusarg sets the global threshold at run time, so one build serves both a quiet regression and a noisy debug session:

# industry-standard simulation tools
vsim top +UVM_VERBOSITY=UVM_HIGH

# VCS
./simv +UVM_VERBOSITY=UVM_LOW

# industry-standard simulators
xrun -R +UVM_VERBOSITY=UVM_FULL

Run regressions at UVM_LOW for speed and clean logs; re-run the single failing seed at UVM_HIGH to see what happened. Because verbosity filtering also saves the string-formatting cost of skipped messages, keeping routine runs quiet measurably speeds up long simulations.

Controlling verbosity in code

For finer control than one global knob, every uvm_report_object (which includes all components) exposes setter methods. Call them in build_phase or in your test:

// Raise detail for one component instance only
drv.set_report_verbosity_level(UVM_HIGH);

// Raise detail for a component and all its children
env.set_report_verbosity_level_hier(UVM_HIGH);

// Turn up just one message ID, everywhere it is used in this component
set_report_id_verbosity("SCB", UVM_FULL);

The ID-scoped form is the surgical tool: crank “SCB” to UVM_FULL to flood-trace the scoreboard while every other ID stays at the default. This is far more usable than a global UVM_FULL that buries the signal you need.

Changing severities with overrides

Sometimes a third-party VIP screams `uvm_error about a condition your DUT is allowed to produce, or you want to promote a nagging warning into a hard failure. Severity overrides reclassify a message without editing the code that issued it:

// Promote every warning to an error (treat warnings as failures)
set_report_severity_override(UVM_WARNING, UVM_ERROR);

// Demote one specific error ID to a warning so it stops failing the test
set_report_severity_id_override(UVM_ERROR, "VIP_X", UVM_WARNING);

Use demotions sparingly and comment why — a demoted error is an error you have agreed to stop tracking, and it is easy to hide a genuine bug this way.

Report actions and the quit count

Beyond severity, UVM lets you decide what happens when a message fires. An action is a bitwise OR of flags such as UVM_DISPLAY, UVM_LOG, UVM_COUNT, UVM_EXIT, and UVM_NO_ACTION:

// Send errors to the screen AND count them
set_report_severity_action(UVM_ERROR, UVM_DISPLAY | UVM_COUNT);

// Mirror info messages into a log file as well as the screen
UVM_FILE log = $fopen("sim.log", "w");
set_report_default_file(log);
set_report_severity_action(UVM_INFO, UVM_DISPLAY | UVM_LOG);

// Stop the run after 5 counted errors instead of the default 1
set_report_max_quit_count(5);

By default a single UVM_ERROR is counted and UVM_FATAL exits at once. set_report_max_quit_count(n) lets a run collect up to n counted messages before UVM terminates, which is handy when you want to see several failures in one pass rather than stopping at the first.

Counting errors: deciding pass or fail

A test should not announce success just because simulation time ran out. Query the report server in report_phase to get the real counts and print an honest verdict:

function void report_phase(uvm_phase phase);
  uvm_report_server svr = uvm_report_server::get_server();
  int errs   = svr.get_severity_count(UVM_ERROR);
  int fatals = svr.get_severity_count(UVM_FATAL);

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

Tag the pass banner UVM_NONE so it always prints, even in a quiet UVM_LOW regression. get_severity_count() and get_id_count() are the numbers your CI script should grep for; the automatic UVM report summary that prints at run_phase end is a convenient cross-check.

The idea in plain SystemVerilog

Strip away the UVM library and the core of reporting is two simple ideas: filter a message by comparing its verbosity to a threshold, and increment a counter when an error fires. The illustration below models exactly that with nothing but $display — it runs on any SystemVerilog simulator, no UVM required. Watch how the UVM_HIGH line is suppressed and how the final verdict is driven by the error count.

UVM_INFO @ 0 [CFG] medium-detail config message
UVM_ERROR @ 10 [SCB] expected 8'hA5, got 8'h5A

— Simulation summary —
UVM_ERROR count : 1
** TEST FAILED **
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmp6o2icjmy/tb.sv:30: $finish called at 10 (1s)

module tb;
  // Mimic the idea behind UVM verbosity constants
  localparam int UVM_NONE = 0, UVM_LOW = 100, UVM_MEDIUM = 200,
                 UVM_HIGH = 300, UVM_FULL = 400;

  // Like +UVM_VERBOSITY=UVM_MEDIUM : print only at or below this level
  int verbosity_threshold = UVM_MEDIUM;
  int error_count = 0;

  task automatic report_info(string id, string msg, int verb);
    if (verb <= verbosity_threshold)
      $display("UVM_INFO  @ %0t [%s] %s", $time, id, msg);
  endtask

  task automatic report_error(string id, string msg);
    $display("UVM_ERROR @ %0t [%s] %s", $time, id, msg);
    error_count++;
  endtask

  initial begin
    report_info("CFG", "medium-detail config message", UVM_MEDIUM); // prints
    report_info("DBG", "high-detail debug trace",       UVM_HIGH);  // filtered
    #10;
    report_error("SCB", "expected 8'hA5, got 8'h5A");

    $display("n--- Simulation summary ---");
    $display("UVM_ERROR count : %0d", error_count);
    if (error_count > 0) $display("** TEST FAILED **");
    else                 $display("** TEST PASSED **");
    $finish;
  end
endmodule

Practical guidelines

  1. Give each component a stable ID and reuse it for every message there.
  2. Tag milestones UVM_LOW, per-transaction notes UVM_MEDIUM, deep tracing UVM_HIGH/UVM_FULL.
  3. Run regressions quiet with +UVM_VERBOSITY=UVM_LOW; debug one seed loud.
  4. Build error messages with $sformatf so expected-vs-actual values travel with the report.
  5. Decide pass/fail from the report server’s counts, not from reaching the end of time.
  6. Comment every severity override — especially demotions.

Quick check

With the default threshold, is a message tagged UVM_HIGH printed?

No. The default threshold is UVM_MEDIUM (200) and UVM_HIGH is 300. A message prints only when its verbosity is less than or equal to the threshold, and 300 > 200, so it is filtered out.

Does verbosity affect uvm_error and uvm_warning messages?

No. Verbosity gates only uvm_info. Warnings, errors, and fatals always print regardless of the verbosity setting.

How do you raise the global verbosity at run time without recompiling?

Pass the +UVM_VERBOSITY plusarg to the simulator, e.g. +UVM_VERBOSITY=UVM_HIGH. It sets the global threshold for that run only.

How can a test report an accurate pass or fail?

Query the report server in report_phase with uvm_report_server::get_server() and get_severity_count(UVM_ERROR)/get_severity_count(UVM_FATAL); declare PASSED only when both counts are zero.

Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.
▶ Try it in the ChipXpert Lab

Compile and simulate this in the browser — no install. Edit the code and re-run instantly.

Open in Verification Lab

Learn Verilog with mentors, labs and placement support

This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.

Explore VLSI Courses
Next batch starts 18th November 2026
Start your VLSI career with ChipXpert

Live online and classroom batches in Hyderabad & Bengaluru. Fill in your details and a counsellor will call you back.

  • Real EDA tools in your browser: industry-standard EDAReal EDA tools in your browser
  • Recorded sessions on the elearn portalRecorded sessions
  • Placement assistance: resume, mock interviewsPlacement assistance
  • Merit scholarship up to 60% · EMI optionsScholarship up to 60%
Hi! Ask me about courses, fees, batches or discounts. ×
BENGALURU
HYDERABAD