Skip to content

UVM

UVM Verbosity Control

The six levels, +UVM_VERBOSITY plusarg, per-component and per-ID control, regression patterns.

UVM Fundamentals · Module 11

The Verbosity Hierarchy — Six Levels, One Rule

UVM defines six verbosity constants. Every ``uvm_info` call declares its verbosity level. Every component has a verbosity threshold. The rule is simple:

UVM verbosity levels and threshold gate
UVM verbosity levels and threshold gate

Figure 1 — The threshold gate. With default threshold UVM_MEDIUM (200): UVM_NONE/LOW/MEDIUM messages pass, UVM_HIGH/FULL/DEBUG are filtered. Raising the threshold to UVM_HIGH shows more detail without showing everything.

ConstantValueTypical UseAlways Visible At Threshold
UVM_NONE0Critical status — test PASS/FAIL, simulation milestones. Must always be visible.Every threshold setting
UVM_LOW100Important events — transaction starts/ends, phase transitions, key state changes.UVM_LOW and above
UVM_MEDIUM200Normal operation debug — transaction content, scoreboard checks, driver activity. Default threshold.UVM_MEDIUM and above
UVM_HIGH300Detailed signal-level debug — cycle-by-cycle bus activity, intermediate values.UVM_HIGH and above
UVM_FULL400Extremely verbose — internal state dumps, every clock edge logged.UVM_FULL and above
UVM_DEBUG500UVM framework internals. Very rarely needed by testbench engineers.UVM_DEBUG only

Runtime Verbosity Control — The +UVM_VERBOSITY Plusarg

The production-standard approach: control verbosity entirely from the command line without touching source code. One plusarg sets the threshold for every component in the simulation. This is the method used in regression farms.

Shell — UVM_VERBOSITY plusarg patterns
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
## Standard regression runminimal output (fast logs, CI-friendly)
vsim +UVM_VERBOSITY=UVM_LOW  work.tb_top
 
## Default development run
vsim +UVM_VERBOSITY=UVM_MEDIUM  work.tb_top
 
## Debug rundetailed transaction-level output
vsim +UVM_VERBOSITY=UVM_HIGH  work.tb_top
 
## Numeric also accepteduseful when scripting
vsim +UVM_VERBOSITY=300  work.tb_top   ## same as UVM_HIGH
vsim +UVM_VERBOSITY=400  work.tb_top   ## same as UVM_FULL
 
## VCS syntax
vcs +UVM_VERBOSITY=UVM_HIGH ... && simv +UVM_VERBOSITY=UVM_HIGH
 
## Xcelium syntax
xrun -uvmverbosity UVM_HIGH  work.tb_top
 
## No plusarg = UVM_MEDIUM (the compiled-in default)
 
## Combine with other UVM plusargs:
vsim +UVM_TESTNAME=smoke_test \
     +UVM_VERBOSITY=UVM_LOW   \
     +UVM_TIMEOUT=1ms         \
     work.tb_top

Programmatic Verbosity Control — In-Simulation Adjustment

For interactive debug sessions where you want to raise verbosity on one specific component without rebuilding the command line — or for tests that dynamically increase verbosity just before a known complex region — use the programmatic API.

SystemVerilog — programmatic verbosity control methods
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── Set verbosity on this component only ─────────────────────────────
// Called inside the component (this.set_report_verbosity_level)
function void start_of_simulation_phase(uvm_phase phase);
    super.start_of_simulation_phase(phase);
    set_report_verbosity_level(UVM_HIGH);   // only THIS component
endfunction
 
// ── Set verbosity on this component AND all its children ─────────────
set_report_verbosity_level_hier(UVM_HIGH);
// If called on env: all agents, drivers, monitors also get UVM_HIGH
 
// ── Set from outside a component (via handle) ─────────────────────────
// In the test, after env is built:
env.apb_agent.drv.set_report_verbosity_level(UVM_FULL);
// Only apb_agent's driver gets UVM_FULL — all others stay at default
 
// ── Dynamic verbosity change during run_phase ─────────────────────────
task run_phase(uvm_phase phase);
    // Normal operation — minimal output
    set_report_verbosity_level(UVM_LOW);
 
    // Before a complex handshake sequence — bump verbosity
    @(vif.START_CONDITION);
    set_report_verbosity_level(UVM_HIGH);
    execute_handshake();
    set_report_verbosity_level(UVM_LOW);   // restore after
endtask
 
// ── Read the current verbosity level ─────────────────────────────────
int current = get_report_verbosity_level();
`uvm_info("VRB", $sformatf("Current verbosity: %0d", current), UVM_NONE)

Per-Component and Per-ID Verbosity — Precision Targeting

When a specific module is noisy and you want to silence just its detailed messages without changing global verbosity, or when a critical flow needs detailed logging while everything else stays quiet:

SystemVerilog — per-ID verbosity override
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── Silence a noisy message ID (even if global verbosity is high) ─────
// Context: "CYCLE_TRACE" fires on every clock edge — 50,000 messages per test
// Global verbosity is UVM_HIGH — but we don't want CYCLE_TRACE messages
set_report_id_verbosity("CYCLE_TRACE", UVM_DEBUG);
// CYCLE_TRACE messages now only shown if global verbosity = UVM_DEBUG (500)
// At UVM_HIGH (300), they are filtered — other HIGH messages still appear
 
// ── Always show a specific ID (override lower global verbosity) ───────
// Context: global verbosity is UVM_LOW for regression
// But "HANDSHAKE" messages are critical debug info — always show them
set_report_id_verbosity("HANDSHAKE", UVM_NONE);
// HANDSHAKE messages now appear regardless of global verbosity setting
 
