42 classes
uvm_component Component
extends uvm_report_object

Base class for all hierarchical testbench components. Provides phasing, hierarchy traversal, factory integration, and configuration.

Key Methods

MethodDescription
build_phaseConstruct child components and get configuration
connect_phaseConnect TLM ports between components
run_phaseMain time-consuming simulation phase (task)
get_full_nameReturns the full hierarchical path name
get_parentReturns the parent component
get_childReturns 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
endclass

Common 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

uvm_driver Component
extends uvm_component

Pulls sequence items from a sequencer and drives them onto the DUT interface through a virtual interface.

Key Methods

MethodDescription
run_phaseContinuously gets items from sequencer and drives to DUT
seq_item_portTLM port connected to sequencer for getting items
get_next_itemBlocking call that waits for next item from sequencer
item_doneSignals sequencer that the current item is complete
try_next_itemNon-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
endclass

Common 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

uvm_monitor Component
extends uvm_component

Passively observes DUT signals and broadcasts collected transactions via an analysis port. Must never drive signals.

Key Methods

MethodDescription
run_phaseContinuously samples interface and constructs transactions
analysis_portBroadcasts 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
endclass

Common 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

uvm_agent Component
extends uvm_component

Groups a driver, sequencer, and monitor into a reusable protocol agent. Can operate in active or passive mode.

Key Methods

MethodDescription
build_phaseCreates monitor always; creates driver + sequencer only if active
connect_phaseConnects driver.seq_item_port to sequencer if active
get_is_activeReturns 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
endclass

Common 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

uvm_env Component
extends uvm_component

Top-level verification environment container. Instantiates agents, scoreboards, coverage collectors, and sub-environments.

Key Methods

MethodDescription
build_phaseCreates agents, scoreboards, and sub-environments
connect_phaseConnects 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
endclass

Common 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

uvm_test Component
extends uvm_component

Top of the testbench hierarchy. Creates the environment, sets configuration, and launches test sequences.

Key Methods

MethodDescription
build_phaseCreates environment and sets all configuration
run_phaseRaises objection, starts sequences, drops objection
end_of_elaboration_phaseGood 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
endclass

Common 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

uvm_sequencer Component
extends uvm_sequencer_base

Arbitrates between multiple sequences and routes items to the connected driver via a TLM export.

Key Methods

MethodDescription
seq_item_exportTLM export connected to driver's seq_item_port
set_arbitrationSet arbitration mode: SEQ_ARB_FIFO, SEQ_ARB_WEIGHTED, SEQ_ARB_RANDOM, etc.
stop_sequencesKills 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

uvm_scoreboard Component
extends uvm_component

Checks DUT correctness by comparing actual outputs against expected values. Receives data via analysis ports from monitors.

Key Methods

MethodDescription
writeReceives a transaction from a connected analysis port
check_phasePerform end-of-test validation checks
report_phasePrint 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
endclass

Common 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

uvm_virtual_sequencer Component
extends uvm_sequencer

A sequencer that does not connect to a driver. Routes virtual sequences to multiple sub-sequencers in a multi-agent environment.

Key Methods

MethodDescription
build_phaseGet handles to actual sub-sequencers via config or hierarchy
startLaunch 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
endclass

Common 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

uvm_config_db Configuration

Type-safe static database for passing configuration objects and virtual interfaces across the component hierarchy.

Key Methods

MethodDescription
setStore a value: set(context, inst_path, field_name, value)
getRetrieve a value: get(context, inst_path, field_name, value) — returns 1 if found
existsCheck if a value exists without retrieving it
wait_modifiedBlock 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

uvm_resource_db Configuration

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

MethodDescription
setStore a resource: set(scope, name, value, accessor)
get_by_nameRetrieve a resource by scope and name
get_by_typeRetrieve a resource by scope and type
read_by_nameStatic convenience — returns value directly
write_by_nameStatic convenience — stores value directly
dumpPrint 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 internally

Common 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

uvm_factory Factory

Central singleton that manages type registration and overrides. Enables creating objects by type without hardcoding class names.

Key Methods

