askill
uvm-verification

uvm-verificationSafety 90Repository

UVM testbench architecture and verification methodology for SystemVerilog. Use when creating UVM tests, agents, drivers, monitors, sequences, or scoreboards.

0 stars
1.2k downloads
Updated 1/23/2026

Package Files

Loading files...
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

ComponentNaming PatternExample
Test<module>_<type>_testaxiuart_basic_test
Environment<module>_envaxiuart_env
Agent<protocol>_agentuart_agent
Driver<protocol>_driveruart_driver
Monitor<protocol>_monitoruart_monitor
Sequencer<protocol>_sequenceruart_sequencer
Sequence<protocol>_<action>_sequenceuart_write_sequence
Transaction<protocol>_transactionuart_transaction
Scoreboard<module>_scoreboardaxiuart_scoreboard

File Naming

File TypePatternExample
Testbenchtb_<module>.svtb_axiuart_top.sv
UVM Test<test_name>.svaxiuart_basic_test.sv
UVM Package<module>_pkg.svaxiuart_uvm_pkg.sv

UVM Component Templates

Driver Template

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

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

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

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

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

// 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 transitions
  • UVM_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:

`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

// 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

// 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

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

// 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

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

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

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

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:

# 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

Summary

Key UVM principles:

  1. Use factory pattern for all component creation (type_id::create())
  2. Always check config DB retrieval with error handling
  3. Raise/drop objections in test run_phase
  4. Use uvm_info/uvm_error/uvm_fatal with appropriate verbosity
  5. Connect analysis ports in connect_phase
  6. Follow naming conventions: <protocol>_driver, <module>_env
  7. Never use placeholder DUTs - always use actual RTL from rtl/

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

78/100Analyzed 2/18/2026

High-quality UVM verification skill with comprehensive code templates for all major components (driver, monitor, agent, environment, test, sequence, scoreboard). Includes clear naming conventions, logging standards, config DB usage, and factory patterns. Slight penalty for AXIUART-specific naming limiting broader reusability, and content appears truncated at coverage section. Tags are mismatched (github-actions, database don't fit UVM). Strong actionability with structured, copy-pasteable templates."

90
85
65
70
80

Metadata

Licenseunknown
Version-
Updated1/23/2026
PublisherMameMame777

Tags

databasegithub-actionsobservabilitytesting