// ── Combining per-component + per-ID ─────────────────────────────────
// In start_of_simulation_phase of apb_driver:
set_report_verbosity_level(UVM_LOW);            // driver: default LOW
set_report_id_verbosity("DRV_DETAIL", UVM_NONE); // always show DRV_DETAIL
set_report_id_verbosity("BUS_IDLE", UVM_DEBUG);  // BUS_IDLE: only at DEBUG level
 
// ── The override priority chain ───────────────────────────────────────
// Per-ID verbosity overrides the component threshold for that specific ID.
// Component threshold applies to all other IDs.
// Global +UVM_VERBOSITY sets the initial component threshold for all components.
// Programmatic set_report_verbosity_level() overrides the plusarg for that component.

Priority Order — From Highest to Lowest

PriorityMechanismScope
1 (highest)set_report_id_verbosity("ID", level)Specific message ID in this component
2set_report_verbosity_level(level)All messages in this component
3+UVM_VERBOSITY=LEVEL plusargAll components globally
4 (lowest)Compiled-in default: UVM_MEDIUMAll components globally

Compile-Time Verbosity — Performance and Message Removal

Runtime filtering is powerful but has a small cost: even filtered messages still evaluate the $sformatf() string before the check discards the result. For production-speed simulation, compile-time removal eliminates this overhead entirely.

SystemVerilog — compile-time verbosity defines
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── Why compile-time control matters: the sformatf overhead ──────────
`uvm_info("MON", $sformatf(
    "Observed addr=0x%0h data=0x%0h resp=%0b at %0t",
    txn.addr, txn.data, txn.resp, $time), UVM_HIGH)
 
// Even if verbosity is UVM_LOW and this message is filtered:
// 1. $sformatf() is evaluated — string formatting takes time
// 2. uvm_report_enabled() is called — returns 0 and discards the string
// In a monitor that fires every 2ns for 1ms: 500,000 sformatf calls
 
// ── UVM compile-time define: set default verbosity ───────────────────
// vlog +define+UVM_DEFAULT_VERBOSITY=UVM_LOW
// Sets the initial threshold for all components at compile time
// Still overridable at runtime with +UVM_VERBOSITY plusarg
 
// ── Performance trick: check verbosity BEFORE the expensive sformatf ─
if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "MON")) begin
    // sformatf only called if the message will actually be shown
    `uvm_info("MON", $sformatf("..."), UVM_HIGH)
end
// Use this pattern for messages in tight loops or with expensive formatting
 
// ── UVM_NO_* defines: compile-time message removal ───────────────────
// These are preprocessor defines that eliminate macro calls at compile time:
//
// +define+UVM_NO_INFO    → removes ALL `uvm_info calls from compilation
//                          Warnings, errors, fatals still present
//
// Use case: gate-level simulation for timing — no testbench overhead
// Warning: you lose ALL diagnostic output — debug is impossible
// Recommendation: never use in regular development; only for specific GLS flows

Verbosity in Production Regression Environments

A well-designed regression infrastructure never requires log files to be examined manually for pass/fail. Verbosity is set low enough to keep logs small but high enough to diagnose failures when they occur.

Makefile — tiered verbosity for regression and debug runs
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
## Makefiletiered verbosity targets
 
## Default: regression modeminimal log, CI-friendly
regression:
	vsim +UVM_TESTNAME=$(TEST)         \
	     +UVM_VERBOSITY=UVM_NONE       \
	     +UVM_TIMEOUT=10ms             \
	     work.tb_top
 
## Development: medium output for daily runs
run:
	vsim +UVM_TESTNAME=$(TEST)         \
	     +UVM_VERBOSITY=UVM_MEDIUM     \
	     work.tb_top
 
## Debug: high verbosityuse when a test is failing
debug:
	vsim +UVM_TESTNAME=$(TEST)         \
	     +UVM_VERBOSITY=UVM_HIGH       \
	     work.tb_top
 
## Deep debug: full verbositylast resort
trace:
	vsim +UVM_TESTNAME=$(TEST)         \
	     +UVM_VERBOSITY=UVM_FULL       \
	     work.tb_top
 
## Usage:  make regression TEST=smoke_test
##         make debug       TEST=failing_test

Logging to File for Post-Processing

SystemVerilog — routing UVM output for regression log parsing
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// In regression: errors and warnings always appear in the transcript
// CI systems grep for specific patterns:
// grep "UVM_ERROR\|UVM_FATAL" sim.log | wc -l  → 0 = PASS
 
// ── Set up file logging for HIGH verbosity (selective per-component) ──
function void start_of_simulation_phase(uvm_phase phase);
    integer fd;
    super.start_of_simulation_phase(phase);
 
    if ($test$plusargs("LOG_DRIVER")) begin
        fd = $fopen("driver_log.txt", "w");
        set_report_default_file(fd);           // all messages from this comp → file
        set_report_severity_action(UVM_INFO,
            UVM_DISPLAY | UVM_LOG);              // console AND file
        set_report_verbosity_level(UVM_FULL);   // full detail in log
    end
endfunction
 
// Simulate with: vsim +UVM_VERBOSITY=UVM_LOW +LOG_DRIVER work.tb_top
// Result: console has LOW verbosity; driver_log.txt has FULL verbosity

Verbosity Anti-Patterns — What to Avoid

Anti-Pattern 1 — Using $display instead of uvm_info $display("addr=%0h", req.addr)`

Bypasses verbosity filtering completely. Always prints regardless of +UVM_VERBOSITY. Not tagged with component path. Cannot be routed to file. Cannot be silenced per-ID.

Use uvm_info("ID", msg, UVM_HIGH)` instead. Correct — `uvm_info with appropriate verbosity uvm_info("DRV", $sformatf("addr=%0h", req.addr), UVM_HIGH)`

