Agent skill
uvm-verification
UVM testbench architecture and verification methodology for SystemVerilog. Use when creating UVM tests, agents, drivers, monitors, sequences, or scoreboards.
Stars
163
Forks
31
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/uvm-verification
SKILL.md
UVM Verification Methodology
UVM testbench design patterns and best practices for the AXIUART_RV32I verification environment.
When to Use This Skill
- Creating UVM testbench components (tests, environments, agents)
- Implementing drivers, monitors, sequences, or scoreboards
- Debugging UVM configuration or communication issues
- Resolving UVM naming convention questions
- Setting up factory patterns or objection management
UVM Component Naming
Component Hierarchy
| Component | Naming Pattern | Example |
|---|---|---|
| Test | <module>_<type>_test |
axiuart_basic_test |
| Environment | <module>_env |
axiuart_env |
| Agent | <protocol>_agent |
uart_agent |
| Driver | <protocol>_driver |
uart_driver |
| Monitor | <protocol>_monitor |
uart_monitor |
| Sequencer | <protocol>_sequencer |
uart_sequencer |
| Sequence | <protocol>_<action>_sequence |
uart_write_sequence |
| Transaction | <protocol>_transaction |
uart_transaction |
| Scoreboard | <module>_scoreboard |
axiuart_scoreboard |
File Naming
| File Type | Pattern | Example |
|---|---|---|
| Testbench | tb_<module>.sv |
tb_axiuart_top.sv |
| UVM Test | <test_name>.sv |
axiuart_basic_test.sv |
| UVM Package | <module>_pkg.sv |
axiuart_uvm_pkg.sv |
UVM Component Templates
Driver Template
systemverilog
class uart_driver extends uvm_driver #(uart_transaction);
`uvm_component_utils(uart_driver)
virtual uart_if vif;
function new(string name = "uart_driver", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual uart_if)::get(this, "", "vif", vif)) begin
`uvm_fatal(get_type_name(), "Virtual interface not found in config DB")
endif
endfunction
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
drive_transaction(req);
seq_item_port.item_done();
end
endtask
virtual task drive_transaction(uart_transaction trans);
// Implementation
`uvm_info(get_type_name(),
$sformatf("Driving transaction: %s", trans.convert2string()),
UVM_HIGH)
endtask
endclass
Monitor Template
systemverilog
class uart_monitor extends uvm_monitor;
`uvm_component_utils(uart_monitor)
virtual uart_if vif;
uvm_analysis_port #(uart_transaction) analysis_port;
function new(string name = "uart_monitor", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual uart_if)::get(this, "", "vif", vif)) begin
`uvm_fatal(get_type_name(), "Virtual interface not found in config DB")
endif
analysis_port = new("analysis_port", this);
endfunction
virtual task run_phase(uvm_phase phase);
uart_transaction trans;
forever begin
trans = uart_transaction::type_id::create("trans");
collect_transaction(trans);
`uvm_info(get_type_name(),
$sformatf("Collected: %s", trans.convert2string()),
UVM_HIGH)
analysis_port.write(trans);
end
endtask
virtual task collect_transaction(uart_transaction trans);
// Implementation
endtask
endclass
Agent Template
systemverilog
class uart_agent extends uvm_agent;
`uvm_component_utils(uart_agent)
uart_driver driver;
uart_monitor monitor;
uart_sequencer sequencer;
function new(string name = "uart_agent", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
monitor = uart_monitor::type_id::create("monitor", this);
if (get_is_active() == UVM_ACTIVE) begin
driver = uart_driver::type_id::create("driver", this);
sequencer = uart_sequencer::type_id::create("sequencer", this);
end
endfunction
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (get_is_active() == UVM_ACTIVE) begin
driver.seq_item_port.connect(sequencer.seq_item_export);
end
endfunction
endclass
Environment Template
systemverilog
class axiuart_env extends uvm_env;
`uvm_component_utils(axiuart_env)
uart_agent uart_agt;
axi_agent axi_agt;
axiuart_scoreboard scoreboard;
function new(string name = "axiuart_env", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
uart_agt = uart_agent::type_id::create("uart_agt", this);
axi_agt = axi_agent::type_id::create("axi_agt", this);
scoreboard = axiuart_scoreboard::type_id::create("scoreboard", this);
endfunction
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
uart_agt.monitor.analysis_port.connect(scoreboard.uart_export);
axi_agt.monitor.analysis_port.connect(scoreboard.axi_export);
endfunction
endclass
Test Template with Objections
systemverilog
class axiuart_basic_test extends uvm_test;
`uvm_component_utils(axiuart_basic_test)
axiuart_env env;
function new(string name = "axiuart_basic_test", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = axiuart_env::type_id::create("env", this);
endfunction
virtual task run_phase(uvm_phase phase);
uart_write_sequence seq;
phase.raise_objection(this, "Test starting");
`uvm_info(get_type_name(), "========== Test Started ==========", UVM_LOW)
// Test body
seq = uart_write_sequence::type_id::create("seq");
seq.start(env.uart_agt.sequencer);
#1000ns; // Wait for processing
`uvm_info(get_type_name(), "========== Test Completed ==========", UVM_LOW)
phase.drop_objection(this, "Test completed");
endtask
endclass
UVM Logging Standards
Verbosity Levels
systemverilog
// Informational (UVM_MEDIUM or UVM_HIGH)
`uvm_info(get_type_name(),
$sformatf("Transaction: addr=0x%08h, data=0x%08h", trans.addr, trans.data),
UVM_MEDIUM)
// Error (always displayed)
`uvm_error(get_type_name(),
$sformatf("CRC mismatch: expected=0x%04h, got=0x%04h", exp_crc, act_crc))
// Fatal error (stops simulation)
`uvm_fatal(get_type_name(), "Watchdog timeout - DUT not responding")
Verbosity guidelines:
UVM_LOW: Test start/end, major phase transitionsUVM_MEDIUM: Transaction-level events (default for regression)UVM_HIGH: Detailed signal-level activity (debug only)UVM_FULL: Exhaustive debug (rarely used)
Message Formatting
Use $sformatf for structured messages:
systemverilog
`uvm_info(get_type_name(),
$sformatf("State transition: %s -> %s (cycle=%0d)",
state_to_string(prev_state),
state_to_string(new_state),
cycle_count),
UVM_MEDIUM)
Configuration Database
Setting Values
systemverilog
// In testbench top
initial begin
uvm_config_db#(virtual uart_if)::set(null, "uvm_test_top.env.uart_agt*", "vif", uart_if_inst);
uvm_config_db#(int)::set(null, "uvm_test_top.env", "num_transactions", 100);
end
Getting Values
systemverilog
// In component build_phase
if (!uvm_config_db#(virtual uart_if)::get(this, "", "vif", vif)) begin
`uvm_fatal(get_type_name(), "Virtual interface not found in config DB")
endif
// With default value
if (!uvm_config_db#(int)::get(this, "", "timeout", timeout)) begin
timeout = 1000; // Default
`uvm_info(get_type_name(), $sformatf("Using default timeout: %0d", timeout), UVM_MEDIUM)
end
Factory Pattern
Registration
systemverilog
class uart_transaction extends uvm_sequence_item;
rand logic [7:0] data;
rand logic parity;
`uvm_object_utils_begin(uart_transaction)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_int(parity, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "uart_transaction");
super.new(name);
endfunction
endclass
Creating Objects
systemverilog
// Use factory instead of direct new()
uart_transaction trans = uart_transaction::type_id::create("trans");
// Enables runtime override
set_type_override_by_type(
uart_transaction::get_type(),
extended_uart_transaction::get_type()
);
Sequence Patterns
Basic Sequence
systemverilog
class uart_write_sequence extends uvm_sequence #(uart_transaction);
`uvm_object_utils(uart_write_sequence)
rand int num_transactions;
constraint c_num_trans {
num_transactions inside {[10:50]};
}
function new(string name = "uart_write_sequence");
super.new(name);
endfunction
virtual task body();
`uvm_info(get_type_name(),
$sformatf("Starting sequence with %0d transactions", num_transactions),
UVM_MEDIUM)
repeat (num_transactions) begin
req = uart_transaction::type_id::create("req");
start_item(req);
if (!req.randomize()) begin
`uvm_fatal(get_type_name(), "Randomization failed")
endif
finish_item(req);
end
endtask
endclass
Scoreboard Pattern
systemverilog
class axiuart_scoreboard extends uvm_scoreboard;
`uvm_component_utils(axiuart_scoreboard)
uvm_analysis_imp #(uart_transaction, axiuart_scoreboard) uart_export;
uvm_analysis_imp #(axi_transaction, axiuart_scoreboard) axi_export;
uart_transaction uart_queue[$];
int pass_count, fail_count;
function new(string name = "axiuart_scoreboard", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
uart_export = new("uart_export", this);
axi_export = new("axi_export", this);
endfunction
virtual function void write(uart_transaction trans);
uart_queue.push_back(trans);
endfunction
virtual function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info(get_type_name(),
$sformatf("Scoreboard results: PASS=%0d, FAIL=%0d", pass_count, fail_count),
UVM_LOW)
endfunction
endclass
Verification Requirements
DUT Integration
- Use actual RTL modules from rtl/ as DUTs; mocks are prohibited
- Never instantiate simplified or placeholder DUT models
- Verify module hierarchy matches actual synthesis structure
Coverage
systemverilog
class uart_transaction extends uvm_sequence_item;
rand logic [7:0] data;
rand logic parity;
covergroup cg_uart;
cp_data: coverpoint data {
bins low = {[0:63]};
bins mid = {[64:191]};
bins high = {[192:255]};
}
cp_parity: coverpoint parity;
cross cp_data, cp_parity;
endgroup
function new(string name = "uart_transaction");
super.new(name);
cg_uart = new();
endfunction
endclass
Project-Specific Patterns
Test File Structure
All UVM tests located in sim/tests/:
sim/tests/
├── axiuart_basic_test.sv
├── axiuart_stress_test.sv
└── axiuart_error_injection_test.sv
UVM Architecture
sim/uvm/
├── env/ # Environments
├── agents/ # Protocol agents
├── sequences/ # Stimulus sequences
├── tests/ # Top-level tests (also in sim/tests/)
└── tb/ # Testbench top modules
Package Organization
systemverilog
package axiuart_uvm_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
// Transactions
`include "uart_transaction.sv"
`include "axi_transaction.sv"
// Sequences
`include "uart_write_sequence.sv"
// Components
`include "uart_driver.sv"
`include "uart_monitor.sv"
`include "uart_agent.sv"
// Environment
`include "axiuart_env.sv"
// Tests
`include "axiuart_basic_test.sv"
endpackage
Compilation and Execution
Standard Test Workflow
See the mcp-workflow skill for detailed MCP command sequences. Brief overview:
bash
# 1. Compile test
python mcp_server/mcp_client.py --workspace . --tool run_uvm_simulation \
--test-name axiuart_basic_test --mode compile --verbosity UVM_LOW
# 2. Run with waves
python mcp_server/mcp_client.py --workspace . --tool run_uvm_simulation \
--test-name axiuart_basic_test --mode run --verbosity UVM_MEDIUM --waves
Additional Resources
- UVM architecture: sim/uvm/README.md
- MCP workflow: Reference
mcp-workflowskill for command sequences - Accellera UVM examples: reference/Accellera/uvm/distrib/examples/
Summary
Key UVM principles:
- Use factory pattern for all component creation (
type_id::create()) - Always check config DB retrieval with error handling
- Raise/drop objections in test
run_phase - Use
uvm_info/uvm_error/uvm_fatalwith appropriate verbosity - Connect analysis ports in
connect_phase - Follow naming conventions:
<protocol>_driver,<module>_env - Never use placeholder DUTs - always use actual RTL from rtl/
Didn't find tool you were looking for?