MethodDescription
create_object_by_typeCreate an object using the factory (internal — use type_id::create instead)
create_component_by_typeCreate a component using the factory (internal)
set_type_override_by_typeReplace all instances of one type with another globally
set_inst_override_by_typeReplace instances of a type at a specific hierarchy path
printPrint all registered types and active overrides
find_override_by_typeQuery 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();
end

Common 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

uvm_object Object

Base class for all UVM data and transaction objects. Provides core utilities for copying, comparing, printing, and packing.

Key Methods

MethodDescription
createCreates a new object of this type via the factory
cloneCreates and returns a deep copy of this object
copyCopies all fields from the given object to this one
compareDeep-compares this object with another, returns 1 if equal
printPrints all registered fields to the log
pack / unpackSerialize 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
endclass

Common 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

uvm_transaction Object
extends uvm_object

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

MethodDescription
accept_trCalled by a port to accept a transaction — marks begin time
begin_trMarks the beginning of a transaction for recording
end_trMarks the end of a transaction and triggers events
get_tr_handleReturns the integer handle for this recorded transaction
do_accept_tr / do_begin_tr / do_end_trUser 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
endclass

Common 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

uvm_phase Phasing
extends uvm_object

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");
endtask

Common 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

uvm_objection Phasing
extends uvm_object

Mechanism to coordinate phase completion. A phase ends only when all raised objections are dropped. Critical for run-time phases.

Key Methods

MethodDescription
raise_objectionIncrement objection count — prevents phase from ending
drop_objectionDecrement objection count — phase ends when count reaches 0
set_drain_timeAdd delay after last drop before phase actually ends
get_objection_countReturn current count for a component
get_objection_totalReturn 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
endtask

Common 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

uvm_reg_block Register
extends uvm_object

Top-level container for a register model. Groups registers, memories, and address maps to mirror DUT register space.

Key Methods

MethodDescription
buildPure virtual — create registers, memories, and address maps
create_mapCreate an address map with base address, bus width, and endianness
lock_modelFreeze the model after building — no more modifications allowed
configureSet 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
endclass

Common 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

uvm_reg Register
extends uvm_object

Models a single hardware register containing one or more fields. Supports front-door (bus) and back-door (HDL path) access.

Key Methods

MethodDescription
buildPure virtual — add fields to this register
configureSet parent block, HDL path, and regfile
readFront-door read via bus agent, or back-door via HDL path
writeFront-door write via bus agent, or back-door
getReturn the current desired (mirror) value without bus access
setSet the desired value without writing to DUT
mirrorRead DUT register and update the mirror, optionally check
predictUpdate mirror value without bus access
get_mirrored_valueReturn current mirrored value
resetReset 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 + compare

Common 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

uvm_reg_field Register
extends uvm_object

Models a single field within a register. Defines bit width, position, access policy, and reset value.

Key Methods

MethodDescription
configureSet parent reg, width, LSB position, access, volatility, reset value, has_reset, is_rand, individually_accessible
setSet the desired value of this field
getGet the current desired value
get_mirrored_valueGet the current mirrored value
get_resetGet the reset value of this field
read / writeFront-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, WO1

Common 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

uvm_reg_map Register
extends uvm_object

Defines the address space for a register block. Maps registers to offsets and connects to a bus agent via an adapter.

Key Methods

MethodDescription
add_regMap a register to a byte offset with access type
add_memMap a memory to a byte offset with access type
add_submapInclude another reg_map at a given base address
set_sequencerAssign the bus sequencer and adapter for front-door access
get_base_addrReturn the base address of this map
set_auto_predictEnable 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

uvm_reg_adapter Register
extends uvm_object

Converts between abstract register operations (uvm_reg_bus_op) and protocol-specific bus transactions. One adapter per bus protocol.

Key Methods

MethodDescription
reg2busConvert a register operation to a bus transaction — must override
bus2regConvert a bus response back to a register result — must override
supports_byte_enableOverride to return 1 if bus supports byte enables
provides_responsesOverride 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
endclass

Common 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

uvm_reg_predictor Register
extends uvm_component

Observes bus transactions via an analysis port and updates the register model mirror automatically. More accurate than auto-predict.

Key Methods

MethodDescription
bus_inAnalysis export — connect the monitor analysis port here
mapHandle to the register map being predicted
adapterHandle 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
endclass

Common 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

uvm_mem Register
extends uvm_object