Filtered by verbosity. Tagged with component path. Routable to file. Silenceable per-ID. Counted separately from warnings/errors. Anti-Pattern 2 — Hardcoding UVM_FULL in components set_report_verbosity_level(UVM_FULL) in every component's build_phase.

Overrides the plusarg. Every regression run generates gigabyte logs regardless of +UVM_VERBOSITY. Defeats the entire verbosity control system. Correct — Respect the hierarchy Let plusarg control global threshold. Use set_report_verbosity_level() only for targeted debug in specific circumstances. Remove it before commit. Anti-Pattern 3 — All messages at UVM_LOW or UVM_NONE Every ``uvm_infousesUVM_NONEorUVM_LOW. In regression with +UVM_VERBOSITY=UVM_NONE, 10,000 messages still appear — they're all "critical". Correct — Use verbosity to express message importance UVM_NONE: test result only. UVM_LOW: major events. UVM_MEDIUM: transaction-level. UVM_HIGH`: signal-level. Fewer UVM_LOW messages = cleaner regression logs.

Quick Reference

TaskMethod / Plusarg
Set global verbosity (runtime)+UVM_VERBOSITY=UVM_HIGH (or numeric 300)
Set this component's verbosityset_report_verbosity_level(UVM_HIGH)
Set this component + all childrenset_report_verbosity_level_hier(UVM_HIGH)
Read current verbosityget_report_verbosity_level()
Silence specific message IDset_report_id_verbosity("ID", UVM_DEBUG)
Always show specific message IDset_report_id_verbosity("ID", UVM_NONE)
Check enabled before expensive formatif (uvm_report_enabled(UVM_HIGH, UVM_INFO, "ID"))
Set verbosity from outside componentenv.agent.drv.set_report_verbosity_level(UVM_FULL)
Compile-time default+define+UVM_DEFAULT_VERBOSITY=UVM_LOW
SystemVerilog — verbosity discipline quick reference
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── UVM_NONE (0): always visible — test PASS/FAIL only ────────────────
`uvm_info("RESULT", "*** TEST PASSED ***", UVM_NONE)
 
// ── UVM_LOW (100): important milestones ───────────────────────────────
`uvm_info("TEST", "Starting directed register test sequence", UVM_LOW)
 
// ── UVM_MEDIUM (200): transaction-level — default visibility ─────────
`uvm_info("DRV", $sformatf("Driving txn: addr=0x%0h write=%0b",
           req.addr, req.write), UVM_MEDIUM)
 
// ── UVM_HIGH (300): signal/cycle-level — debug runs only ─────────────
`uvm_info("MON", $sformatf("psel=%0b penable=%0b pready=%0b",
           vif.psel, vif.penable, vif.pready), UVM_HIGH)
 
