Why Learn UVM Reporting? A full-chip regression can produce millions of log lines across thousands of runs. When one test fails at 3 a.m., the engineer on call needs to find the one real error fast, filter out debug noise, and know whether the test stopped for the right reason. UVM's reporting classes make every message carry a severity, an ID and a verbosity, so all of that is possible without touching the testbench code.

In SystemVerilog, messages are usually printed with $display:
$display ("%t addr = 0x%0h data = 0x%0h", addr, data);

With plain $display, there is no way to tell whether a message is informational, a debug detail, a warning, an error or a fatal problem. It is also hard to keep the same format across hundreds of files. The UVM reporting classes solve this. They issue every message with a consistent format, let you choose what action to take and which file to write to based on severity, ID or both, and filter messages by verbosity.

8 min read | Intermediate Level

What You'll Learn

  • The four UVM reporting classes and the role each plays
  • How severity, verbosity, ID and action decide what happens to a message
  • Configure verbosity, actions and log files per component or per ID
  • Use the report server and a report catcher to control test results

Why Not Just Use $display?

Need$displayUVM reporting
Mark a message as warning, error or fatalOnly by text in the stringBuilt-in severity
Hide debug messages in regressionsEdit or comment out codeChange verbosity, often from the command line
Know where a message came fromMust print it manuallyFile, line, time and component path added automatically
Count errors and stop after too manyWrite your own countersReport server counts and can end the test
Send some messages to a separate fileChange every callConfigure by severity or ID

The UVM Reporting Classes

Reporting in UVM is split across four main classes. You rarely create them yourself, but knowing what each one does tells you where to configure a behavior.

ClassRole
uvm_report_objectBase class of uvm_component. Provides the reporting methods and the set_report_* configuration functions.
uvm_report_handlerCreated inside each report object. Stores that object's verbosity threshold, actions and file handles.
uvm_report_serverOne global instance. Formats messages, counts them by severity and ID, executes actions and prints the final summary.
uvm_report_catcherOptional callback that can inspect a message before the server processes it, then modify, demote or drop it.

Every component is a report object, so a driver, monitor or test can report directly. Sequences and sequence items are not components, but they also support the reporting macros. Their messages are routed through the sequencer they run on, or through the top of the hierarchy if there is none.

Flow of a UVM report message through the report object, handler, catcher and server

A message first passes the verbosity check in the report object. The handler then attaches the action and file configured for its severity and ID. Any registered catchers can change or drop it, and finally the server formats it and carries out the actions.

Severity, Verbosity and Actions

Severity

Each message has one of four severities, and each severity has a default action.

SeverityMeaningDefault action
UVM_INFOInformational or debug messageUVM_DISPLAY
UVM_WARNINGSomething unusual, but the test can continueUVM_DISPLAY
UVM_ERRORA real problem; the test should failUVM_DISPLAY | UVM_COUNT
UVM_FATALThe simulation cannot continueUVM_DISPLAY | UVM_EXIT

Verbosity

Verbosity sets how much detail you want to see. Each component has a verbosity threshold, UVM_MEDIUM by default. A message is printed only if its verbosity is less than or equal to that threshold.

LevelValueTypical use
UVM_NONE0Always printed
UVM_LOW100Key milestones such as test start and end
UVM_MEDIUM200Normal progress messages (default threshold)
UVM_HIGH300Per-transaction details
UVM_FULL400Very detailed debug
UVM_DEBUG500Deep internal debug

Actions

An action tells the server what to do with a message. Actions are bit flags, so they are combined with |. The most common are UVM_DISPLAY (print to the console), UVM_LOG (write to a file), UVM_COUNT (add to the quit count), UVM_EXIT (end the simulation), UVM_STOP (call $stop) and UVM_NO_ACTION (do nothing).

Syntax

Messages are normally issued through the reporting macros, which add the file name and line number for you. These are covered in detail in Reporting Functions.


