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:
VERBOSITY LEVELS — lower number = more critical = always shownUVM_NONE= 0UVM_LOW= 100UVM_MEDIUM= 200 ← defaultUVM_HIGH= 300UVM_FULL= 400UVM_DEBUG= 500increasing verbosity → more detail, more outputTHRESHOLD SET TO UVM_MEDIUM (200)SHOWN ✓ (verbosity ≤ 200)UVM_NONE (0), UVM_LOW (100), UVM_MEDIUM (200)FILTERED ✗ (verbosity > 200)UVM_HIGH (300), UVM_FULL (400), UVM_DEBUG (500)thresholdgate = 200Raising the threshold(e.g., to UVM_HIGH=300)allows UVM_HIGH messages through but still blocks UVM_FULL and UVM_DEBUG. 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.
| Constant | Value | Typical Use | Always Visible At Threshold |
|---|---|---|---|
UVM_NONE | 0 | Critical status — test PASS/FAIL, simulation milestones. Must always be visible. | Every threshold setting |
UVM_LOW | 100 | Important events — transaction starts/ends, phase transitions, key state changes. | UVM_LOW and above |
UVM_MEDIUM | 200 | Normal operation debug — transaction content, scoreboard checks, driver activity. Default threshold. | UVM_MEDIUM and above |
UVM_HIGH | 300 | Detailed signal-level debug — cycle-by-cycle bus activity, intermediate values. | UVM_HIGH and above |
UVM_FULL | 400 | Extremely verbose — internal state dumps, every clock edge logged. | UVM_FULL and above |
UVM_DEBUG | 500 | UVM 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.
## Standard regression run — minimal 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 run — detailed transaction-level output
vsim +UVM_VERBOSITY=UVM_HIGH work.tb_top
## Numeric also accepted — useful 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_topProgrammatic 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.
// ── 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:
// ── 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
| Priority | Mechanism | Scope |
|---|---|---|
| 1 (highest) | set_report_id_verbosity("ID", level) | Specific message ID in this component |
| 2 | set_report_verbosity_level(level) | All messages in this component |
| 3 | +UVM_VERBOSITY=LEVEL plusarg | All components globally |
| 4 (lowest) | Compiled-in default: UVM_MEDIUM | All 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.
// ── 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 flowsVerbosity 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 targets
## Default: regression mode — minimal 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 verbosity — use when a test is failing
debug:
vsim +UVM_TESTNAME=$(TEST) \
+UVM_VERBOSITY=UVM_HIGH \
work.tb_top
## Deep debug: full verbosity — last resort
trace:
vsim +UVM_TESTNAME=$(TEST) \
+UVM_VERBOSITY=UVM_FULL \
work.tb_top
## Usage: make regression TEST=smoke_test
## make debug TEST=failing_testLogging to File for Post-Processing
// 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 verbosityVerbosity 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
| Task | Method / Plusarg |
|---|---|
| Set global verbosity (runtime) | +UVM_VERBOSITY=UVM_HIGH (or numeric 300) |
| Set this component's verbosity | set_report_verbosity_level(UVM_HIGH) |
| Set this component + all children | set_report_verbosity_level_hier(UVM_HIGH) |
| Read current verbosity | get_report_verbosity_level() |
| Silence specific message ID | set_report_id_verbosity("ID", UVM_DEBUG) |
| Always show specific message ID | set_report_id_verbosity("ID", UVM_NONE) |
| Check enabled before expensive format | if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "ID")) |
| Set verbosity from outside component | env.agent.drv.set_report_verbosity_level(UVM_FULL) |
| Compile-time default | +define+UVM_DEFAULT_VERBOSITY=UVM_LOW |
// ── 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.
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 viewExample 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.
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
endclassExample 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.
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 failuresExample 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.
// ❌ 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 & Debugging
Bug 1 — Hardcoded UVM_FULL Left from a Debug Session
⚠️ Production Bug — 2GB Regression Log, CI Farm Storage Alarm
An engineer debugs a failing test by adding set_report_verbosity_level(UVM_FULL) in the driver's build_phase. The test passes. They commit the fix without removing the verbosity change. Every subsequent regression run generates 2GB logs regardless of +UVM_VERBOSITY=UVM_NONE on the command line. The CI farm's disk fills up after three days.
// ❌ 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
⚠️ Anti-Pattern Bug — 10,000 "Low Priority" Messages at UVM_NONE Threshold
An engineer assigns UVM_LOW to every ``uvm_infocall because "it seems important." When the regression team sets+UVM_VERBOSITY=UVM_NONE` to get clean logs, 10,000 messages still print — all tagged UVM_LOW, none of them actually low-priority. The verbosity hierarchy is meaningless when every message claims to be important.
// ❌ 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 debuggingBug 3 — set_report_id_verbosity on the Wrong Component
// ❌ 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§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: 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
Beginner Level
Intermediate Level
Senior / Architect Level
§13 — Best Practices
| Rule | Practice | Why It Matters |
|---|---|---|
| BP-1 | Never hardcode set_report_verbosity_level() in a reusable component's build_phase | Overrides the plusarg; breaks regression log sizing for everyone using the VIP |
| BP-2 | Assign verbosity based on actual message importance: UVM_NONE for pass/fail only, UVM_HIGH for cycle-level signals | Verbosity inflation defeats the hierarchy — +UVM_VERBOSITY=UVM_NONE becomes meaningless |
| BP-3 | Place per-component verbosity overrides in the test's start_of_simulation_phase, not in the component itself | Keeps reusable components verbosity-neutral; test controls debug granularity without modifying VIP code |
| BP-4 | Use if (uvm_report_enabled(...)) guard before expensive $sformatf() in tight loops | Eliminates string formatting overhead in filtered messages; critical for cycle-by-cycle monitors |
| BP-5 | Use set_report_id_verbosity("ID", UVM_DEBUG) to silence noisy IDs, UVM_NONE to force critical ones visible | Precision targeting — silences one noisy ID without affecting other messages from the same component |
| BP-6 | Set regression Makefile target to +UVM_VERBOSITY=UVM_NONE, debug target to +UVM_HIGH | No code changes between regression and debug — only command-line argument changes |
| BP-7 | Save and restore verbosity when dynamically raising it in run_phase | A temporarily raised verbosity that isn't restored pollutes the rest of the simulation log |
| BP-8 | Use UVM_NONE verbosity only for the final test PASS/FAIL line — never for routine messages | At UVM_NONE threshold, only UVM_NONE messages appear alongside errors/warnings — this is the CI-grade minimal log |
§14 — Summary
| Level | Value | Typical Message Type | Regression Visibility |
|---|---|---|---|
| UVM_NONE | 0 | Test PASS/FAIL, critical simulation milestones | Always — at every threshold setting |
| UVM_LOW | 100 | Phase transitions, sequence start/end, key state changes | At UVM_LOW threshold and above |
| UVM_MEDIUM | 200 | Transaction-level: addr, data, write flag — one per transaction | Default — shown unless threshold below MEDIUM |
| UVM_HIGH | 300 | Signal-level: bus signals, handshake cycles, interrupt states | Only with +UVM_VERBOSITY=UVM_HIGH or above |
| UVM_FULL | 400 | Internal state dumps, arbitration state, every clock edge | Only with +UVM_VERBOSITY=UVM_FULL or above |
| UVM_DEBUG | 500 | UVM framework internals — rarely needed by testbench engineers | Only with +UVM_VERBOSITY=UVM_DEBUG |