// ── UVM_FULL (400): internal state — last resort ──────────────────────
`uvm_info("SEQR", $sformatf("Arbitration state: %s", arb_state), UVM_FULL)
 
// ── Production verbosity table ────────────────────────────────────────
//   Regression CI   : +UVM_VERBOSITY=UVM_NONE   (0)   — only PASS/FAIL
//   Development run : +UVM_VERBOSITY=UVM_MEDIUM  (200)  — default
//   Debug run       : +UVM_VERBOSITY=UVM_HIGH    (300)  — detailed
//   Full trace      : +UVM_VERBOSITY=UVM_FULL    (400)  — everything

§9 — Code Examples

Example 1 — Beginner: Verbosity Threshold in Action

The best way to understand the threshold rule is to see the same five messages filtered differently across different verbosity settings. This example makes the gate visible.

SystemVerilog — verbosity threshold gate demonstrated
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class apb_monitor extends uvm_monitor;
    `uvm_component_utils(apb_monitor)
 
    task run_phase(uvm_phase phase);
        apb_seq_item txn;
        forever begin
            @(posedge vif.clk);
            if (vif.psel) begin
                txn = apb_seq_item::type_id::create("txn");
                txn.addr  = vif.paddr;
                txn.data  = vif.pwdata;
                txn.write = vif.pwrite;
 
                // Level 0 — always visible, even at UVM_NONE threshold
                `uvm_info("MON", "APB transaction captured", UVM_NONE)
 
                // Level 100 — visible at UVM_LOW and above
                `uvm_info("MON", $sformatf("TXN: addr=0x%0h write=%0b",
                    txn.addr, txn.write), UVM_LOW)
 
                // Level 200 — visible at UVM_MEDIUM and above (DEFAULT)
                `uvm_info("MON", $sformatf("TXN: data=0x%0h", txn.data), UVM_MEDIUM)
 
                // Level 300 — only at UVM_HIGH and above
                `uvm_info("MON", $sformatf("BUS: psel=%0b penable=%0b pready=%0b",
                    vif.psel, vif.penable, vif.pready), UVM_HIGH)
 
                // Level 400 — only at UVM_FULL (internal state, rarely needed)
                `uvm_info("MON", $sformatf("CLK cycle %0d, internal fsm=%0d",
                    cycle_count, fsm_state), UVM_FULL)
            end
        end
    endtask
endclass
 
// What prints at different thresholds per transaction:
//
// +UVM_VERBOSITY=UVM_NONE   (threshold=0):   1 message  — "APB transaction captured"
// +UVM_VERBOSITY=UVM_LOW    (threshold=100): 2 messages — + "TXN: addr=0x... write=..."
// +UVM_VERBOSITY=UVM_MEDIUM (threshold=200): 3 messages — + "TXN: data=0x..."
// +UVM_VERBOSITY=UVM_HIGH   (threshold=300): 4 messages — + "BUS: psel=... penable=..."
// +UVM_VERBOSITY=UVM_FULL   (threshold=400): 5 messages — + "CLK cycle N, fsm=..."
//
// In regression: +UVM_VERBOSITY=UVM_NONE → minimal log
// In debug mode: +UVM_VERBOSITY=UVM_HIGH → full transaction + bus signal view

Example 2 — Intermediate: Precision Targeting with Per-Component and Per-ID Control

A test that runs globally at UVM_NONE verbosity for a clean regression log, but specifically raises verbosity on the scoreboard for detailed mismatch analysis and permanently silences a high-frequency bus-idle message.

SystemVerilog — precision verbosity targeting in a test
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class precision_test extends base_test;
    `uvm_component_utils(precision_test)
 
    function void start_of_simulation_phase(uvm_phase phase);
        super.start_of_simulation_phase(phase);
 
        // Step 1: Start everyone at UVM_LOW (set globally, then override specific ones)
        // Global default from +UVM_VERBOSITY=UVM_LOW on command line
 
        // Step 2: Scoreboard gets full verbosity — mismatches need all context
        env.sb.set_report_verbosity_level(UVM_FULL);
 
        // Step 3: APB monitor gets reduced verbosity — already verified
        env.apb_agent.mon.set_report_verbosity_level(UVM_NONE);
 
        // Step 4: Silence BUS_IDLE from driver — fires every cycle, already known good
        env.apb_agent.drv.set_report_id_verbosity("BUS_IDLE", UVM_DEBUG);
        // BUS_IDLE: only shows if global verbosity is UVM_DEBUG — effectively silenced
 
        // Step 5: HANDSHAKE must always appear — critical protocol event
        env.apb_agent.drv.set_report_id_verbosity("HANDSHAKE", UVM_NONE);
        // HANDSHAKE: visible at threshold 0 — always shown regardless of global setting
 
        `uvm_info("TEST", "Precision verbosity config applied", UVM_LOW)
    endfunction
 
    // Result at +UVM_VERBOSITY=UVM_LOW:
    // env.sb:              FULL verbosity  — all scoreboard detail printed
    // env.apb_agent.mon:  NONE verbosity  — silent (only errors/warnings from it)
    // env.apb_agent.drv:  LOW  verbosity  — BUS_IDLE silenced, HANDSHAKE always visible
    // Everything else:     LOW  verbosity  — from the global plusarg
endclass

Example 3 — Verification: Dynamic Verbosity During Run-Phase

A production pattern for complex protocol flows: run at low verbosity until a specific signal condition is detected, then temporarily raise verbosity to capture full detail through the critical handshake window, then drop back.

SystemVerilog — dynamic verbosity in a protocol monitor
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class protocol_monitor extends uvm_monitor;
    `uvm_component_utils(protocol_monitor)
    virtual apb_if vif;
 
    task run_phase(uvm_phase phase);
        int saved_verbosity;
        forever begin
            // Wait for an error response — rare event worth detailed capture
            @(posedge vif.clk iff (vif.psel && vif.pslverr));
 
            // Save current verbosity before bumping
            saved_verbosity = get_report_verbosity_level();
 
            `uvm_info("MON", "PSLVERR detected — capturing detailed context", UVM_LOW)
 
            // Temporarily raise verbosity for detailed analysis window
            set_report_verbosity_level(UVM_FULL);
 
            // Capture 10 cycles of detailed signal state
            repeat(10) begin
                @(posedge vif.clk);
                `uvm_info("MON", $sformatf(
                    "[POST-ERR] paddr=0x%0h pwdata=0x%0h pslverr=%0b pready=%0b",
                    vif.paddr, vif.pwdata, vif.pslverr, vif.pready), UVM_FULL)
            end
 
            // Restore previous verbosity — don't leave it elevated
            set_report_verbosity_level(saved_verbosity);
            `uvm_info("MON", "Verbosity restored", UVM_LOW)
        end
    endtask
endclass
 
// Normal operation:  LOW verbosity — minimal output
// On PSLVERR event:  FULL verbosity for 10 cycles — complete bus capture
// After window:      verbosity restored to original level
// No code changes, no recompile, no waveform needed for most failures

Example 4 — Tricky: The sformatf Performance Trap

The most common performance mistake in high-frequency monitors: expensive string formatting runs on every cycle even when the message will be filtered. At 500 MHz simulation with a cycle-by-cycle monitor, this matters.

SystemVerilog — sformatf evaluation cost and the guard pattern
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ❌ SLOW — sformatf runs every cycle regardless of verbosity ─────────
task run_phase(uvm_phase phase);
    forever begin
        @(posedge vif.clk);
        // At UVM_LOW threshold: this line fires uvm_report_enabled → returns 0
        // BUT $sformatf was already evaluated before the call! Zero benefit from filter.
        `uvm_info("MON", $sformatf(
            "CYCLE %0d: paddr=0x%0h pwdata=0x%0h psel=%0b penable=%0b pready=%0b @%0t",
            cycle_cnt, vif.paddr, vif.pwdata,
            vif.psel, vif.penable, vif.pready, $time), UVM_HIGH)
        cycle_cnt++;
    end
endtask
 
// At 1ns clock for 1ms simulation: 1,000,000 $sformatf calls
// Each formats 6 signals + timestamp — significant string allocation overhead
 