`uvm_info    (ID, MESSAGE, VERBOSITY)   // Only info messages take a verbosity
`uvm_warning (ID, MESSAGE)
`uvm_error   (ID, MESSAGE)
`uvm_fatal   (ID, MESSAGE)
  • ID - a short string that names the message type, such as "DRV" or "SCB_MISMATCH". Configuration can target it (required)
  • MESSAGE - the text, usually built with $sformatf (required)
  • VERBOSITY - one of the levels above, for `uvm_info only (required)

Configuring Reports

Because every component is a report object, its reporting behavior can be changed from outside, usually from the test. Each set_report_* function also has a _hier version that applies to the component and everything below it.


class my_test extends uvm_test;
  `uvm_component_utils (my_test)
  // Rest of the code (constructor, build_phase, etc.)

  UVM_FILE m_err_log;

  virtual function void end_of_elaboration_phase (uvm_phase phase);
    super.end_of_elaboration_phase (phase);

    // 1. Show UVM_HIGH messages from the env and all components below it
    m_env.set_report_verbosity_level_hier (UVM_HIGH);

    // 2. Silence one known, harmless message ID everywhere in the env
    m_env.set_report_id_action_hier ("DRV_IDLE", UVM_NO_ACTION);

    // 3. Also write every error to a separate file, and keep counting them
    m_err_log = $fopen ("errors.log", "w");
    m_env.set_report_severity_file_hier (UVM_ERROR, m_err_log);
    m_env.set_report_severity_action_hier (UVM_ERROR, UVM_DISPLAY | UVM_LOG | UVM_COUNT);
  endfunction
endclass

When more than one setting matches a message, the most specific one wins: a severity-and-ID setting overrides an ID setting, which overrides a severity setting.

Many settings can also be changed without recompiling. For example, +UVM_VERBOSITY=UVM_HIGH sets the default verbosity for every component, and +UVM_MAX_QUIT_COUNT=5 ends the test after five counted errors.

Quick Check

Q: A component's threshold is UVM_MEDIUM. Which of these messages are printed: one at UVM_LOW, one at UVM_HIGH, and a `uvm_error?

Show Answer

The UVM_LOW message and the error. UVM_LOW (100) is below the threshold (200), UVM_HIGH (300) is above it, and errors are issued at UVM_NONE, so they always pass the verbosity check.

Where is Report Configuration Used?

Regression scripts usually run every test at UVM_LOW or UVM_MEDIUM to keep logs small. When a test fails, the same seed is rerun with a higher verbosity on just the failing block, so the detailed log covers only the component under investigation.

The Report Server

The report server counts every message by severity and ID and prints the "UVM Report Summary" at the end of the test. It also tracks the quit count: each message with the UVM_COUNT action increments it, and when it reaches the maximum, the test ends.


uvm_report_server svr = uvm_report_server::get_server ();   // The single global server
svr.set_max_quit_count (10);                               // End the test after 10 counted errors

Stopping early saves simulation time when a design is badly broken, because errors after the first few are rarely useful.

The Report Catcher

A report catcher sees each message before the server processes it. Extend uvm_report_catcher, implement catch(), and return THROW to pass the message on, or CAUGHT to drop it.

A common use is an error-injection test, where certain errors are expected and should not fail the test.


