Base class for all hierarchical testbench components. Provides phasing, hierarchy traversal, factory integration, and configuration.
Key Methods
| Method | Description |
|---|---|
build_phase | Construct child components and get configuration |
connect_phase | Connect TLM ports between components |
run_phase | Main time-consuming simulation phase (task) |
get_full_name | Returns the full hierarchical path name |
get_parent | Returns the parent component |
get_child | Returns a child component by name |
Example
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);
// Create children here
endfunction
function void connect_phase(uvm_phase phase);
// Connect TLM ports here
endfunction
endclassCommon Mistakes
- Creating children in the constructor instead of build_phase
- Forgetting to call super.build_phase()
- Connecting TLM ports in build_phase instead of connect_phase
- Using new() instead of factory create()
Related Classes
Pulls sequence items from a sequencer and drives them onto the DUT interface through a virtual interface.
Key Methods
| Method | Description |
|---|---|
run_phase | Continuously gets items from sequencer and drives to DUT |
seq_item_port | TLM port connected to sequencer for getting items |
get_next_item | Blocking call that waits for next item from sequencer |
item_done | Signals sequencer that the current item is complete |
try_next_item | Non-blocking attempt to get next item, returns null if none |
Example
class my_driver extends uvm_driver #(my_txn);
virtual my_if vif;
`uvm_component_utils(my_driver)
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 my_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "Virtual interface not set")
endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
// Drive req onto vif
@(posedge vif.clk);
vif.addr <= req.addr;
vif.data <= req.data;
seq_item_port.item_done();
end
endtask
endclassCommon Mistakes
- Forgetting item_done() — causes sequencer to hang forever
- Not getting virtual interface from config_db
- Calling get_next_item without pairing with item_done
Related Classes
Passively observes DUT signals and broadcasts collected transactions via an analysis port. Must never drive signals.
Key Methods
| Method | Description |
|---|---|
run_phase | Continuously samples interface and constructs transactions |
analysis_port | Broadcasts collected transactions to subscribers |
Example
class my_monitor extends uvm_monitor;
virtual my_if vif;
uvm_analysis_port #(my_txn) ap;
`uvm_component_utils(my_monitor)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new("ap", this);
if (!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "Virtual interface not set")
endfunction
task run_phase(uvm_phase phase);
forever begin
my_txn txn = my_txn::type_id::create("txn");
// Sample signals from vif and populate txn
@(posedge vif.clk);
txn.addr = vif.addr;
txn.data = vif.data;
ap.write(txn);
end
endtask
endclassCommon Mistakes
- Driving DUT signals from the monitor (must be passive/read-only)
- Not creating the analysis port in build_phase
- Forgetting to broadcast via ap.write()
Related Classes
Groups a driver, sequencer, and monitor into a reusable protocol agent. Can operate in active or passive mode.
Key Methods
| Method | Description |
|---|---|
build_phase | Creates monitor always; creates driver + sequencer only if active |
connect_phase | Connects driver.seq_item_port to sequencer if active |
get_is_active | Returns UVM_ACTIVE or UVM_PASSIVE |
Example
class my_agent extends uvm_agent;
my_driver drv;
my_monitor mon;
uvm_sequencer #(my_txn) seqr;
`uvm_component_utils(my_agent)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
mon = my_monitor::type_id::create("mon", this);
if (get_is_active() == UVM_ACTIVE) begin
drv = my_driver::type_id::create("drv", this);
seqr = uvm_sequencer#(my_txn)::type_id::create("seqr", this);
end
endfunction
function void connect_phase(uvm_phase phase);
if (get_is_active() == UVM_ACTIVE)
drv.seq_item_port.connect(seqr.seq_item_export);
endfunction
endclassCommon Mistakes
- Creating driver/sequencer in passive mode
- Not checking is_active before connecting ports
- Forgetting to set is_active via config_db in the env or test
Related Classes
Top-level verification environment container. Instantiates agents, scoreboards, coverage collectors, and sub-environments.
Key Methods
| Method | Description |
|---|---|
build_phase | Creates agents, scoreboards, and sub-environments |
connect_phase | Connects agent analysis ports to scoreboards and coverage |
Example
class my_env extends uvm_env;
my_agent agent;
my_scoreboard sb;
`uvm_component_utils(my_env)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = my_agent::type_id::create("agent", this);
sb = my_scoreboard::type_id::create("sb", this);
endfunction
function void connect_phase(uvm_phase phase);
agent.mon.ap.connect(sb.analysis_export);
endfunction
endclassCommon Mistakes
- Hardcoding configuration instead of using config_db
- Not propagating config to sub-components
- Putting too much logic in env instead of delegating to agents
Related Classes
Top of the testbench hierarchy. Creates the environment, sets configuration, and launches test sequences.
Key Methods
| Method | Description |
|---|---|
build_phase | Creates environment and sets all configuration |
run_phase | Raises objection, starts sequences, drops objection |
end_of_elaboration_phase | Good place to print the component topology |
Example
class base_test extends uvm_test;
my_env env;
`uvm_component_utils(base_test)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
my_sequence seq = my_sequence::type_id::create("seq");
phase.raise_objection(this);
seq.start(env.agent.seqr);
phase.drop_objection(this);
endtask
function void end_of_elaboration_phase(uvm_phase phase);
uvm_top.print_topology();
endfunction
endclassCommon Mistakes
- Forgetting phase.raise_objection — test exits immediately at time 0
- Not setting configuration before creating env
- Starting sequences in build_phase instead of run_phase
Related Classes
Arbitrates between multiple sequences and routes items to the connected driver via a TLM export.
Key Methods
| Method | Description |
|---|---|
seq_item_export | TLM export connected to driver's seq_item_port |
set_arbitration | Set arbitration mode: SEQ_ARB_FIFO, SEQ_ARB_WEIGHTED, SEQ_ARB_RANDOM, etc. |
stop_sequences | Kills all currently running sequences |
Example
// Typically use the built-in parameterized sequencer:
uvm_sequencer #(my_txn) seqr;
// In agent build_phase:
seqr = uvm_sequencer#(my_txn)::type_id::create("seqr", this);
// In agent connect_phase:
drv.seq_item_port.connect(seqr.seq_item_export);
// To change arbitration:
seqr.set_arbitration(SEQ_ARB_STRICT_FIFO);Common Mistakes
- Creating a custom sequencer subclass when the built-in one is sufficient
- Not connecting to the driver in connect_phase
- Choosing wrong arbitration mode for the test scenario
Related Classes
Checks DUT correctness by comparing actual outputs against expected values. Receives data via analysis ports from monitors.
Key Methods
| Method | Description |
|---|---|
write | Receives a transaction from a connected analysis port |
check_phase | Perform end-of-test validation checks |
report_phase | Print summary statistics (matches, mismatches, etc.) |
Example
class my_scoreboard extends uvm_scoreboard;
uvm_analysis_imp #(my_txn, my_scoreboard) analysis_export;
int pass_count, fail_count;
`uvm_component_utils(my_scoreboard)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
analysis_export = new("analysis_export", this);
endfunction
function void write(my_txn txn);
// Compare txn against expected
if (txn.data == expected_data)
pass_count++;
else begin
`uvm_error("SB", $sformatf("Mismatch: got %0h, exp %0h", txn.data, expected_data))
fail_count++;
end
endfunction
function void report_phase(uvm_phase phase);
`uvm_info("SB", $sformatf("Pass=%0d Fail=%0d", pass_count, fail_count), UVM_LOW)
endfunction
endclassCommon Mistakes
- Not reporting final statistics
- Letting the test pass when there are mismatches
- Not implementing check_phase for end-of-test drain validation
Related Classes
A sequencer that does not connect to a driver. Routes virtual sequences to multiple sub-sequencers in a multi-agent environment.
Key Methods
| Method | Description |
|---|---|
build_phase | Get handles to actual sub-sequencers via config or hierarchy |
start | Launch a virtual sequence on this sequencer |
Example
class my_virtual_sequencer extends uvm_sequencer;
my_sequencer_a seqr_a;
my_sequencer_b seqr_b;
`uvm_component_utils(my_virtual_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
// Virtual sequence:
class my_virtual_seq extends uvm_sequence;
`uvm_object_utils(my_virtual_seq)
`uvm_declare_p_sequencer(my_virtual_sequencer)
task body();
my_seq_a seq_a = my_seq_a::type_id::create("seq_a");
my_seq_b seq_b = my_seq_b::type_id::create("seq_b");
fork
seq_a.start(p_sequencer.seqr_a);
seq_b.start(p_sequencer.seqr_b);
join
endtask
endclassCommon Mistakes
- Connecting a driver to the virtual sequencer
- Forgetting to assign sub-sequencer handles in the env connect_phase
- Not using `uvm_declare_p_sequencer in the virtual sequence
Related Classes
Type-safe static database for passing configuration objects and virtual interfaces across the component hierarchy.
Key Methods
| Method | Description |
|---|---|
set | Store a value: set(context, inst_path, field_name, value) |
get | Retrieve a value: get(context, inst_path, field_name, value) — returns 1 if found |
exists | Check if a value exists without retrieving it |
wait_modified | Block until the value is updated by another set() call |
Example
// In top-level testbench (typically initial block):
initial begin
uvm_config_db#(virtual my_if)::set(null, "*", "vif", dut_if);
run_test();
end
// In test build_phase:
uvm_config_db#(int)::set(this, "env.agent*", "is_active", UVM_ACTIVE);
// In component build_phase:
if (!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
`uvm_fatal("CFG", "Virtual interface not found in config_db")Common Mistakes
- Not checking get() return value — silently uses null/zero
- Setting config after the target component is already built
- Using overly specific paths that break when hierarchy changes
Related Classes
Lower-level resource database that uvm_config_db is built upon. Stores configuration by scope and type. Prefer uvm_config_db for most use cases.
Key Methods
| Method | Description |
|---|---|
set | Store a resource: set(scope, name, value, accessor) |
get_by_name | Retrieve a resource by scope and name |
get_by_type | Retrieve a resource by scope and type |
read_by_name | Static convenience — returns value directly |
write_by_name | Static convenience — stores value directly |
dump | Print all resources in the database for debug |
Example
// uvm_resource_db is lower-level than uvm_config_db
// Prefer uvm_config_db for configuration in most cases.
// Direct resource_db usage:
uvm_resource_db#(int)::set("*", "timeout", 1000, null);
int timeout;
if (uvm_resource_db#(int)::read_by_name(
"*", "timeout", timeout))
`uvm_info("CFG", $sformatf("timeout=%0d", timeout), UVM_LOW)
// Dump all resources for debug:
uvm_resource_db#(int)::dump();
// Key difference from uvm_config_db:
// - config_db uses component hierarchy for scoping
// - resource_db uses arbitrary string scopes
// - config_db calls resource_db internallyCommon Mistakes
- Using resource_db when config_db would be simpler and more maintainable
- String-based scoping is error-prone — typos create silent failures
- Mixing config_db and resource_db for the same parameter
Related Classes
Central singleton that manages type registration and overrides. Enables creating objects by type without hardcoding class names.
Key Methods
| Method | Description |
|---|---|
create_object_by_type | Create an object using the factory (internal — use type_id::create instead) |
create_component_by_type | Create a component using the factory (internal) |
set_type_override_by_type | Replace all instances of one type with another globally |
set_inst_override_by_type | Replace instances of a type at a specific hierarchy path |
print | Print all registered types and active overrides |
find_override_by_type | Query what a type would resolve to after overrides |
Example
// Register with factory (in class definition):
class my_driver extends uvm_driver #(my_txn);
`uvm_component_utils(my_driver)
...
endclass
// Create via factory (not new):
my_driver drv = my_driver::type_id::create("drv", this);
// Global type override (e.g., in test):
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Replace all my_driver with my_better_driver
my_driver::type_id::set_type_override(my_better_driver::get_type());
// Or override at specific path only:
factory.set_inst_override_by_type(
my_driver::get_type(),
my_better_driver::get_type(),
"env.agent.drv"
);
endfunction
// Print all overrides (useful for debug):
initial begin
factory.print();
endCommon Mistakes
- Using new() instead of type_id::create() — bypasses factory overrides entirely
- Setting overrides after components are already created
- Forgetting `uvm_component_utils or `uvm_object_utils registration macro
Related Classes
Base class for all UVM data and transaction objects. Provides core utilities for copying, comparing, printing, and packing.
Key Methods
| Method | Description |
|---|---|
create | Creates a new object of this type via the factory |
clone | Creates and returns a deep copy of this object |
copy | Copies all fields from the given object to this one |
compare | Deep-compares this object with another, returns 1 if equal |
print | Prints all registered fields to the log |
pack / unpack | Serialize or deserialize object fields into a bit stream |
Example
class my_txn extends uvm_object;
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
endclassCommon Mistakes
- Forgetting super.new(name) in constructor
- Not registering with factory via `uvm_object_utils
- Using uvm_component_utils instead of uvm_object_utils
Related Classes
Extends uvm_object with timing and recording support. Base class for uvm_sequence_item. Adds begin/end time, transaction recording, and event triggers.
Key Methods
| Method | Description |
|---|---|
accept_tr | Called by a port to accept a transaction — marks begin time |
begin_tr | Marks the beginning of a transaction for recording |
end_tr | Marks the end of a transaction and triggers events |
get_tr_handle | Returns the integer handle for this recorded transaction |
do_accept_tr / do_begin_tr / do_end_tr | User callbacks invoked during accept, begin, and end |
Example
class my_txn extends uvm_sequence_item;
// uvm_sequence_item extends uvm_transaction
// Transaction timing is handled automatically:
// accept_tr() → begin_tr() → end_tr()
//
// In a driver:
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
req.begin_tr(this); // mark start
drive_item(req);
req.end_tr(this); // mark end
seq_item_port.item_done();
end
endtask
endclassCommon Mistakes
- Using uvm_transaction directly instead of uvm_sequence_item for driver/sequencer flows
- Forgetting to call end_tr after begin_tr — breaks transaction recording in wave viewer
Related Classes
Represents a single phase in the UVM execution lifecycle. Phases run in a defined order: build → connect → run → extract → check → report.
Example
// UVM Phase Order:
// ─── Build-time (functions, top-down) ───
// build_phase
// connect_phase
// end_of_elaboration_phase
// start_of_simulation_phase
//
// ─── Run-time (tasks, parallel) ───
// run_phase ← main phase, needs objections
// (or sub-phases: reset, configure, main, shutdown)
//
// ─── Clean-up (functions, bottom-up) ───
// extract_phase
// check_phase
// report_phase
// final_phase
task run_phase(uvm_phase phase);
phase.raise_objection(this, "Starting test");
// ... stimulus ...
phase.drop_objection(this, "Test complete");
endtaskCommon Mistakes
- Forgetting raise_objection in run_phase — simulation ends at time 0
- Raising objection in build_phase (build is a function phase, not task)
- Putting time-consuming code in build_phase or connect_phase (function phases)
Related Classes
Mechanism to coordinate phase completion. A phase ends only when all raised objections are dropped. Critical for run-time phases.
Key Methods
| Method | Description |
|---|---|
raise_objection | Increment objection count — prevents phase from ending |
drop_objection | Decrement objection count — phase ends when count reaches 0 |
set_drain_time | Add delay after last drop before phase actually ends |
get_objection_count | Return current count for a component |
get_objection_total | Return total count across all components |
Example
task run_phase(uvm_phase phase);
// MUST raise before any delay
phase.raise_objection(this, "Starting stimulus");
// Optional: set drain time for in-flight transactions
uvm_objection obj = phase.get_objection();
obj.set_drain_time(this, 100ns);
// Run stimulus
repeat (100) begin
my_txn txn = my_txn::type_id::create("txn");
start_item(txn);
assert(txn.randomize());
finish_item(txn);
end
phase.drop_objection(this, "Stimulus complete");
// Phase waits 100ns drain time, then ends
endtaskCommon Mistakes
- Dropping objection before all transactions are complete — ends simulation early
- Not raising objection at all — simulation exits immediately at time 0
- Raising in one component but dropping in a different component
Related Classes
Top-level container for a register model. Groups registers, memories, and address maps to mirror DUT register space.
Key Methods
| Method | Description |
|---|---|
build | Pure virtual — create registers, memories, and address maps |
create_map | Create an address map with base address, bus width, and endianness |
lock_model | Freeze the model after building — no more modifications allowed |
configure | Set parent block and optional HDL path for backdoor access |
Example
class my_reg_block extends uvm_reg_block;
rand my_ctrl_reg ctrl;
rand my_status_reg status;
`uvm_object_utils(my_reg_block)
function new(string name = "my_reg_block");
super.new(name, UVM_NO_COVERAGE);
endfunction
virtual function void build();
ctrl = my_ctrl_reg::type_id::create("ctrl");
ctrl.configure(this, null, "");
ctrl.build();
status = my_status_reg::type_id::create("status");
status.configure(this, null, "");
status.build();
default_map = create_map("default_map", 0, 4, UVM_LITTLE_ENDIAN);
default_map.add_reg(ctrl, 32'h0000, "RW");
default_map.add_reg(status, 32'h0004, "RO");
lock_model();
endfunction
endclassCommon Mistakes
- Not calling lock_model() after build — model remains mutable
- Forgetting to create an address map
- Not calling configure() on each register before build()
Related Classes
Models a single hardware register containing one or more fields. Supports front-door (bus) and back-door (HDL path) access.
Key Methods
| Method | Description |
|---|---|
build | Pure virtual — add fields to this register |
configure | Set parent block, HDL path, and regfile |
read | Front-door read via bus agent, or back-door via HDL path |
write | Front-door write via bus agent, or back-door |
get | Return the current desired (mirror) value without bus access |
set | Set the desired value without writing to DUT |
mirror | Read DUT register and update the mirror, optionally check |
predict | Update mirror value without bus access |
get_mirrored_value | Return current mirrored value |
reset | Reset the mirror value to the register reset value |
Example
class my_ctrl_reg extends uvm_reg;
rand uvm_reg_field enable;
rand uvm_reg_field mode;
`uvm_object_utils(my_ctrl_reg)
function new(string name = "my_ctrl_reg");
super.new(name, 32, UVM_NO_COVERAGE);
endfunction
virtual function void build();
enable = uvm_reg_field::type_id::create("enable");
enable.configure(this, 1, 0, "RW", 0, 1'h0, 1, 1, 1);
mode = uvm_reg_field::type_id::create("mode");
mode.configure(this, 2, 1, "RW", 0, 2'h0, 1, 1, 1);
endfunction
endclass
// Usage in a sequence:
my_ctrl_reg ctrl = reg_block.ctrl;
uvm_status_e status;
ctrl.write(status, 32'h0000_0005); // front-door write
ctrl.read(status, rdata); // front-door read
ctrl.mirror(status, UVM_CHECK); // read + compareCommon Mistakes
- Forgetting to call configure() before build()
- Not calling lock_model() on the parent reg_block
- Confusing get/set (mirror only) with read/write (bus access)
- Not specifying the correct register width in the constructor
Related Classes
Models a single field within a register. Defines bit width, position, access policy, and reset value.
Key Methods
| Method | Description |
|---|---|
configure | Set parent reg, width, LSB position, access, volatility, reset value, has_reset, is_rand, individually_accessible |
set | Set the desired value of this field |
get | Get the current desired value |
get_mirrored_value | Get the current mirrored value |
get_reset | Get the reset value of this field |
read / write | Front-door field-level read/write (uses read-modify-write for sub-register fields) |
Example
// Fields are created inside a register's build() method:
function void build();
// configure(parent, size, lsb_pos, access, volatile,
// reset, has_reset, is_rand, individually_accessible)
status = uvm_reg_field::type_id::create("status");
status.configure(this, 4, 0, "RO", 1, 4'h0, 1, 0, 0);
control = uvm_reg_field::type_id::create("control");
control.configure(this, 4, 4, "RW", 0, 4'h0, 1, 1, 0);
reserved = uvm_reg_field::type_id::create("reserved");
reserved.configure(this, 24, 8, "RO", 0, 24'h0, 1, 0, 0);
endfunction
// Access policies: RO, RW, RC, RS, WRC, WRS, WC, WS,
// WSRC, WCRS, W1C, W1S, W1T, W0C, W0S, W0T, W1SRC,
// W1CRS, W0SRC, W0CRS, WO, WOC, WOS, W1, WO1Common Mistakes
- Getting the configure() argument order wrong (9 positional args)
- Using wrong access policy — e.g., RW for a status register
- Forgetting has_reset=1 which prevents proper reset value tracking
Related Classes
Defines the address space for a register block. Maps registers to offsets and connects to a bus agent via an adapter.
Key Methods
| Method | Description |
|---|---|
add_reg | Map a register to a byte offset with access type |
add_mem | Map a memory to a byte offset with access type |
add_submap | Include another reg_map at a given base address |
set_sequencer | Assign the bus sequencer and adapter for front-door access |
get_base_addr | Return the base address of this map |
set_auto_predict | Enable auto-prediction (mirror updates without predictor component) |
Example
// Inside reg_block build():
virtual function void build();
// ... create registers ...
default_map = create_map("default_map",
.base_addr(0),
.n_bytes(4),
.endian(UVM_LITTLE_ENDIAN)
);
default_map.add_reg(ctrl, 'h0000, "RW");
default_map.add_reg(status, 'h0004, "RO");
default_map.add_reg(data, 'h0008, "RW");
lock_model();
endfunction
// Connect to bus agent in env:
reg_block.default_map.set_sequencer(agent.seqr, adapter);
reg_block.default_map.set_auto_predict(1);Common Mistakes
- Using bit addresses instead of byte addresses for offsets
- Not calling set_sequencer — front-door access will fail
- Confusing set_auto_predict with explicit predictor component
- Adding registers after lock_model()
Related Classes
Converts between abstract register operations (uvm_reg_bus_op) and protocol-specific bus transactions. One adapter per bus protocol.
Key Methods
| Method | Description |
|---|---|
reg2bus | Convert a register operation to a bus transaction — must override |
bus2reg | Convert a bus response back to a register result — must override |
supports_byte_enable | Override to return 1 if bus supports byte enables |
provides_responses | Override to return 1 if bus sends separate response items |
Example
class my_reg_adapter extends uvm_reg_adapter;
`uvm_object_utils(my_reg_adapter)
function new(string name = "my_reg_adapter");
super.new(name);
supports_byte_enable = 0;
provides_responses = 0;
endfunction
virtual function uvm_sequence_item reg2bus(
const ref uvm_reg_bus_op rw
);
my_txn txn = my_txn::type_id::create("txn");
txn.addr = rw.addr;
txn.data = rw.data;
txn.wr_en = (rw.kind == UVM_WRITE);
return txn;
endfunction
virtual function void bus2reg(
uvm_sequence_item bus_item,
ref uvm_reg_bus_op rw
);
my_txn txn;
if (!$cast(txn, bus_item)) begin
`uvm_fatal("CAST", "Failed to cast bus_item")
return;
end
rw.data = txn.data;
rw.status = UVM_IS_OK;
endfunction
endclassCommon Mistakes
- Not setting provides_responses when the bus has a separate response channel
- Forgetting bus2reg — read data is lost
- Returning wrong status in bus2reg
Related Classes
Observes bus transactions via an analysis port and updates the register model mirror automatically. More accurate than auto-predict.
Key Methods
| Method | Description |
|---|---|
bus_in | Analysis export — connect the monitor analysis port here |
map | Handle to the register map being predicted |
adapter | Handle to the reg adapter for bus2reg conversion |
Example
class my_env extends uvm_env;
my_reg_block reg_block;
my_agent agent;
my_reg_adapter adapter;
uvm_reg_predictor #(my_txn) predictor;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
reg_block = my_reg_block::type_id::create("reg_block");
reg_block.build();
reg_block.lock_model();
agent = my_agent::type_id::create("agent", this);
adapter = my_reg_adapter::type_id::create("adapter");
predictor = uvm_reg_predictor#(my_txn)::type_id::create("predictor", this);
endfunction
function void connect_phase(uvm_phase phase);
reg_block.default_map.set_sequencer(agent.seqr, adapter);
predictor.map = reg_block.default_map;
predictor.adapter = adapter;
agent.mon.ap.connect(predictor.bus_in);
endfunction
endclassCommon Mistakes
- Using both auto_predict and explicit predictor — causes double updates
- Forgetting to assign predictor.map or predictor.adapter
- Not connecting the monitor analysis port to the predictor
Related Classes
Models a memory region in the DUT register space. Supports front-door and back-door read/write with configurable size and access.
Key Methods
| Method | Description |
|---|---|
configure | Set parent block, size (entries), width (bits), access, and HDL path |
read | Read a single memory location by offset |
write | Write a single memory location by offset |
burst_read | Read multiple consecutive locations |
burst_write | Write multiple consecutive locations |
get_size | Return number of memory entries |
get_n_bits | Return width of each entry in bits |
Example
class my_mem extends uvm_mem;
`uvm_object_utils(my_mem)
function new(string name = "my_mem");
super.new(name, 256, 32, "RW"); // 256 entries x 32 bits
endfunction
endclass
// In reg_block build():
mem = my_mem::type_id::create("mem");
mem.configure(this, "");
default_map.add_mem(mem, 'h1000, "RW");
// In a test sequence:
uvm_status_e status;
reg_block.mem.write(status, .offset(0), .value(32'hDEAD_BEEF));
reg_block.mem.read(status, .offset(0), .value(rdata));Common Mistakes
- Confusing memory offset (entry index) with byte address
- Not adding memory to the address map
- Using write() without checking status return
Related Classes
Singleton that collects all UVM messages (info, warning, error, fatal). Tracks counts and controls simulation exit on max errors.
Key Methods
| Method | Description |
|---|---|
get_server | Static method to get the global report server singleton |
get_severity_count | Return total count of messages at a given severity |
set_max_quit_count | Set how many errors/fatals before simulation exits |
get_max_quit_count | Get current max quit count |
report_summarize | Print end-of-simulation summary of all message counts |
Example
// Check message counts in report_phase:
function void report_phase(uvm_phase phase);
uvm_report_server srv = uvm_report_server::get_server();
int err_count = srv.get_severity_count(UVM_ERROR);
int fat_count = srv.get_severity_count(UVM_FATAL);
if (err_count == 0 && fat_count == 0)
`uvm_info("TEST", "*** TEST PASSED ***", UVM_NONE)
else
`uvm_info("TEST", $sformatf("*** TEST FAILED *** (%0d errors)", err_count), UVM_NONE)
endfunction
// Set max errors before quit (in test build_phase):
uvm_report_server srv = uvm_report_server::get_server();
srv.set_max_quit_count(10); // quit after 10 errorsCommon Mistakes
- Not checking error counts in report_phase — test may silently pass with errors
- Setting max_quit_count too low — masks additional failures
Related Classes
Intercepts UVM messages before they are processed. Can modify, demote, promote, or suppress messages.
Key Methods
| Method | Description |
|---|---|
catch | Override this — return CAUGHT to suppress, THROW to pass through |
add | Static — register this catcher globally or for a specific component |
get_severity | Get the severity of the intercepted message |
get_id | Get the message ID string |
get_message | Get the message text |
set_severity | Change the severity (demote/promote) |
set_action | Change the action (display, log, count, exit) |
Example
// Demote a known benign error to warning:
class demote_catcher extends uvm_report_catcher;
`uvm_object_utils(demote_catcher)
function new(string name = "demote_catcher");
super.new(name);
endfunction
function action_e catch();
if (get_severity() == UVM_ERROR &&
get_id() == "EXPECTED_ERR") begin
set_severity(UVM_WARNING);
return THROW; // pass modified message through
end
return THROW; // pass all others unchanged
endfunction
endclass
// Register in test:
demote_catcher catcher = new("catcher");
uvm_report_catcher::add(null, catcher); // null = globalCommon Mistakes
- Returning CAUGHT for all messages — suppresses everything
- Forgetting to return THROW for non-matching messages
- Not registering the catcher with add()
Related Classes
Base class for transaction objects passed between sequences, sequencers, and drivers. Contains randomizable stimulus fields.
Key Methods
| Method | Description |
|---|---|
new | Constructor — takes only a name string (no parent) |
do_copy | Override for custom deep-copy behavior |
do_compare | Override for custom comparison logic |
convert2string | Return a string representation for debug printing |
Example
class my_txn extends uvm_sequence_item;
rand bit [7:0] addr;
rand bit [31:0] data;
rand bit wr_en;
constraint valid_c {
addr inside {[8'h00:8'hFF]};
}
`uvm_object_utils_begin(my_txn)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_int(wr_en, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "my_txn");
super.new(name);
endfunction
endclassCommon Mistakes
- Using uvm_component_utils instead of uvm_object_utils
- Adding a parent argument to the constructor (sequence items have no parent)
- Not making stimulus fields rand
Related Classes
Generates ordered stimulus by creating, randomizing, and sending sequence items to a sequencer/driver pair.
Key Methods
| Method | Description |
|---|---|
body | Main sequence logic — override this to define stimulus |
start_item | Request sequencer access for an item (blocks until granted) |
finish_item | Send item to driver and wait for item_done() |
start | Launch this sequence on the given sequencer |
pre_body / post_body | Hooks that run before/after body() |
Example
class my_sequence extends uvm_sequence #(my_txn);
`uvm_object_utils(my_sequence)
function new(string name = "my_sequence");
super.new(name);
endfunction
task body();
repeat (10) begin
my_txn txn = my_txn::type_id::create("txn");
start_item(txn);
assert(txn.randomize());
finish_item(txn);
end
endtask
endclass
// Usage in test:
// my_sequence seq = my_sequence::type_id::create("seq");
// seq.start(env.agent.seqr);Common Mistakes
- Not pairing start_item with finish_item
- Randomizing before start_item (sequencer may add late constraints)
- Using new() instead of factory create() for the sequence
Related Classes
A sequence that randomly selects and executes sequences from a registered pool. Useful for constrained-random regression testing.
Key Methods
| Method | Description |
|---|---|
add_typewide_sequence | Register a sequence type to all libraries of this type |
add_typewide_sequences | Register multiple sequence types at once |
add_sequence | Register a sequence type to this specific library instance |
selection_mode | Control how sequences are picked: UVM_SEQ_LIB_RAND, UVM_SEQ_LIB_RANDC, UVM_SEQ_LIB_ITEM, UVM_SEQ_LIB_USER |
min_random_count / max_random_count | Min/max number of sequences to execute per run |
Example
class my_seq_lib extends uvm_sequence_library #(my_txn);
`uvm_object_utils(my_seq_lib)
`uvm_sequence_library_utils(my_seq_lib)
function new(string name = "my_seq_lib");
super.new(name);
init_sequence_library();
endfunction
endclass
// Register sequences into the library:
initial begin
my_seq_lib::add_typewide_sequence(my_seq_a::get_type());
my_seq_lib::add_typewide_sequence(my_seq_b::get_type());
end
// Usage in test:
my_seq_lib seq_lib = my_seq_lib::type_id::create("seq_lib");
seq_lib.selection_mode = UVM_SEQ_LIB_RANDC;
seq_lib.min_random_count = 5;
seq_lib.max_random_count = 10;
seq_lib.start(env.agent.seqr);Common Mistakes
- Not calling init_sequence_library() in the constructor
- Forgetting `uvm_sequence_library_utils macro
- Registering sequences after the library has already started
Related Classes
A synchronization primitive for inter-component communication. Can be triggered and waited on, with optional data payload.
Key Methods
| Method | Description |
|---|---|
trigger | Fire the event — all waiters are unblocked |
wait_trigger | Block until the event is triggered |
wait_trigger_data | Block and retrieve the data payload when triggered |
reset | Reset the event to untriggered state |
is_on | Returns 1 if event has been triggered (and not reset) |
wait_ptrigger | Wait for persistent trigger — catches trigger even if already fired |
get_trigger_data | Return the data from the last trigger |
Example
class my_env extends uvm_env;
uvm_event reset_done;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
reset_done = new("reset_done");
endfunction
endclass
// In reset sequence:
task body();
// ... drive reset ...
@(posedge vif.clk);
vif.rst_n <= 1;
p_sequencer.reset_done.trigger(); // signal others
endtask
// In another component:
task run_phase(uvm_phase phase);
env.reset_done.wait_trigger(); // blocks until reset
`uvm_info("MON", "Reset complete, starting", UVM_MEDIUM)
// ... start monitoring ...
endtaskCommon Mistakes
- Not resetting the event between test iterations
- Using wait_trigger instead of wait_ptrigger — misses trigger if already fired
- Triggering from multiple sources without coordination
Related Classes
Global associative array of named uvm_events. Allows components to share events by name without hierarchy references.
Key Methods
| Method | Description |
|---|---|
get_global_pool | Static — returns the global event pool singleton |
get | Get or create an event by name (auto-creates if not found) |
exists | Check if a named event exists in the pool |
delete | Remove a named event from the pool |
num | Return number of events in the pool |
Example
// Any component can get/create shared events by name:
// In driver:
task run_phase(uvm_phase phase);
uvm_event_pool pool = uvm_event_pool::get_global_pool();
uvm_event pkt_sent = pool.get("packet_sent");
forever begin
seq_item_port.get_next_item(req);
drive(req);
pkt_sent.trigger(); // signal packet was sent
seq_item_port.item_done();
end
endtask
// In scoreboard:
task run_phase(uvm_phase phase);
uvm_event_pool pool = uvm_event_pool::get_global_pool();
uvm_event pkt_sent = pool.get("packet_sent");
forever begin
pkt_sent.wait_trigger();
// process the sent packet
pkt_sent.reset();
end
endtaskCommon Mistakes
- Misspelling event names — creates separate events silently
- Not resetting events after handling
- Using the pool for high-frequency synchronization (events have overhead)
Related Classes
A synchronization barrier that blocks all waiters until a specified number of processes arrive. Useful for multi-agent synchronization.
Key Methods
| Method | Description |
|---|---|
set_threshold | Set how many processes must arrive before barrier opens |
get_threshold | Get current threshold |
wait_for | Block until threshold is reached — then all waiters proceed |
reset | Reset the barrier — clears all current waiters |
cancel | Cancel the barrier — unblock all waiters immediately |
get_num_waiters | Return how many processes are currently waiting |
Example
class my_env extends uvm_env;
uvm_barrier sync_barrier;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
sync_barrier = new("sync_barrier");
sync_barrier.set_threshold(3); // wait for 3 agents
endfunction
endclass
// In each agent's driver:
task run_phase(uvm_phase phase);
// Initialize...
env.sync_barrier.wait_for(); // blocks until 3 drivers ready
// All 3 proceed together
forever begin
// ... drive stimulus ...
end
endtaskCommon Mistakes
- Setting threshold after some processes have already called wait_for
- Forgetting to reset barrier between uses
- Setting threshold higher than actual number of waiters — deadlock
Related Classes
One-to-many broadcast port. A single write() call delivers the transaction to all connected subscribers simultaneously.
Key Methods
| Method | Description |
|---|---|
write | Broadcasts a transaction to every connected analysis export/imp |
connect | Connect this port to an analysis export or imp |
Example
// Declare in monitor:
uvm_analysis_port #(my_txn) ap;
// Create in build_phase:
ap = new("ap", this);
// Broadcast in run_phase:
ap.write(txn);
// Connect in env:
monitor.ap.connect(scoreboard.analysis_export);
monitor.ap.connect(coverage.analysis_export);
// One write() reaches both scoreboard and coverageCommon Mistakes
- Forgetting to create the analysis port in build_phase (causes null pointer)
- Trying to connect in the wrong direction
- Not broadcasting all collected transactions
Related Classes
Convenience base class that has a built-in analysis_export. Just override the write() method to receive transactions.
Key Methods
| Method | Description |
|---|---|
write | Pure virtual — must be implemented to handle incoming transactions |
Example
class my_coverage extends uvm_subscriber #(my_txn);
my_txn txn;
covergroup cg;
addr_cp: coverpoint txn.addr {
bins low = {[0:127]};
bins high = {[128:255]};
}
endgroup
`uvm_component_utils(my_coverage)
function new(string name, uvm_component parent);
super.new(name, parent);
cg = new();
endfunction
function void write(my_txn t);
txn = t;
cg.sample();
endfunction
endclass
// Connect in env:
monitor.ap.connect(coverage.analysis_export);Common Mistakes
- Not sampling the covergroup in write()
- Forgetting to connect the monitor analysis port to the subscriber
- Creating the covergroup outside the constructor
Related Classes
Implementation port that receives transactions from an analysis port. The parent component must implement a write() function.
Key Methods
| Method | Description |
|---|---|
write | Called when a connected analysis port broadcasts a transaction — implement in parent component |
new | Constructor: new(name, parent) — parent must implement write() |
Example
class my_scoreboard extends uvm_scoreboard;
// Standard imp — parent implements write()
uvm_analysis_imp #(my_txn, my_scoreboard) ap_imp;
`uvm_component_utils(my_scoreboard)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap_imp = new("ap_imp", this);
endfunction
// Must match the transaction type
function void write(my_txn txn);
`uvm_info("SB", $sformatf("Received: addr=%0h", txn.addr), UVM_MEDIUM)
endfunction
endclass
// For multiple analysis ports, use `uvm_analysis_imp_decl:
`uvm_analysis_imp_decl(_expected)
`uvm_analysis_imp_decl(_actual)
class dual_sb extends uvm_scoreboard;
uvm_analysis_imp_expected #(my_txn, dual_sb) exp_imp;
uvm_analysis_imp_actual #(my_txn, dual_sb) act_imp;
function void write_expected(my_txn t); ... endfunction
function void write_actual(my_txn t); ... endfunction
endclassCommon Mistakes
- Forgetting to implement write() in the parent component — causes compile error
- Confusing analysis_imp with analysis_export
- Not using `uvm_analysis_imp_decl when connecting multiple analysis ports to the same component
Related Classes
A FIFO buffer component with put and get TLM exports. Decouples producers from consumers with configurable depth.
Key Methods
| Method | Description |
|---|---|
put_export | Connect a producer port here to put items into the FIFO |
get_peek_export | Connect a consumer port here to get/peek items |
put | Blocking put — waits if FIFO is full |
get | Blocking get — waits if FIFO is empty |
try_put / try_get | Non-blocking versions that return 0 if unable |
is_full / is_empty | Check FIFO state |
size / used | Returns max capacity / current occupancy |
flush | Remove all items from the FIFO |
Example
class my_env extends uvm_env;
uvm_tlm_fifo #(my_txn) fifo;
my_producer prod;
my_consumer cons;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
fifo = new("fifo", this, 16); // depth = 16
prod = my_producer::type_id::create("prod", this);
cons = my_consumer::type_id::create("cons", this);
endfunction
function void connect_phase(uvm_phase phase);
prod.put_port.connect(fifo.put_export);
cons.get_port.connect(fifo.get_peek_export);
endfunction
endclassCommon Mistakes
- Forgetting to specify FIFO depth (defaults to 1)
- Using blocking put/get in zero-time contexts — causes simulation hang
- Not flushing FIFO between test phases
Related Classes
A TLM FIFO with an unbounded analysis_export that never blocks on write. Ideal for connecting monitors to scoreboards asynchronously.
Key Methods
| Method | Description |
|---|---|
analysis_export | Unbounded write port — connect analysis_port here, never blocks |
get_peek_export | Consumer side — get or peek items from the FIFO |
get | Blocking get — waits if FIFO is empty |
try_get | Non-blocking get — returns 0 if empty |
Example
class my_scoreboard extends uvm_scoreboard;
uvm_tlm_analysis_fifo #(my_txn) exp_fifo;
uvm_tlm_analysis_fifo #(my_txn) act_fifo;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
exp_fifo = new("exp_fifo", this);
act_fifo = new("act_fifo", this);
endfunction
// In env connect_phase:
// ref_model.ap.connect(sb.exp_fifo.analysis_export);
// monitor.ap.connect(sb.act_fifo.analysis_export);
task run_phase(uvm_phase phase);
my_txn exp_txn, act_txn;
forever begin
exp_fifo.get(exp_txn);
act_fifo.get(act_txn);
if (!exp_txn.compare(act_txn))
`uvm_error("SB", "Mismatch!")
end
endtask
endclassCommon Mistakes
- Using a regular uvm_tlm_fifo instead — it blocks when full
- Forgetting that analysis_export is write-only (use get_peek_export for reading)
- Not draining the FIFO at end of test
Related Classes
Controls how uvm_object::compare() works. Configures comparison depth, verbosity, and which mismatches to report.
Key Methods
| Method | Description |
|---|---|
compare_field | Compare a single field by name, size, and radix |
compare_string | Compare two strings |
compare_object | Deep-compare two uvm_objects recursively |
show_max | Property — max number of mismatches to display (default 1) |
verbosity | Property — UVM_LOW etc., controls when mismatches are printed |
result | Property — number of mismatches found (0 = objects are equal) |
Example
// Custom comparison policy:
uvm_comparer comp = new();
comp.show_max = 10; // show up to 10 mismatches
comp.verbosity = UVM_MEDIUM; // report at medium verbosity
if (!txn_a.compare(txn_b, comp))
`uvm_error("CMP", $sformatf("%0d mismatches", comp.result))
// Override do_compare for custom logic:
class my_txn extends uvm_sequence_item;
function bit do_compare(uvm_object rhs, uvm_comparer comparer);
my_txn rhs_txn;
if (!$cast(rhs_txn, rhs)) return 0;
return (addr == rhs_txn.addr) &&
(data == rhs_txn.data);
endfunction
endclassCommon Mistakes
- Not checking compare() return value
- Setting show_max=0 which suppresses all mismatch output
- Forgetting to $cast rhs in do_compare override
Related Classes
Serializes and deserializes uvm_objects to/from a bitstream. Used by pack/unpack methods for data transfer and comparison.
Key Methods
| Method | Description |
|---|---|
pack_field | Pack a value of specified size into the bitstream |
pack_string | Pack a string (length-prefixed) into the bitstream |
pack_object | Recursively pack an object and its fields |
unpack_field | Extract a value of specified size from the bitstream |
unpack_string | Extract a string from the bitstream |
unpack_object | Recursively unpack fields into an object |
big_endian | Property — pack in big-endian order (default 0) |
Example
class my_txn extends uvm_sequence_item;
rand bit [7:0] addr;
rand bit [31:0] data;
// Field automation handles pack/unpack:
`uvm_object_utils_begin(my_txn)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end
endclass
// Manual pack/unpack:
my_txn txn = my_txn::type_id::create("txn");
txn.addr = 8'hAB;
txn.data = 32'hDEADBEEF;
bit bitstream[];
txn.pack(bitstream); // serialize to bits
my_txn txn2 = my_txn::type_id::create("txn2");
txn2.unpack(bitstream); // deserialize from bits
// txn2.addr == 8'hAB, txn2.data == 32'hDEADBEEFCommon Mistakes
- Pack and unpack field order mismatch — data corruption
- Mixing manual do_pack with field automation
- Forgetting to call super.do_pack in override
Related Classes
Controls how uvm_object::print() and sprint() format output. UVM provides table, tree, and line printer variants.
Key Methods
| Method | Description |
|---|---|
print_object | Print an object using this printer's format |
knobs.depth | How deep to recurse into sub-objects (-1 = unlimited) |
knobs.reference | Show object reference IDs |
knobs.full_name | Show full hierarchical names |
knobs.indent | Number of spaces per indent level |
Example
// UVM provides 3 built-in printers:
// uvm_default_table_printer — tabular format (default)
// uvm_default_tree_printer — indented tree format
// uvm_default_line_printer — single-line format
my_txn txn = my_txn::type_id::create("txn");
assert(txn.randomize());
// Print with default table printer:
txn.print();
// Print with tree format:
txn.print(uvm_default_tree_printer);
// Print topology in end_of_elaboration:
function void end_of_elaboration_phase(uvm_phase phase);
uvm_top.print_topology();
endfunction
// Customize printer:
uvm_table_printer printer = new();
printer.knobs.depth = 2;
txn.print(printer);Common Mistakes
- Printing in time-critical code paths — print has performance overhead
- Not using sprint() when you need the string (print goes to log)
- Excessive depth causing huge output for complex objects
Related Classes
Base class for callback objects. Callbacks let users inject custom behavior into existing components without modifying their source code.
Key Methods
| Method | Description |
|---|---|
callback method | Define virtual methods in your callback class — components call these at hook points |
add | Static (via uvm_callbacks#(T,CB)) — register a callback with a component |
delete | Static — remove a previously registered callback |
Example
// Step 1: Define callback class with virtual methods:
class my_driver_cb extends uvm_callback;
`uvm_object_utils(my_driver_cb)
function new(string name = "my_driver_cb");
super.new(name);
endfunction
virtual task pre_drive(my_driver drv, my_txn txn);
endtask
virtual task post_drive(my_driver drv, my_txn txn);
endtask
endclass
// Step 2: Add callback hooks in driver:
class my_driver extends uvm_driver #(my_txn);
`uvm_register_cb(my_driver, my_driver_cb)
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
`uvm_do_callbacks(my_driver, my_driver_cb, pre_drive(this, req))
drive_item(req);
`uvm_do_callbacks(my_driver, my_driver_cb, post_drive(this, req))
seq_item_port.item_done();
end
endtask
endclass
// Step 3: Create and register callback in test:
class my_error_cb extends my_driver_cb;
virtual task pre_drive(my_driver drv, my_txn txn);
txn.addr = 8'hFF; // inject error
endtask
endclass
// In test:
my_error_cb cb = new("cb");
uvm_callbacks#(my_driver, my_driver_cb)::add(env.agent.drv, cb);Common Mistakes
- Forgetting `uvm_register_cb in the component
- Not calling `uvm_do_callbacks at the hook points
- Registering callbacks after the component has started running
Related Classes
Singleton that parses simulation command-line arguments. Retrieve +args to control test behavior without recompilation.
Key Methods
| Method | Description |
|---|---|
get_inst | Static — return the singleton instance |
get_arg_value | Get value of +name=value argument, returns count of matches |
get_arg_values | Get all values matching a +name= prefix into a queue |
get_args | Get the complete list of command-line arguments |
+UVM_TESTNAME= | Built-in: select which uvm_test to run |
+UVM_VERBOSITY= | Built-in: set global message verbosity |
Example
// Parse custom +args:
class my_test extends uvm_test;
int num_txns = 100;
string mode = "normal";
function void build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst();
string val;
if (clp.get_arg_value("+NUM_TXNS=", val))
num_txns = val.atoi();
if (clp.get_arg_value("+MODE=", val))
mode = val;
`uvm_info("TEST", $sformatf("num_txns=%0d mode=%s",
num_txns, mode), UVM_LOW)
endfunction
endclass
// Run with:
// vsim +UVM_TESTNAME=my_test +NUM_TXNS=500 +MODE=stress
// Built-in UVM +args:
// +UVM_TESTNAME=<test> Select test
// +UVM_VERBOSITY=<level> UVM_NONE/LOW/MEDIUM/HIGH/FULL
// +UVM_MAX_QUIT_COUNT=<n> Max errors before quit
// +UVM_TIMEOUT=<time>,<YES> Global timeoutCommon Mistakes
- Hardcoding test parameters instead of using +args
- Not providing default values when +arg is missing
- Using get_arg_value for arguments without = sign (use get_args instead)
Related Classes
The implicit top-level component in every UVM testbench. Accessible via uvm_root::get() or the global uvm_top handle. Manages phasing and topology.
Key Methods
| Method | Description |
|---|---|
get | Static — returns the uvm_root singleton (also available as uvm_top) |
run_test | Launch UVM phasing — call from initial block or use +UVM_TESTNAME |
print_topology | Print the complete component hierarchy tree |
find | Find a component by full hierarchical path |
find_all | Find all components matching a glob pattern |
set_timeout | Set the global simulation timeout |
Example
// Standard UVM entry point:
module top;
my_if dut_if();
dut dut_inst(.*);
initial begin
uvm_config_db#(virtual my_if)::set(
null, "*", "vif", dut_if);
run_test(); // reads +UVM_TESTNAME from command line
end
endmodule
// Print topology in end_of_elaboration:
function void end_of_elaboration_phase(uvm_phase phase);
uvm_top.print_topology();
endfunction
// Set simulation timeout:
initial begin
uvm_top.set_timeout(10ms);
end
// Find components at runtime:
uvm_component comp;
comp = uvm_top.find("uvm_test_top.env.agent.drv");Common Mistakes
- Calling run_test() multiple times
- Not setting virtual interface before run_test()
- Using uvm_root::get() when uvm_top global handle works fine