// ✓ FAST — guard with uvm_report_enabled() ─────────────────────────────
task run_phase(uvm_phase phase);
    forever begin
        @(posedge vif.clk);
        // Check FIRST — only format the string if it will actually be printed
        if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "MON")) begin
            `uvm_info("MON", $sformatf(
                "CYCLE %0d: paddr=0x%0h pwdata=0x%0h psel=%0b penable=%0b pready=%0b @%0t",
                cycle_cnt, vif.paddr, vif.pwdata,
                vif.psel, vif.penable, vif.pready, $time), UVM_HIGH)
        end
        cycle_cnt++;
    end
endtask
 
// At UVM_LOW threshold, UVM_HIGH guard returns 0:
// sformatf() never called → zero string allocation → measurable speedup
// At UVM_HIGH threshold: guard returns 1 → sformatf runs normally
// Use this pattern in any monitor that fires on every clock cycle

§10 — Bugs and Debugging

Bug 1 — Hardcoded UVM_FULL Left from a Debug Session

SystemVerilog — hardcoded verbosity overriding the plusarg
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ❌ COMMITTED BUG — debug verbosity left in build_phase ─────────────
class apb_driver extends uvm_driver#(apb_seq_item);
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        set_report_verbosity_level(UVM_FULL);  // ← FORGOT TO REMOVE
    endfunction
endclass
 
// What happens:
// Command line: vsim +UVM_VERBOSITY=UVM_NONE  ← engineers expect minimal log
// Reality: driver overrides at build_phase → UVM_FULL → massive output
// UVM applies plusarg BEFORE build_phase fires, then set_report_verbosity_level() wins
 
// ✓ CORRECT — no hardcoded verbosity in committed code ────────────────
class apb_driver extends uvm_driver#(apb_seq_item);
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        // No set_report_verbosity_level here — let the plusarg control it
        // Per-component overrides belong in the TEST's start_of_simulation_phase
    endfunction
endclass
 
// If you need per-component verbosity in tests, set it from the test:
// env.apb_agent.drv.set_report_verbosity_level(UVM_HIGH);
// This way it's scoped to specific tests, not baked into the reusable component.

Bug 2 — All Messages Tagged UVM_LOW: Verbosity Control Becomes Useless

SystemVerilog — verbosity inflation vs disciplined assignment
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ❌ WRONG — verbosity inflation: everything is UVM_LOW ───────────────
task run_phase(uvm_phase phase);
    forever begin
        @(posedge vif.clk);
        `uvm_info("DRV", "Clock edge",                             UVM_LOW) // 1M times/ms
        `uvm_info("DRV", $sformatf("paddr=0x%0h", vif.paddr),     UVM_LOW) // cycle-level
        `uvm_info("DRV", $sformatf("pwdata=0x%0h", vif.pwdata),    UVM_LOW) // cycle-level
        `uvm_info("DRV", $sformatf("pready=%0b", vif.pready),     UVM_LOW) // cycle-level
    end
endtask
// Result: +UVM_VERBOSITY=UVM_NONE does nothing useful
// Regression logs are still massive — verbosity system is defeated
 
// ✓ CORRECT — verbosity reflects actual importance ─────────────────────
task run_phase(uvm_phase phase);
    apb_seq_item req;
    forever begin
        seq_item_port.get_next_item(req);
 
        `uvm_info("DRV", $sformatf("Driving txn: addr=0x%0h", req.addr), UVM_MEDIUM)
        // ↑ Transaction start: medium importance — one per transaction
 
        @(posedge vif.clk);
        vif.paddr <= req.addr;
        `uvm_info("DRV", $sformatf("Bus cycle: psel=%0b pready=%0b",
            vif.psel, vif.pready), UVM_HIGH)
        // ↑ Cycle-level: high verbosity — only in debug mode
 
        seq_item_port.item_done();
    end
endtask
// Result: +UVM_VERBOSITY=UVM_LOW  → no driver messages (all MEDIUM/HIGH)
// Result: +UVM_VERBOSITY=UVM_MEDIUM → transaction-level only (clean)
// Result: +UVM_VERBOSITY=UVM_HIGH  → full cycle detail for debugging

Bug 3 — set_report_id_verbosity on the Wrong Component

SystemVerilog — wrong vs right component for ID verbosity
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ❌ WRONG — called on env, but BUS_IDLE is from drv ──────────────────
class apb_env extends uvm_env;
    function void start_of_simulation_phase(uvm_phase phase);
        set_report_id_verbosity("BUS_IDLE", UVM_DEBUG); // sets on env — not driver!
        // env doesn't emit BUS_IDLE — driver does. This call does nothing useful.
    endfunction
endclass
 
// ✓ CORRECT option A — set on driver directly from test ───────────────
class my_test extends base_test;
    function void start_of_simulation_phase(uvm_phase phase);
        super.start_of_simulation_phase(phase);
        env.apb_agent.drv.set_report_id_verbosity("BUS_IDLE", UVM_DEBUG);
        // Explicitly targeting the component that emits the ID
    endfunction
endclass
 
// ✓ CORRECT option B — set inside the driver itself ───────────────────
class apb_driver extends uvm_driver#(apb_seq_item);
    function void start_of_simulation_phase(uvm_phase phase);
        super.start_of_simulation_phase(phase);
        set_report_id_verbosity("BUS_IDLE", UVM_DEBUG);
        // 'this' IS the driver — correct component
    endfunction
endclass

§10b — The Message That Was Never Printed

Every other bug on this page produces wrong output. This one produces no output, which is harder, because absence of evidence looks exactly like absence of the event.

1

A driver appeared to stop driving, and the transactions were fine

VERBOSITY-FILTERED-EVIDENCE
Symptom

A scoreboard reported that a burst of transactions never reached the DUT. The driver's own trace confirmed it: uvm_info messages logging each drive stopped appearing partway through the test, and the log went quiet for thousands of cycles before resuming.

A day went into the driver and the sequencer handshake — get_next_item, item_done, the sequence's own loop — on the reasonable assumption that a driver which stops logging has stopped driving. It had not. The waveform showed the bus active throughout the silent window.

Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// In a test, to quieten one noisy agent during a long soak phase:
function void my_test::configure_phase(uvm_phase phase);
  super.configure_phase(phase);
  // Intent: reduce output from the memory agent only.
  uvm_top.set_report_verbosity_level_hier(UVM_NONE);   // ✗ applies to EVERYTHING
endfunction
 
// The driver's trace, written at the usual level:
`uvm_info("DRV", $sformatf("driving %s", req.convert2string()), UVM_MEDIUM)
Diagnostic Evidence