class demote_catcher extends uvm_report_catcher;
  `uvm_object_utils (demote_catcher)

  function new (string name = "demote_catcher");
    super.new (name);
  endfunction

  // Called for every message before the report server sees it
  virtual function action_e catch ();
    if (get_severity () == UVM_ERROR && get_id () == "PARITY_ERR")
      set_severity (UVM_WARNING);    // Expected in this test, so do not fail it
    return THROW;                    // Pass the (possibly modified) message on
  endfunction
endclass

// In the test, for example in end_of_elaboration_phase:
// demote_catcher m_catcher = demote_catcher::type_id::create ("m_catcher");
// uvm_report_cb::add (null, m_catcher);    // null = apply to all report objects

Always limit a catcher to specific IDs and only use it in tests that inject that error on purpose. A catcher that demotes every error makes a broken design look like a passing test.

Where are Report Catchers Used?

Error-injection and negative tests use catchers widely. For example, a test that deliberately corrupts parity on a bus expects the monitor to flag parity errors, so it demotes exactly that message ID while every other error still fails the test.

Common Mistakes

Mistake #1: Setting verbosity before the components exist

Wrong: calling m_env.set_report_verbosity_level_hier(UVM_HIGH) in the test's build_phase, right after creating m_env
Right: make the call in end_of_elaboration_phase

Why? The _hier functions apply only to components that already exist. In the test's build_phase, the env has not built its agents yet, so they keep the default UVM_MEDIUM.

Mistake #2: Using verbosity to hide warnings or errors

The `uvm_warning, `uvm_error and `uvm_fatal macros are issued at UVM_NONE, so no verbosity setting can hide them. To silence a known warning, change its action with set_report_id_action() or demote it with a report catcher.

Mistake #3: Overriding an error action and dropping UVM_COUNT

Wrong: set_report_severity_action_hier(UVM_ERROR, UVM_DISPLAY | UVM_LOG)
Right: set_report_severity_action_hier(UVM_ERROR, UVM_DISPLAY | UVM_LOG | UVM_COUNT)

Why? A new action replaces the default completely. Without UVM_COUNT, errors are still printed but no longer counted, so the quit count never triggers, and pass/fail scripts that check the error count can report a failing test as passing.

Practice Exercise

Challenge: Debug One Component, Log One ID

In my_test, configure reporting so that:

  • Only the monitor m_env.m_agent.m_mon prints messages up to UVM_FULL
  • Info messages with ID "SCB" from anywhere in the env are also written to scoreboard.log
  • Errors with ID "SCB" still count toward the quit count
Hint

Use the non-_hier verbosity function for a single component. For the ID, set both a file and an action, but use a severity-and-ID action so errors are not affected.

Solution

class my_test extends uvm_test;
  `uvm_component_utils (my_test)
  // Rest of the code (constructor, build_phase, etc.)

  UVM_FILE m_scb_log;

  virtual function void end_of_elaboration_phase (uvm_phase phase);
    super.end_of_elaboration_phase (phase);

    // Only the monitor gets full detail
    m_env.m_agent.m_mon.set_report_verbosity_level (UVM_FULL);

    // Route all "SCB" messages in the env to scoreboard.log
    m_scb_log = $fopen ("scoreboard.log", "w");
    m_env.set_report_id_file_hier ("SCB", m_scb_log);

    // Add UVM_LOG only for info; errors keep their default action (DISPLAY | COUNT)
    m_env.set_report_severity_id_action_hier (UVM_INFO, "SCB", UVM_DISPLAY | UVM_LOG);
  endfunction

  virtual function void final_phase (uvm_phase phase);
    super.final_phase (phase);
    $fclose (m_scb_log);                 // Flush and close the log file
  endfunction
endclass

Using set_report_id_action_hier("SCB", ...) instead would replace the action for every severity with that ID, and SCB errors would stop being counted.

Summary

In this tutorial, you learned:

  • UVM reporting replaces $display with messages that carry a severity, an ID and a verbosity
  • uvm_report_object, uvm_report_handler, uvm_report_server and uvm_report_catcher each handle one stage of a message's path
  • Info messages print only if their verbosity is at or below the threshold, which is UVM_MEDIUM by default
  • Actions such as UVM_DISPLAY, UVM_LOG, UVM_COUNT and UVM_EXIT are combined with | and set by severity, ID or both
  • Configuration with the _hier functions belongs in end_of_elaboration_phase, after the hierarchy is built
  • The report server counts errors and can end the test, and catchers can demote expected errors in specific tests
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5