SV-05
UVM Basics —
Universal Verification Methodology
UVM Component Hierarchy
What is UVM?
UVM (Universal Verification Methodology) is a standardized SystemVerilog class library (IEEE 1800.2) adopted across all major EDA tools and semiconductor companies. It provides a reusable framework so that verification components (drivers, monitors, scoreboards) written for one project can be plugged into another with minimal change.
UVM is built on three pillars:
- Component hierarchy — structured nesting of env/agent/driver/monitor
- Factory pattern — late binding of components for easy substitution
- TLM (Transaction Level Modeling) — standard ports for inter-component communication
1. UVM Phases
| Phase | Purpose | Notes |
|---|---|---|
| build_phase | Create all sub-components using factory | Top-down: parent builds before children |
| connect_phase | Wire TLM ports between components | Bottom-up: children connect before parents |
| start_of_simulation_phase | Print topology, configure | Rarely overridden |
| run_phase | Drive stimulus, collect responses (time-consuming) | The only phase that advances simulation time |
| extract_phase | Collect final results | Post-run |
| check_phase | Verify no pending expected transactions | After extract |
| report_phase | Print coverage, pass/fail summary | Last phase |
2. The `uvm_component_utils Macro
Every UVM component must register itself with the factory using `uvm_component_utils (for components) or `uvm_object_utils (for transaction objects like sequence items):
SystemVerilog — UVM Transaction (Sequence Item)
class apb_txn extends uvm_sequence_item; // Factory registration — required for create() and factory overrides `uvm_object_utils_begin(apb_txn) `uvm_field_int(addr, UVM_ALL_ON) `uvm_field_int(data, UVM_ALL_ON) `uvm_field_int(write, UVM_ALL_ON) `uvm_object_utils_end rand bit [11:0] addr; rand bit [31:0] data; rand bit write; function new(string name = "apb_txn"); super.new(name); endfunction constraint c_addr { addr[1:0] == 0; } // word-aligned endclass
3. Driver — Driving Transactions on the Interface
SystemVerilog — UVM Driver
class apb_driver extends uvm_driver #(apb_txn); `uvm_component_utils(apb_driver) virtual apb_if vif; // virtual interface to DUT function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); // Get virtual interface from config_db if (!uvm_config_db #(virtual apb_if)::get(this, "", "vif", vif)) `uvm_fatal("NO_VIF", "Virtual interface not set") endfunction task run_phase(uvm_phase phase); apb_txn txn; forever begin seq_item_port.get_next_item(txn); // block until sequence sends drive_apb(txn); // drive DUT interface seq_item_port.item_done(); // signal: done with this item end endtask task drive_apb(apb_txn txn); @(posedge vif.clk); vif.PSEL = 1; vif.PENABLE = 0; vif.PADDR = txn.addr; vif.PWRITE = txn.write; vif.PWDATA = txn.data; @(posedge vif.clk); vif.PENABLE = 1; @(posedge vif.clk iff vif.PREADY); vif.PSEL = 0; vif.PENABLE = 0; endtask endclass
4. Sequence and Sequencer
SystemVerilog — UVM Sequence
class apb_write_seq extends uvm_sequence #(apb_txn); `uvm_object_utils(apb_write_seq) int num_txns = 10; function new(string name = "apb_write_seq"); super.new(name); endfunction task body(); apb_txn txn; repeat (num_txns) begin // create() uses factory — allows override txn = apb_txn::type_id::create("txn"); start_item(txn); // request access to sequencer assert (txn.randomize() with { write == 1; }); finish_item(txn); // send to driver, wait for item_done end endtask endclass // In run_phase of uvm_test: apb_write_seq seq = apb_write_seq::type_id::create("seq"); seq.num_txns = 50; seq.start(env.agent.sequencer); // run on agent's sequencer
5. Monitor — Observing the Bus
SystemVerilog — UVM Monitor
class apb_monitor extends uvm_monitor; `uvm_component_utils(apb_monitor) virtual apb_if vif; // TLM port — broadcasts transactions to scoreboard/coverage uvm_analysis_port #(apb_txn) ap; function void build_phase(uvm_phase phase); super.build_phase(phase); ap = new("ap", this); if (!uvm_config_db #(virtual apb_if)::get(this, "", "vif", vif)) `uvm_fatal("NO_VIF", "Virtual interface not found") endfunction task run_phase(uvm_phase phase); forever begin apb_txn txn = apb_txn::type_id::create("mon_txn"); // Sample DUT signals on PENABLE + PREADY handshake @(posedge vif.clk iff (vif.PENABLE && vif.PREADY)); txn.addr = vif.PADDR; txn.data = vif.PWRITE ? vif.PWDATA : vif.PRDATA; txn.write = vif.PWRITE; ap.write(txn); // broadcast to all connected subscribers end endtask endclass
6. Complete Testbench Structure — Top Module
SystemVerilog — UVM top module
module tb_top; import uvm_pkg::*; `include "uvm_macros.svh" `include "apb_txn.sv" `include "apb_driver.sv" `include "apb_monitor.sv" `include "apb_agent.sv" `include "apb_env.sv" `include "apb_test.sv" // Clock and interface logic clk, rst_n; apb_if dut_if(.clk(clk), .rst_n(rst_n)); apb_slave dut(.apb(dut_if)); initial clk = 0; always #5 clk = ~clk; initial begin rst_n = 0; #20; rst_n = 1; end initial begin // Pass virtual interface through config_db to all UVM components uvm_config_db #(virtual apb_if)::set( null, "uvm_test_top.*", "vif", dut_if ); // Start the test — replace "apb_test" via +UVM_TESTNAME=xxx at runtime run_test("apb_test"); end endmodule
UVM Key Classes — Quick Reference
| Class | Extends | Role |
|---|---|---|
| uvm_sequence_item | uvm_object | Transaction — the data passed between components |
| uvm_sequence | uvm_sequence_base | Generate a stream of transactions (body task) |
| uvm_sequencer | uvm_sequencer_base | Arbitrate sequences and feed driver via TLM FIFO |
| uvm_driver | uvm_component | Pull items from sequencer, drive interface |
| uvm_monitor | uvm_component | Observe interface, broadcast via uvm_analysis_port |
| uvm_scoreboard | uvm_component | Compare expected vs actual via uvm_analysis_imp |
| uvm_agent | uvm_component | Container: driver + sequencer + monitor |
| uvm_env | uvm_component | Top-level container: agents + scoreboard + coverage |
| uvm_test | uvm_component | Configure env, start sequences, override factory |
Series complete! You've covered the full SystemVerilog verification stack — SVA, OOP, constrained-random, functional coverage, and UVM. Go to the SystemVerilog Hub to review all five topics, or explore the Interview Prep section for UVM/SV interview questions.