The decisive check took one line and should have been the first thing tried:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
`uvm_info("DBG", $sformatf("my verbosity threshold = %0d",
                           get_report_verbosity_level()), UVM_NONE)
// -> my verbosity threshold = 0     (UVM_NONE)

The driver's threshold was 0, so its UVM_MEDIUM (200) trace could not print. Printing the query at UVM_NONE is what makes this work — a diagnostic written at the level you are debugging is filtered by the same setting you are trying to observe.

+UVM_VERBOSITY was not on the command line, which is why the run looked like a default one. The threshold had been changed from inside the testbench, and set_report_verbosity_level_hier on uvm_top reaches the entire component tree rather than the one agent the author intended.

The confirming evidence was that the bus was active in the waveform for the same window the log was silent. A quiet log and a busy bus is a reporting problem, not a stimulus problem — and that comparison costs nothing.

Root Cause

Two mistakes compounding.

set_report_verbosity_level_hier applied to uvm_top sets the threshold for every component in the hierarchy, not for a subtree. Targeting one agent requires calling it on that agent's handle — env.mem_agent.set_report_verbosity_level_hier(UVM_NONE) — or, better, leaving the threshold alone and using set_report_id_verbosity to quieten one message ID.

And the driver's own trace was written at UVM_MEDIUM, which is exactly the default threshold. Anything written at the default disappears the moment the threshold moves down, which makes the most useful traces the most fragile.

What makes this class expensive is the inference it invites. A missing log line is read as a missing event, and every subsequent hypothesis is built on that. The verification engineer was debugging a driver that was working, using evidence that had been deleted rather than never produced — and there is nothing in a log to distinguish those two cases.

Fix
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 1. Target the subtree you mean, not the whole tree.
env.mem_agent.set_report_verbosity_level_hier(UVM_NONE);
 
// 2. Better still: leave thresholds alone and quieten one message ID, so
//    every other message from that component survives.
env.mem_agent.set_report_id_verbosity_hier("MEM_TRACE", UVM_HIGH);
 
// 3. Write structural traces one level ABOVE the noise, so a routine
//    threshold change cannot erase them.
`uvm_info("DRV", $sformatf("driving %s", req.convert2string()), UVM_HIGH)  // detail
`uvm_info("DRV", "driver entered run_phase", UVM_LOW)                      // structure

The habit that closes the whole class is to make the reporting configuration observable rather than assumed:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
function void end_of_elaboration_phase(uvm_phase phase);
  super.end_of_elaboration_phase(phase);
  // Printed at UVM_NONE so it survives any threshold.
  `uvm_info("CFG", $sformatf("%s verbosity = %0d",
            get_full_name(), get_report_verbosity_level()), UVM_NONE)
endfunction

One line per component, printed at a level nothing can filter, and every future "my message vanished" question is answered by the top of the log.

The diagnostic rule worth internalising: before debugging a missing event, prove the event is missing. Compare the log against a waveform, a coverage count, or a UVM_NONE heartbeat. A quiet log and a busy bus is a reporting problem, and the two investigations have nothing in common.

See messaging infrastructure for the report path this sits on and report catchers for changing a message's severity rather than its visibility.

§11 — Ready-to-Run Code

A complete, self-contained verbosity demo. Run it three times with different +UVM_VERBOSITY arguments and observe how the output changes without touching a single line of code. That's the whole point.

verbosity_demo.sv — compile and run with different +UVM_VERBOSITY
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// verbosity_demo.sv
// Compile: vlog -sv verbosity_demo.sv
// Run A:   vsim -c work.tb_verb_top +UVM_TESTNAME=verb_test +UVM_VERBOSITY=UVM_NONE   -do "run -all; quit"
// Run B:   vsim -c work.tb_verb_top +UVM_TESTNAME=verb_test +UVM_VERBOSITY=UVM_MEDIUM -do "run -all; quit"
// Run C:   vsim -c work.tb_verb_top +UVM_TESTNAME=verb_test +UVM_VERBOSITY=UVM_HIGH   -do "run -all; quit"
 