Models a memory region in the DUT register space. Supports front-door and back-door read/write with configurable size and access.

Key Methods

MethodDescription
configureSet parent block, size (entries), width (bits), access, and HDL path
readRead a single memory location by offset
writeWrite a single memory location by offset
burst_readRead multiple consecutive locations
burst_writeWrite multiple consecutive locations
get_sizeReturn number of memory entries
get_n_bitsReturn 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

uvm_report_server Reporting

Singleton that collects all UVM messages (info, warning, error, fatal). Tracks counts and controls simulation exit on max errors.

Key Methods

MethodDescription
get_serverStatic method to get the global report server singleton
get_severity_countReturn total count of messages at a given severity
set_max_quit_countSet how many errors/fatals before simulation exits
get_max_quit_countGet current max quit count
report_summarizePrint 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 errors

Common 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

uvm_report_catcher Reporting
extends uvm_callback

Intercepts UVM messages before they are processed. Can modify, demote, promote, or suppress messages.

Key Methods

MethodDescription
catchOverride this — return CAUGHT to suppress, THROW to pass through
addStatic — register this catcher globally or for a specific component
get_severityGet the severity of the intercepted message
get_idGet the message ID string
get_messageGet the message text
set_severityChange the severity (demote/promote)
set_actionChange 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 = global

Common Mistakes

  • Returning CAUGHT for all messages — suppresses everything
  • Forgetting to return THROW for non-matching messages
  • Not registering the catcher with add()

Related Classes

uvm_sequence_item Sequence
extends uvm_transaction

Base class for transaction objects passed between sequences, sequencers, and drivers. Contains randomizable stimulus fields.

Key Methods

MethodDescription
newConstructor — takes only a name string (no parent)
do_copyOverride for custom deep-copy behavior
do_compareOverride for custom comparison logic
convert2stringReturn 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
endclass

Common 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

uvm_sequence Sequence
extends uvm_sequence_base

Generates ordered stimulus by creating, randomizing, and sending sequence items to a sequencer/driver pair.

Key Methods

MethodDescription
bodyMain sequence logic — override this to define stimulus
start_itemRequest sequencer access for an item (blocks until granted)
finish_itemSend item to driver and wait for item_done()
startLaunch this sequence on the given sequencer
pre_body / post_bodyHooks 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

uvm_sequence_library Sequence
extends uvm_sequence

A sequence that randomly selects and executes sequences from a registered pool. Useful for constrained-random regression testing.

Key Methods

MethodDescription
add_typewide_sequenceRegister a sequence type to all libraries of this type
add_typewide_sequencesRegister multiple sequence types at once
add_sequenceRegister a sequence type to this specific library instance
selection_modeControl 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_countMin/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

uvm_event Synchronization
extends uvm_object

A synchronization primitive for inter-component communication. Can be triggered and waited on, with optional data payload.

Key Methods

MethodDescription
triggerFire the event — all waiters are unblocked
wait_triggerBlock until the event is triggered
wait_trigger_dataBlock and retrieve the data payload when triggered
resetReset the event to untriggered state
is_onReturns 1 if event has been triggered (and not reset)
wait_ptriggerWait for persistent trigger — catches trigger even if already fired
get_trigger_dataReturn 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 ...
endtask

Common 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

uvm_event_pool Synchronization

Global associative array of named uvm_events. Allows components to share events by name without hierarchy references.

Key Methods

MethodDescription
get_global_poolStatic — returns the global event pool singleton
getGet or create an event by name (auto-creates if not found)
existsCheck if a named event exists in the pool
deleteRemove a named event from the pool
numReturn 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
endtask

Common 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

uvm_barrier Synchronization
extends uvm_object

A synchronization barrier that blocks all waiters until a specified number of processes arrive. Useful for multi-agent synchronization.

Key Methods

MethodDescription
set_thresholdSet how many processes must arrive before barrier opens
get_thresholdGet current threshold
wait_forBlock until threshold is reached — then all waiters proceed
resetReset the barrier — clears all current waiters
cancelCancel the barrier — unblock all waiters immediately
get_num_waitersReturn 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
endtask

Common 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

uvm_analysis_port TLM
extends uvm_port_base

One-to-many broadcast port. A single write() call delivers the transaction to all connected subscribers simultaneously.

