Quick Reference Guide with Key Points and Code Snippets
Your one-stop UVM reference for rapid development
Table of Contents
- UVM Class Hierarchy
- UVM Phases
- Transaction and Sequence
- Driver
- Monitor
- Sequencer
- Agent
- Scoreboard
- Environment
- Test
- Configuration
- Factory
- TLM Ports
- Macros
- Quick Patterns
1. UVM Class Hierarchy
Key Concepts
- uvm_object: Data items (transactions, configs)
- uvm_component: Structural hierarchy (driver, monitor, etc.)
- uvm_sequence: Stimulus generation
Quick Reference
uvm_void
└── uvm_object
├── uvm_transaction
│ └── uvm_sequence_item
│ └── YOUR_TRANSACTION
├── uvm_sequence
│ └── YOUR_SEQUENCE
├── uvm_component
│ ├── uvm_driver
│ │ └── YOUR_DRIVER
│ ├── uvm_monitor
│ │ └── YOUR_MONITOR
│ ├── uvm_sequencer
│ │ └── YOUR_SEQUENCER
│ ├── uvm_agent
│ │ └── YOUR_AGENT
│ ├── uvm_scoreboard
│ │ └── YOUR_SCOREBOARD
│ ├── uvm_env
│ │ └── YOUR_ENV
│ └── uvm_test
│ └── YOUR_TEST
└── uvm_config (user-defined)
2. UVM Phases
Phase Execution Order
BUILD PHASES (Function, Bottom-Up):
├── build_phase() - Create components
├── connect_phase() - Connect TLM ports
├── end_of_elaboration() - Topology checks
└── start_of_simulation() - Display info
RUN PHASE (Task, Parallel):
└── run_phase() - Main execution
OR fine-grained:
├── pre_reset_phase()
├── reset_phase()
├── post_reset_phase()
├── pre_configure_phase()
├── configure_phase()
├── post_configure_phase()
├── pre_main_phase()
├── main_phase()
├── post_main_phase()
├── pre_shutdown_phase()
├── shutdown_phase()
└── post_shutdown_phase()
POST-RUN PHASES (Function, Bottom-Up):
├── extract_phase() - Extract coverage
├── check_phase() - Check results
├── report_phase() - Print reports
└── final_phase() - Cleanup (Top-Down)
Phase Code Snippets
// Build phase (create components)
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = apb_agent::type_id::create("agent", this);
endfunction
// Connect phase (connect ports)
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
driver.seq_item_port.connect(seqr.seq_item_export);
endfunction
// Run phase (with objections)
task run_phase(uvm_phase phase);
phase.raise_objection(this);
// Do work
repeat(100) @(posedge vif.clk);
phase.drop_objection(this);
endtask
// Report phase
function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info("REPORT", $sformatf("Test %s",
(errors==0)?"PASSED":"FAILED"), UVM_LOW)
endfunction
Key Points:
- Call
super.xxx_phase()FIRST in build/connect (bottom-up) - Call
super.xxx_phase()LAST in final_phase (top-down) - Use objections in run_phase to control when it ends
- Match every raise_objection() with drop_objection()
3. Transaction and Sequence
Transaction Template
class apb_transaction extends uvm_sequence_item;
// Data members
rand bit [31:0] addr;
rand bit [31:0] wdata;
rand bit write;
bit [31:0] rdata;
// Constraints
constraint addr_c {
addr inside {[32'h0000:32'hFFFF]};
}
// Factory registration
`uvm_object_utils_begin(apb_transaction)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(wdata, UVM_ALL_ON)
`uvm_field_int(write, UVM_ALL_ON)
`uvm_field_int(rdata, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "apb_transaction");
super.new(name);
endfunction
endclass
Sequence Template
class apb_sequence extends uvm_sequence#(apb_transaction);
`uvm_object_utils(apb_sequence)
function new(string name = "apb_sequence");
super.new(name);
endfunction
task body();
apb_transaction req;
repeat(10) begin
req = apb_transaction::type_id::create("req");
start_item(req); // Get grant [BLOCKS]
assert(req.randomize());
finish_item(req); // Send txn [BLOCKS]
end
endtask
// Optional: Objection handling
task pre_body();
if (starting_phase != null)
starting_phase.raise_objection(this);
endtask
task post_body();
if (starting_phase != null)
starting_phase.drop_objection(this);
endtask
endclass
Key Points:
start_item(req)– Request grant, BLOCKS until grantedrandomize()– Between start_item and finish_itemfinish_item(req)– Send transaction, BLOCKS until done- Use
pre_body()/post_body()for automatic objection handling
4. Driver
Driver Template
class apb_driver extends uvm_driver#(apb_transaction);
`uvm_component_utils(apb_driver)
virtual apb_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual apb_if)::get(this, "", "vif", vif))
`uvm_fatal("DRIVER", "No virtual interface!")
endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req); // [BLOCKS]
drive_transaction(req);
seq_item_port.item_done(); // Signal complete
end
endtask
task drive_transaction(apb_transaction txn);
@(posedge vif.pclk);
vif.paddr <= txn.addr;
vif.pwdata <= txn.wdata;
vif.pwrite <= txn.write;
vif.psel <= 1;
vif.penable <= 0;
@(posedge vif.pclk);
vif.penable <= 1;
wait(vif.pready);
if (!txn.write)
txn.rdata = vif.prdata;
@(posedge vif.pclk);
vif.psel <= 0;
vif.penable <= 0;
endtask
endclass
Key Points:
- Get VIF from config_db in build_phase
- Use
get_next_item(req)– BLOCKS until transaction available - Call
item_done()after driving - Alternative:
try_next_item(req)– non-blocking, returns null if no txn
5. Monitor
Monitor Template
class apb_monitor extends uvm_monitor;
`uvm_component_utils(apb_monitor)
virtual apb_if vif;
uvm_analysis_port#(apb_transaction) ap;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual apb_if)::get(this, "", "vif", vif))
`uvm_fatal("MON", "No VIF!")
ap = new("ap", this);
endfunction
task run_phase(uvm_phase phase);
forever begin
collect_transaction();
end
endtask
task collect_transaction();
apb_transaction txn;
@(posedge vif.pclk);
if (vif.psel && !vif.penable) begin
txn = apb_transaction::type_id::create("txn");
// Capture setup phase
txn.addr = vif.paddr;
txn.write = vif.pwrite;
if (txn.write)
txn.wdata = vif.pwdata;
// Wait for access phase
@(posedge vif.pclk);
wait(vif.pready);
if (!txn.write)
txn.rdata = vif.prdata;
// Broadcast to subscribers
ap.write(txn);
end
endtask
endclass
Key Points:
- Create
analysis_portin build_phase - Observe VIF, reconstruct transaction
- Broadcast via
ap.write(txn)– non-blocking - Don’t modify DUT, only observe
6. Sequencer
Sequencer Template
class apb_sequencer extends uvm_sequencer#(apb_transaction);
`uvm_component_utils(apb_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
// Usually no custom code needed!
// Handles:
// - Arbitration between sequences
// - Transaction queuing
// - Grant/done signaling
Key Points:
- Usually just inherit from
uvm_sequencer#(TXN_TYPE) - No custom code needed in most cases
- Handles arbitration automatically
- Provides
seq_item_exportfor driver connection
7. Agent
Agent Template
class apb_agent extends uvm_agent;
`uvm_component_utils(apb_agent)
apb_sequencer seqr;
apb_driver drv;
apb_monitor mon;
apb_config cfg;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Get configuration
if (!uvm_config_db#(apb_config)::get(this, "", "cfg", cfg))
`uvm_fatal("AGENT", "No config!")
// Always create monitor
mon = apb_monitor::type_id::create("mon", this);
// Create active components if needed
if (cfg.is_active == UVM_ACTIVE) begin
seqr = apb_sequencer::type_id::create("seqr", this);
drv = apb_driver::type_id::create("drv", this);
end
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (cfg.is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(seqr.seq_item_export);
end
endfunction
endclass
Key Points:
- Contains sequencer, driver, monitor
- Check
is_activebefore creating driver/sequencer - Monitor always present (passive mode = monitor only)
- Connect driver to sequencer in connect_phase
8. Scoreboard
Scoreboard Template
class apb_scoreboard extends uvm_scoreboard;
`uvm_component_utils(apb_scoreboard)
uvm_analysis_imp#(apb_transaction, apb_scoreboard) analysis_imp;
int match_count = 0;
int mismatch_count = 0;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
analysis_imp = new("analysis_imp", this);
endfunction
// Called by monitor's analysis_port
virtual function void write(apb_transaction txn);
apb_transaction expected;
// Get expected from reference model
expected = predict(txn);
// Compare
if (txn.compare(expected)) begin
match_count++;
`uvm_info("SCBD", "MATCH", UVM_HIGH)
end else begin
mismatch_count++;
`uvm_error("SCBD", $sformatf("MISMATCH: exp=%h act=%h",
expected.data, txn.data))
end
endfunction
function apb_transaction predict(apb_transaction txn);
// Reference model logic
apb_transaction exp = new();
// ... prediction logic
return exp;
endfunction
function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info("SCBD_REPORT",
$sformatf("Matches: %0d, Mismatches: %0d",
match_count, mismatch_count), UVM_LOW)
endfunction
endclass
Key Points:
- Use
uvm_analysis_impto receive transactions - Implement
write()function (called by monitor) - Compare actual vs expected (reference model)
- Report statistics in report_phase
9. Environment
Environment Template
class apb_env extends uvm_env;
`uvm_component_utils(apb_env)
apb_agent agent;
apb_scoreboard scbd;
apb_coverage cov;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = apb_agent::type_id::create("agent", this);
scbd = apb_scoreboard::type_id::create("scbd", this);
cov = apb_coverage::type_id::create("cov", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// Connect monitor to scoreboard
agent.mon.ap.connect(scbd.analysis_imp);
// Connect monitor to coverage
agent.mon.ap.connect(cov.analysis_export);
endfunction
endclass
Key Points:
- Contains agents, scoreboard, coverage
- Create all in build_phase
- Connect analysis ports in connect_phase
- One environment per DUT or protocol
10. Test
Test Template
class apb_test extends uvm_test;
`uvm_component_utils(apb_test)
apb_env env;
apb_config cfg;
virtual apb_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Get VIF from top module
if (!uvm_config_db#(virtual apb_if)::get(this, "", "vif", vif))
`uvm_fatal("TEST", "No VIF!")
// Create and configure
cfg = apb_config::type_id::create("cfg");
cfg.vif = vif;
cfg.is_active = UVM_ACTIVE;
// Set config for agent
uvm_config_db#(apb_config)::set(this, "env.agent", "cfg", cfg);
// Create environment
env = apb_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
apb_sequence seq;
phase.raise_objection(this);
seq = apb_sequence::type_id::create("seq");
seq.start(env.agent.seqr);
#100ns; // Drain time
phase.drop_objection(this);
endtask
endclass
Key Points:
- Top-level component in UVM hierarchy
- Get VIF from config_db
- Create and distribute configuration
- Set factory overrides here
- Start sequences in run_phase
- Manage objections
11. Configuration
Config Object Template
class apb_config extends uvm_object;
`uvm_object_utils(apb_config)
virtual apb_if vif;
uvm_active_passive_enum is_active = UVM_ACTIVE;
int num_trans = 100;
bit checks_enable = 1;
bit coverage_enable = 1;
function new(string name = "apb_config");
super.new(name);
endfunction
endclass
Config DB Usage
// SET configuration (in test/top)
uvm_config_db#(TYPE)::set(
this, // Context (uvm_component)
"path.to.comp", // Instance path (use wildcards)
"field_name", // Field identifier
value); // Value to set
// Example
uvm_config_db#(apb_config)::set(this, "env.agent*", "cfg", cfg);
uvm_config_db#(virtual apb_if)::set(null, "uvm_test_top", "vif", vif);
// GET configuration (in components)
if (!uvm_config_db#(TYPE)::get(
this, // Context
"", // Instance ("" = this level)
"field_name", // Field identifier
value)) // Variable to receive value
`uvm_fatal("TAG", "Config not found!")
// Example
if (!uvm_config_db#(apb_config)::get(this, "", "cfg", cfg))
`uvm_fatal("AGENT", "No config!")
Key Points:
- Set config BEFORE creating components
- Most specific path wins (wildcards:
*,*.agent*) - Always check get() return value
- VIF must be set in top module before run_test()
12. Factory
Factory Registration
// Register object
class apb_transaction extends uvm_sequence_item;
`uvm_object_utils(apb_transaction)
// ...
endclass
// Register component
class apb_driver extends uvm_driver#(apb_transaction);
`uvm_component_utils(apb_driver)
// ...
endclass
Factory Creation
// Create via factory (enables overrides)
comp = apb_driver::type_id::create("drv", this); // Component
obj = apb_transaction::type_id::create("req"); // Object
// DON'T use new() directly (bypasses factory)
// comp = new("drv", this); // BAD - can't override!
Factory Override
// Type override (affects ALL instances)
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// By type
apb_driver::type_id::set_type_override(
enhanced_apb_driver::get_type());
// By name
set_type_override_by_name("apb_driver", "enhanced_apb_driver");
// Create components (will use override)
env = apb_env::type_id::create("env", this);
endfunction
// Instance override (specific instance only)
set_inst_override_by_type(
"env.master_agent.drv", // Instance path
apb_driver::get_type(), // Original type
debug_apb_driver::get_type()); // Override type
// Debug factory
factory.print(); // Print all overrides
Key Points:
- Always use
type_id::create(), nevernew() - Set overrides BEFORE creating components
- Type override: all instances replaced
- Instance override: specific path only
- Instance override takes precedence over type override
13. TLM Ports
TLM Port Types
// Port Types:
// - uvm_analysis_port (1→N broadcast)
// - uvm_seq_item_pull_port (get/put, blocking)
// - uvm_blocking_put_port (blocking put)
// - uvm_blocking_get_port (blocking get)
// Analysis Port (Monitor → Scoreboard/Coverage)
class monitor;
uvm_analysis_port#(txn_t) ap;
function void build_phase(uvm_phase phase);
ap = new("ap", this);
endfunction
task run_phase(uvm_phase phase);
ap.write(txn); // Broadcast to all connected
endtask
endclass
class scoreboard;
uvm_analysis_imp#(txn_t, scoreboard) analysis_imp;
function void build_phase(uvm_phase phase);
analysis_imp = new("analysis_imp", this);
endfunction
function void write(txn_t txn);
// Called when monitor does ap.write(txn)
endfunction
endclass
// Connection
monitor.ap.connect(scoreboard.analysis_imp);
// Multiple subscribers
uvm_analysis_imp_decl(_scbd)
uvm_analysis_imp_decl(_cov)
class scoreboard;
uvm_analysis_imp_scbd#(txn_t, scoreboard) scbd_imp;
uvm_analysis_imp_cov#(txn_t, scoreboard) cov_imp;
function void write_scbd(txn_t txn);
// From scoreboard connection
endfunction
function void write_cov(txn_t txn);
// From coverage connection
endfunction
endclass
Key Points:
- analysis_port: 1-to-many, non-blocking broadcast
- seq_item_port: 1-to-1, blocking get/put
- Port in producer, Export/Imp in consumer
- Connect in connect_phase
14. UVM Macros
Essential Macros
//=============================================================================
// Registration Macros
//=============================================================================
// Object registration (minimal)
`uvm_object_utils(apb_transaction)
// Object with field automation
`uvm_object_utils_begin(apb_transaction)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end
// Component registration
`uvm_component_utils(apb_driver)
//=============================================================================
// Messaging Macros
//=============================================================================
`uvm_info(ID, MSG, VERBOSITY)
`uvm_warning(ID, MSG)
`uvm_error(ID, MSG)
`uvm_fatal(ID, MSG)
// Examples
`uvm_info("DRIVER", "Driving transaction", UVM_HIGH)
`uvm_error("SCBD", $sformatf("Mismatch: exp=%h act=%h", exp, act))
`uvm_fatal("BUILD", "Component creation failed!")
// Verbosity levels: UVM_NONE, UVM_LOW, UVM_MEDIUM, UVM_HIGH, UVM_FULL, UVM_DEBUG
//=============================================================================
// Sequence Macros
//=============================================================================
// Simple sequence item generation
`uvm_do(req)
// Equivalent to:
// start_item(req);
// assert(req.randomize());
// finish_item(req);
// With inline constraints
`uvm_do_with(req, {addr < 100; write == 1;})
// Create and do in one step
`uvm_create(req)
// Creates: req = type::create("req")
// Send on specific sequencer
`uvm_do_on(req, seqr)
// Priority sequencing
`uvm_do_pri(req, priority)
//=============================================================================
// Field Macros
//=============================================================================
// Field automation flags
UVM_ALL_ON // All operations
UVM_COPY // Enable copy
UVM_COMPARE // Enable compare
UVM_PRINT // Enable print
UVM_PACK // Enable pack/unpack
UVM_DEFAULT // Default set
UVM_NOCOMPARE // Disable compare
UVM_NOPRINT // Disable print
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_object(sub_obj, UVM_ALL_ON)
`uvm_field_array_int(array, UVM_ALL_ON)
`uvm_field_queue_int(queue, UVM_ALL_ON)
`uvm_field_enum(state_t, state, UVM_ALL_ON)
`uvm_field_string(name, UVM_ALL_ON)
Key Macro Patterns:
// Typical transaction
class my_txn extends uvm_sequence_item;
rand bit [7:0] addr;
rand bit [31:0] data;
`uvm_object_utils_begin(my_txn)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "my_txn");
super.new(name);
endfunction
endclass
// Typical component
class my_comp extends uvm_component;
`uvm_component_utils(my_comp)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Build code
endfunction
endclass
15. Quick Patterns
15.1 Complete Minimal UVM Testbench
//=============================================================================
// Transaction
//=============================================================================
class txn extends uvm_sequence_item;
rand bit [7:0] addr;
rand bit [31:0] data;
`uvm_object_utils_begin(txn)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "txn");
super.new(name);
endfunction
endclass
//=============================================================================
// Sequence
//=============================================================================
class seq extends uvm_sequence#(txn);
`uvm_object_utils(seq)
function new(string name = "seq");
super.new(name);
endfunction
task body();
repeat(10) `uvm_do(req)
endtask
endclass
//=============================================================================
// Driver
//=============================================================================
class drv extends uvm_driver#(txn);
`uvm_component_utils(drv)
virtual dut_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual dut_if)::get(this, "", "vif", vif))
`uvm_fatal("DRV", "No VIF!")
endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
@(posedge vif.clk);
vif.addr <= req.addr;
vif.data <= req.data;
seq_item_port.item_done();
end
endtask
endclass
//=============================================================================
// Monitor
//=============================================================================
class mon extends uvm_monitor;
`uvm_component_utils(mon)
virtual dut_if vif;
uvm_analysis_port#(txn) ap;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual dut_if)::get(this, "", "vif", vif))
`uvm_fatal("MON", "No VIF!")
ap = new("ap", this);
endfunction
task run_phase(uvm_phase phase);
forever begin
txn t = txn::type_id::create("t");
@(posedge vif.clk);
t.addr = vif.addr;
t.data = vif.data;
ap.write(t);
end
endtask
endclass
//=============================================================================
// Agent
//=============================================================================
class agt extends uvm_agent;
`uvm_component_utils(agt)
drv d;
mon m;
uvm_sequencer#(txn) seqr;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
d = drv::type_id::create("d", this);
m = mon::type_id::create("m", this);
seqr = uvm_sequencer#(txn)::type_id::create("seqr", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
d.seq_item_port.connect(seqr.seq_item_export);
endfunction
endclass
//=============================================================================
// Environment
//=============================================================================
class env extends uvm_env;
`uvm_component_utils(env)
agt agent;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = agt::type_id::create("agent", this);
endfunction
endclass
//=============================================================================
// Test
//=============================================================================
class test extends uvm_test;
`uvm_component_utils(test)
env e;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
e = env::type_id::create("e", this);
endfunction
task run_phase(uvm_phase phase);
seq s = seq::type_id::create("s");
phase.raise_objection(this);
s.start(e.agent.seqr);
phase.drop_objection(this);
endtask
endclass
//=============================================================================
// Top Module
//=============================================================================
module top;
logic clk;
dut_if dut_if_inst(clk);
dut dut_inst(dut_if_inst);
initial begin
uvm_config_db#(virtual dut_if)::set(null, "uvm_test_top", "vif", dut_if_inst);
run_test("test");
end
initial begin
clk = 0;
forever #5ns clk = ~clk;
end
endmodule
15.2 Sequence-Driver-Sequencer Handshake
// SEQUENCE side:
task body();
req = txn::type_id::create("req");
start_item(req); // ① Request grant [BLOCKS]
assert(req.randomize()); // ② Randomize after grant
finish_item(req); // ③ Send txn [BLOCKS until done]
endtask
// SEQUENCER side (automatic):
// - Receives request from sequence
// - Arbitrates if multiple sequences
// - Grants access to sequence
// - Queues transaction for driver
// - Signals driver
// - Waits for done from driver
// - Signals sequence completion
// DRIVER side:
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req); // ④ Get txn [BLOCKS]
drive_txn(req); // ⑤ Drive DUT
seq_item_port.item_done(); // ⑥ Signal done
end
endtask
15.3 Top Module Pattern
module top;
// Clock
logic clk = 0;
always #5ns clk = ~clk;
// Interface
apb_if apb_if_inst(clk);
// DUT
apb_slave dut(
.pclk(apb_if_inst.pclk),
.preset_n(apb_if_inst.preset_n),
.paddr(apb_if_inst.paddr),
.psel(apb_if_inst.psel),
.penable(apb_if_inst.penable),
.pwrite(apb_if_inst.pwrite),
.pwdata(apb_if_inst.pwdata),
.prdata(apb_if_inst.prdata),
.pready(apb_if_inst.pready)
);
// UVM
initial begin
// Set VIF in config_db
uvm_config_db#(virtual apb_if)::set(
null,
"uvm_test_top",
"vif",
apb_if_inst);
// Run test
run_test("apb_test");
end
endmodule
Quick Reference Tables
UVM Component Checklist
| Component | Extends | Key Methods | TLM Ports |
|---|---|---|---|
| Transaction | uvm_sequence_item | randomize() | – |
| Sequence | uvm_sequence | body(), pre_body(), post_body() | – |
| Driver | uvm_driver | run_phase(), drive_txn() | seq_item_port |
| Monitor | uvm_monitor | run_phase(), collect() | analysis_port |
| Sequencer | uvm_sequencer | (none usually) | seq_item_export |
| Agent | uvm_agent | build(), connect() | – |
| Scoreboard | uvm_scoreboard | write(), check() | analysis_imp |
| Coverage | uvm_subscriber | write() | analysis_export |
| Environment | uvm_env | build(), connect() | – |
| Test | uvm_test | build(), run_phase() | – |
Phase Order Quick Ref
| Phase | Type | Direction | Purpose |
|---|---|---|---|
| build | Function | Bottom-up | Create components |
| connect | Function | Bottom-up | Connect ports |
| end_of_elaboration | Function | Bottom-up | Checks |
| start_of_simulation | Function | Bottom-up | Display |
| run | Task | Parallel | Main test |
| extract | Function | Bottom-up | Get stats |
| check | Function | Bottom-up | Verify |
| report | Function | Bottom-up | Print report |
| final | Function | Top-down | Cleanup |
Common Code Patterns
// Pattern 1: Get from config_db
if (!uvm_config_db#(TYPE)::get(this, "", "name", var))
`uvm_fatal("TAG", "Not found!")
// Pattern 2: Set to config_db
uvm_config_db#(TYPE)::set(this, "path", "name", value);
// Pattern 3: Create via factory
comp = TYPE::type_id::create("name", this);
// Pattern 4: Sequence execution
seq = SEQ_TYPE::type_id::create("seq");
seq.start(seqr);
// Pattern 5: Objection management
phase.raise_objection(this);
// Do work
phase.drop_objection(this);
// Pattern 6: Analysis port broadcast
ap.write(txn);
// Pattern 7: Connect ports
port.connect(export);
Command-Line Options
# Run specific test
vsim top +UVM_TESTNAME=apb_test
# Set verbosity
+UVM_VERBOSITY=UVM_HIGH
+UVM_VERBOSITY=UVM_LOW
# Timeout
+UVM_TIMEOUT=1000000
# Set config from command line
+uvm_set_config_int=*,num_trans,500
+uvm_set_config_string=*,test_name,"my_test"
# Factory override
+uvm_set_type_override=apb_driver,enhanced_driver
# Config DB trace
+UVM_CONFIG_DB_TRACE
# Factory trace
+UVM_FACTORY_TRACE
# Phase trace
+UVM_PHASE_TRACE
# Objection trace
+UVM_OBJECTION_TRACE
Summary – UVM in 1 Page
//=============================================================================
// COMPLETE UVM TESTBENCH IN ONE VIEW
//=============================================================================
// 1. TRANSACTION (data)
class txn extends uvm_sequence_item;
rand bit[7:0] addr;
`uvm_object_utils(txn)
endclass
// 2. SEQUENCE (generate transactions)
class seq extends uvm_sequence#(txn);
`uvm_object_utils(seq)
task body();
repeat(10) `uvm_do(req)
endtask
endclass
// 3. DRIVER (drive DUT)
class drv extends uvm_driver#(txn);
`uvm_component_utils(drv)
virtual dut_if vif;
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
@(posedge vif.clk); vif.addr <= req.addr;
seq_item_port.item_done();
end
endtask
endclass
// 4. MONITOR (observe DUT)
class mon extends uvm_monitor;
`uvm_component_utils(mon)
uvm_analysis_port#(txn) ap;
task run_phase(uvm_phase phase);
forever begin
@(posedge vif.clk);
t = txn::type_id::create("t");
t.addr = vif.addr;
ap.write(t);
end
endtask
endclass
// 5. SEQUENCER (mediator)
typedef uvm_sequencer#(txn) seqr;
// 6. AGENT (container)
class agt extends uvm_agent;
drv d; mon m; seqr s;
`uvm_component_utils(agt)
function void build_phase(uvm_phase phase);
d = drv::type_id::create("d", this);
m = mon::type_id::create("m", this);
s = seqr::type_id::create("s", this);
endfunction
function void connect_phase(uvm_phase phase);
d.seq_item_port.connect(s.seq_item_export);
endfunction
endclass
// 7. SCOREBOARD (check)
class scbd extends uvm_scoreboard;
`uvm_component_utils(scbd)
uvm_analysis_imp#(txn, scbd) imp;
function void write(txn t);
// Check transaction
endfunction
endclass
// 8. ENVIRONMENT (integration)
class env extends uvm_env;
agt agent; scbd sb;
`uvm_component_utils(env)
function void build_phase(uvm_phase phase);
agent = agt::type_id::create("agent", this);
sb = scbd::type_id::create("sb", this);
endfunction
function void connect_phase(uvm_phase phase);
agent.m.ap.connect(sb.imp);
endfunction
endclass
// 9. TEST (top-level)
class test extends uvm_test;
env e;
`uvm_component_utils(test)
function void build_phase(uvm_phase phase);
e = env::type_id::create("e", this);
endfunction
task run_phase(uvm_phase phase);
seq s = seq::type_id::create("s");
phase.raise_objection(this);
s.start(e.agent.s);
phase.drop_objection(this);
endtask
endclass
// 10. TOP MODULE
module top;
dut_if dif(clk);
dut dut_inst(dif);
initial begin
uvm_config_db#(virtual dut_if)::set(null, "*", "vif", dif);
run_test("test");
end
endmodule
Common Mistakes to Avoid
// ❌ DON'T: Use new() directly
drv = new("drv", this);
// ✅ DO: Use factory
drv = apb_driver::type_id::create("drv", this);
// ❌ DON'T: Create before setting config
env = apb_env::type_id::create("env", this);
uvm_config_db#(cfg)::set(this, "env", "cfg", cfg);
// ✅ DO: Set config before creating
uvm_config_db#(cfg)::set(this, "env", "cfg", cfg);
env = apb_env::type_id::create("env", this);
// ❌ DON'T: Forget objections
task run_phase(uvm_phase phase);
seq.start(seqr); // Phase ends immediately!
endtask
// ✅ DO: Use objections
task run_phase(uvm_phase phase);
phase.raise_objection(this);
seq.start(seqr);
phase.drop_objection(this);
endtask
// ❌ DON'T: Ignore get() return value
uvm_config_db#(vif)::get(this, "", "vif", vif);
// ✅ DO: Check return value
if (!uvm_config_db#(vif)::get(this, "", "vif", vif))
`uvm_fatal("TAG", "VIF not found!")
// ❌ DON'T: Call super last in build
function void build_phase(uvm_phase phase);
comp = my_comp::type_id::create("comp", this);
super.build_phase(phase); // Too late!
endfunction
// ✅ DO: Call super FIRST in build
function void build_phase(uvm_phase phase);
super.build_phase(phase); // First!
comp = my_comp::type_id::create("comp", this);
endfunction
UVM Execution Flow Summary
1. Top module:
- Create interface
- Set VIF in config_db
- run_test("test_name")
2. UVM starts test:
- Create test component
3. build_phase (bottom-up):
- Create all components
- Get config_db values
4. connect_phase (bottom-up):
- Connect TLM ports
5. end_of_elaboration:
- Print topology
6. start_of_simulation:
- Print banners
7. run_phase (parallel):
- All components run simultaneously
- Sequences generate stimulus
- Driver drives DUT
- Monitor observes DUT
- Controlled by objections
8. extract_phase:
- Collect coverage/stats
9. check_phase:
- Verify results
10. report_phase:
- Print reports
11. final_phase:
- Cleanup
12. $finish