`include "uvm_macros.svh"
import uvm_pkg::*;
 
class verbose_component extends uvm_component;
    `uvm_component_utils(verbose_component)
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
 
    task run_phase(uvm_phase phase);
        phase.raise_objection(this);
 
        `uvm_info("DEMO", "[NONE=0]    Always visible — test milestone",  UVM_NONE)
        `uvm_info("DEMO", "[LOW=100]   Important event — visible at LOW+",  UVM_LOW)
        `uvm_info("DEMO", "[MED=200]   Transaction — visible at MEDIUM+",   UVM_MEDIUM)
        `uvm_info("DEMO", "[HIGH=300]  Signal detail — visible at HIGH+",  UVM_HIGH)
        `uvm_info("DEMO", "[FULL=400]  Internal state — visible at FULL+", UVM_FULL)
 
        // Per-ID override demonstration
        set_report_id_verbosity("ALWAYS_ON", UVM_NONE);
        set_report_id_verbosity("ALWAYS_OFF", UVM_DEBUG);
 
        `uvm_info("ALWAYS_ON",  "[ID override UVM_NONE]  Always shown", UVM_FULL)
        `uvm_info("ALWAYS_OFF", "[ID override UVM_DEBUG] Never shown",  UVM_NONE)
        // ALWAYS_ON fires despite UVM_FULL tag — per-ID override wins
        // ALWAYS_OFF silent despite UVM_NONE tag — per-ID DEBUG threshold applied
 
        phase.drop_objection(this);
    endtask
endclass
 
class verb_test extends uvm_test;
    `uvm_component_utils(verb_test)
    verbose_component vc;
 
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
 
    function void build_phase(uvm_phase phase);
        vc = verbose_component::type_id::create("vc", this);
    endfunction
 
    function void report_phase(uvm_phase phase);
        `uvm_info("RESULT", $sformatf("Verbosity threshold was: %0d",
            vc.get_report_verbosity_level()), UVM_NONE)
    endfunction
endclass
 
module tb_verb_top;
    initial run_test();
endmodule
 
// Expected output:
//
// Run A: +UVM_VERBOSITY=UVM_NONE (threshold=0)
//   [NONE=0]    Always visible — test milestone
//   [ID override UVM_NONE]  Always shown    ← per-ID override fires despite FULL tag
//   Verbosity threshold was: 0
//
// Run B: +UVM_VERBOSITY=UVM_MEDIUM (threshold=200)
//   [NONE=0]    Always visible — test milestone
//   [LOW=100]   Important event — visible at LOW+
//   [MED=200]   Transaction — visible at MEDIUM+
//   [ID override UVM_NONE]  Always shown    ← still fires
//   Verbosity threshold was: 200
//
// Run C: +UVM_VERBOSITY=UVM_HIGH (threshold=300)
//   [NONE=0]    Always visible — test milestone
//   [LOW=100]   Important event — visible at LOW+
//   [MED=200]   Transaction — visible at MEDIUM+
//   [HIGH=300]  Signal detail — visible at HIGH+
//   [ID override UVM_NONE]  Always shown    ← still fires
//   Verbosity threshold was: 300
//
// Note: "ALWAYS_OFF" never appears in any run (per-ID threshold = 500 = UVM_DEBUG)

§12 — Interview Questions

A message prints when its declared verbosity is less than or equal to the component's threshold. The default threshold is UVM_MEDIUM (200).

The numbering runs the opposite way from importance, which is the part that confuses people: UVM_NONE is 0 and always prints, UVM_DEBUG is 500 and prints only when the threshold is raised that far. So a lower number means a more important message, and raising the threshold shows more output rather than less.

At the default of 200, UVM_NONE, UVM_LOW and UVM_MEDIUM messages appear while UVM_HIGH, UVM_FULL and UVM_DEBUG are filtered.

The practical consequence for authoring: anything written at UVM_MEDIUM sits exactly at the default and disappears the moment anyone lowers the threshold. Structural traces — a component entering run_phase, a phase objection being raised — belong at UVM_LOW or UVM_NONE, and per-transaction detail belongs at UVM_HIGH or above.

No, and conflating them is the most common misconception about UVM reporting.

Severity is what the message is: UVM_INFO, UVM_WARNING, UVM_ERROR, UVM_FATAL. It determines the count that decides pass/fail and whether the simulation stops — the counting itself lives in the report server, and report catchers can change a severity without touching verbosity.

Verbosity is how much detail the message represents, and it only gates visibility. Changing verbosity never changes a verdict — filtering an UVM_INFO does not make a test pass, and no verbosity setting can turn an error into a non-error.

The precise mechanism is worth knowing because the usual shorthand is slightly wrong. Warnings and errors are not exempt from the verbosity check — they pass through the same filter. What protects them is that the `uvm_warning, `uvm_error and `uvm_fatal macros hard-code UVM_NONE, which is 0 and therefore passes every threshold.

Call the function form directly and that protection is gone: uvm_report_warning("ID", "msg", UVM_HIGH) is genuinely filterable at the default threshold. Prefer the macros — they also capture file and line for you.

Target the narrowest scope that solves the problem, in this order of preference.

By message ID, which is the least destructive: agent.set_report_id_verbosity_hier("MEM_TRACE", UVM_HIGH) silences one stream while every other message from that component survives.

By component subtree: env.mem_agent.set_report_verbosity_level_hier(UVM_NONE). Note the handle — calling the same method on uvm_top applies it to the entire hierarchy, which is the mistake in this page's Debug Lab.

Globally, from the command line: +UVM_VERBOSITY=UVM_LOW for a regression run. Reporting debug techniques covers the wider set of controls. This is the right tool for controlling log volume across a whole regression and the wrong one for isolating a single agent.

What to avoid is deleting the messages, or writing them at a level so high that nobody ever sees them. A trace that exists only in a comment is not a trace, and the cost of a filtered message is zero at run time — UVM checks the threshold before formatting the string.

Four checks, cheapest first.

Print the component's threshold at UVM_NONEget_report_verbosity_level(). Writing that query at the level you are debugging is self-defeating, since the same filter hides it.

Check whether anything set it from inside the testbench. An absent +UVM_VERBOSITY on the command line does not mean the threshold is default; set_report_verbosity_level_hier on uvm_top reaches everything, and a call meant for one agent commonly lands on all of them.

Check for an ID-specific override. set_report_id_verbosity beats the component threshold for that ID, so one message can be invisible while its neighbours print.

Check the code actually executes. Only after the first three — put a UVM_NONE message immediately before the missing one, and if that also fails to appear, you have a control-flow problem rather than a reporting one.