Key Methods

MethodDescription
writeBroadcasts a transaction to every connected analysis export/imp
connectConnect 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 coverage

Common 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

uvm_subscriber TLM
extends uvm_component

Convenience base class that has a built-in analysis_export. Just override the write() method to receive transactions.

Key Methods

MethodDescription
writePure 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

uvm_analysis_imp TLM
extends uvm_port_base

Implementation port that receives transactions from an analysis port. The parent component must implement a write() function.

Key Methods

MethodDescription
writeCalled when a connected analysis port broadcasts a transaction — implement in parent component
newConstructor: 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
endclass

Common 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

uvm_tlm_fifo TLM
extends uvm_component

A FIFO buffer component with put and get TLM exports. Decouples producers from consumers with configurable depth.

Key Methods

MethodDescription
put_exportConnect a producer port here to put items into the FIFO
get_peek_exportConnect a consumer port here to get/peek items
putBlocking put — waits if FIFO is full
getBlocking get — waits if FIFO is empty
try_put / try_getNon-blocking versions that return 0 if unable
is_full / is_emptyCheck FIFO state
size / usedReturns max capacity / current occupancy
flushRemove 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
endclass

Common 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

uvm_tlm_analysis_fifo TLM
extends uvm_tlm_fifo

A TLM FIFO with an unbounded analysis_export that never blocks on write. Ideal for connecting monitors to scoreboards asynchronously.

Key Methods

MethodDescription
analysis_exportUnbounded write port — connect analysis_port here, never blocks
get_peek_exportConsumer side — get or peek items from the FIFO
getBlocking get — waits if FIFO is empty
try_getNon-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
endclass

Common 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

uvm_comparer Utility
extends uvm_object

Controls how uvm_object::compare() works. Configures comparison depth, verbosity, and which mismatches to report.

Key Methods

MethodDescription
compare_fieldCompare a single field by name, size, and radix
compare_stringCompare two strings
compare_objectDeep-compare two uvm_objects recursively
show_maxProperty — max number of mismatches to display (default 1)
verbosityProperty — UVM_LOW etc., controls when mismatches are printed
resultProperty — 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
endclass

Common 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

uvm_packer Utility
extends uvm_object

Serializes and deserializes uvm_objects to/from a bitstream. Used by pack/unpack methods for data transfer and comparison.

Key Methods

MethodDescription
pack_fieldPack a value of specified size into the bitstream
pack_stringPack a string (length-prefixed) into the bitstream
pack_objectRecursively pack an object and its fields
unpack_fieldExtract a value of specified size from the bitstream
unpack_stringExtract a string from the bitstream
unpack_objectRecursively unpack fields into an object
big_endianProperty — 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'hDEADBEEF

Common 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

uvm_printer Utility
extends uvm_object

Controls how uvm_object::print() and sprint() format output. UVM provides table, tree, and line printer variants.

Key Methods

MethodDescription
print_objectPrint an object using this printer's format
knobs.depthHow deep to recurse into sub-objects (-1 = unlimited)
knobs.referenceShow object reference IDs
knobs.full_nameShow full hierarchical names
knobs.indentNumber 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

uvm_callback Utility
extends uvm_object

Base class for callback objects. Callbacks let users inject custom behavior into existing components without modifying their source code.

Key Methods

MethodDescription
callback methodDefine virtual methods in your callback class — components call these at hook points
addStatic (via uvm_callbacks#(T,CB)) — register a callback with a component
deleteStatic — 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

uvm_cmdline_processor Utility

Singleton that parses simulation command-line arguments. Retrieve +args to control test behavior without recompilation.

Key Methods

MethodDescription
get_instStatic — return the singleton instance
get_arg_valueGet value of +name=value argument, returns count of matches
get_arg_valuesGet all values matching a +name= prefix into a queue
get_argsGet 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 timeout

Common 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

uvm_root Utility
extends uvm_component

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

MethodDescription
getStatic — returns the uvm_root singleton (also available as uvm_top)
run_testLaunch UVM phasing — call from initial block or use +UVM_TESTNAME
print_topologyPrint the complete component hierarchy tree
findFind a component by full hierarchical path
find_allFind all components matching a glob pattern
set_timeoutSet 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

Related Classes