The framing that saves the most time: before debugging a missing event, prove the event is missing. Compare the log against a waveform or a coverage count. A quiet log and a busy bus is a reporting problem, and it shares nothing with the stimulus investigation it superficially resembles.

It removes the message from the compiled code entirely, so there is no run-time check, no string formatting and no branch.

The run-time cost of a filtered message is already small — UVM tests the threshold before evaluating the message, so a $sformatf inside a filtered uvm_info is never executed. What remains is the call and the comparison, which matters only in the hottest paths: a per-cycle monitor trace in a long regression can measurably slow a run.

The cost is that the message no longer exists. You cannot raise verbosity to see it, which defeats the purpose of having tiered logging at all — the message you most want during a failure is the one you compiled out to make the passing runs faster.

The reasonable compromise is to compile out only the highest tiers (UVM_FULL, UVM_DEBUG) in regression builds while keeping a debug build where nothing is removed, and to keep every structural message at UVM_LOW or UVM_NONE so it survives both. Measure before doing any of it: the cost is usually not where people assume.

The useful split is by what the message tells you, not by how interesting it seemed when written.

UVM_NONE — things that must survive any setting: test pass/fail markers, the configuration dump at end_of_elaboration, a heartbeat proving a long-running process is alive.

UVM_LOW — structural events, one per phase or per major milestone: components entering run_phase, objections raised and dropped, sequences starting and finishing, end-of-test summaries.

UVM_MEDIUM — per-transaction summaries at the granularity you would want in a routine failing run. Note that this sits exactly at the default threshold, so it is the first thing to vanish if anyone lowers it.

UVM_HIGH — per-transaction detail: full field dumps, protocol phase transitions, scoreboard match reporting.

UVM_FULL / UVM_DEBUG — per-cycle traces and internal state, useful for a single hand-run debug session and never in a regression.

The test to apply when choosing: at what point in a debug would I want this? A message you would want in the first five minutes belongs at LOW; one you would want only after narrowing to a single transaction belongs at HIGH.

Where This Is Specified

  • IEEE 1800.2-2020 (UVM) — reporting. The uvm_verbosity enumeration (UVM_NONE=0, UVM_LOW=100, UVM_MEDIUM=200, UVM_HIGH=300, UVM_FULL=400, UVM_DEBUG=500), and the rule that a report is issued when its verbosity is less than or equal to the configured threshold.
  • IEEE 1800.2-2020 — uvm_report_object. set_report_verbosity_level, set_report_verbosity_level_hier, get_report_verbosity_level, set_report_id_verbosity and set_report_id_verbosity_hier, and the precedence of an ID-specific setting over the component-wide threshold.
  • IEEE 1800.2-2020 — severity versus verbosity. uvm_severity (UVM_INFO, UVM_WARNING, UVM_ERROR, UVM_FATAL) determines counting and simulation control; verbosity gates visibility only. The `uvm_warning / `uvm_error / `uvm_fatal macros supply UVM_NONE as the verbosity, while the corresponding uvm_report_* functions accept a verbosity argument and are therefore filterable.
  • IEEE 1800.2-2020 — command-line processing. The +UVM_VERBOSITY plusarg and its component-scoped +uvm_set_verbosity form.
  • Accellera UVM User Guide — message tiering. The convention of reserving low verbosities for structural events and high verbosities for per-transaction and per-cycle detail.

§13 — Best Practices

RulePracticeWhy It Matters
BP-1Never hardcode set_report_verbosity_level() in a reusable component's build_phaseOverrides the plusarg; breaks regression log sizing for everyone using the VIP
BP-2Assign verbosity based on actual message importance: UVM_NONE for pass/fail only, UVM_HIGH for cycle-level signalsVerbosity inflation defeats the hierarchy — +UVM_VERBOSITY=UVM_NONE becomes meaningless
BP-3Place per-component verbosity overrides in the test's start_of_simulation_phase, not in the component itselfKeeps reusable components verbosity-neutral; test controls debug granularity without modifying VIP code
BP-4Use if (uvm_report_enabled(...)) guard before expensive $sformatf() in tight loopsEliminates string formatting overhead in filtered messages; critical for cycle-by-cycle monitors
BP-5Use set_report_id_verbosity("ID", UVM_DEBUG) to silence noisy IDs, UVM_NONE to force critical ones visiblePrecision targeting — silences one noisy ID without affecting other messages from the same component
BP-6Set regression Makefile target to +UVM_VERBOSITY=UVM_NONE, debug target to +UVM_HIGHNo code changes between regression and debug — only command-line argument changes
BP-7Save and restore verbosity when dynamically raising it in run_phaseA temporarily raised verbosity that isn't restored pollutes the rest of the simulation log
BP-8Use UVM_NONE verbosity only for the final test PASS/FAIL line — never for routine messagesAt UVM_NONE threshold, only UVM_NONE messages appear alongside errors/warnings — this is the CI-grade minimal log

§14 — Summary

LevelValueTypical Message TypeRegression Visibility
UVM_NONE0Test PASS/FAIL, critical simulation milestonesAlways — at every threshold setting
UVM_LOW100Phase transitions, sequence start/end, key state changesAt UVM_LOW threshold and above
UVM_MEDIUM200Transaction-level: addr, data, write flag — one per transactionDefault — shown unless threshold below MEDIUM
UVM_HIGH300Signal-level: bus signals, handshake cycles, interrupt statesOnly with +UVM_VERBOSITY=UVM_HIGH or above
UVM_FULL400Internal state dumps, arbitration state, every clock edgeOnly with +UVM_VERBOSITY=UVM_FULL or above
UVM_DEBUG500UVM framework internals — rarely needed by testbench engineersOnly with +UVM_VERBOSITY=UVM_DEBUG

Continue learning