UVM Complete Cheat Sheet

Quick Reference Guide with Key Points and Code Snippets

Your one-stop UVM reference for rapid development

Table of Contents

  1. UVM Class Hierarchy
  2. UVM Phases
  3. Transaction and Sequence
  4. Driver
  5. Monitor
  6. Sequencer
  7. Agent
  8. Scoreboard
  9. Environment
  10. Test
  11. Configuration
  12. Factory
  13. TLM Ports
  14. Macros
  15. Quick Patterns

1. UVM Class Hierarchy

Key Concepts

  • uvm_object: Data items (transactions, configs)
  • uvm_component: Structural hierarchy (driver, monitor, etc.)
  • uvm_sequence: Stimulus generation

Quick Reference

uvm_void
  └── uvm_object
        ├── uvm_transaction
        │     └── uvm_sequence_item
        │           └── YOUR_TRANSACTION
        ├── uvm_sequence
        │     └── YOUR_SEQUENCE
        ├── uvm_component
        │     ├── uvm_driver
        │     │     └── YOUR_DRIVER
        │     ├── uvm_monitor
        │     │     └── YOUR_MONITOR
        │     ├── uvm_sequencer
        │     │     └── YOUR_SEQUENCER
        │     ├── uvm_agent
        │     │     └── YOUR_AGENT
        │     ├── uvm_scoreboard
        │     │     └── YOUR_SCOREBOARD
        │     ├── uvm_env
        │     │     └── YOUR_ENV
        │     └── uvm_test
        │           └── YOUR_TEST
        └── uvm_config (user-defined)

2. UVM Phases

Phase Execution Order

BUILD PHASES (Function, Bottom-Up):
├── build_phase()           - Create components
├── connect_phase()         - Connect TLM ports
├── end_of_elaboration()    - Topology checks
└── start_of_simulation()   - Display info

RUN PHASE (Task, Parallel):
└── run_phase()             - Main execution
    OR fine-grained:
    ├── pre_reset_phase()
    ├── reset_phase()
    ├── post_reset_phase()
    ├── pre_configure_phase()
    ├── configure_phase()
    ├── post_configure_phase()
    ├── pre_main_phase()
    ├── main_phase()
    ├── post_main_phase()
    ├── pre_shutdown_phase()
    ├── shutdown_phase()
    └── post_shutdown_phase()

POST-RUN PHASES (Function, Bottom-Up):
├── extract_phase()         - Extract coverage
├── check_phase()           - Check results
├── report_phase()          - Print reports
└── final_phase()           - Cleanup (Top-Down)

Phase Code Snippets

// Build phase (create components)
function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  agent = apb_agent::type_id::create("agent", this);
endfunction

// Connect phase (connect ports)
function void connect_phase(uvm_phase phase);
  super.connect_phase(phase);
  driver.seq_item_port.connect(seqr.seq_item_export);
endfunction

// Run phase (with objections)
task run_phase(uvm_phase phase);
  phase.raise_objection(this);
  // Do work
  repeat(100) @(posedge vif.clk);
  phase.drop_objection(this);
endtask

// Report phase
function void report_phase(uvm_phase phase);
  super.report_phase(phase);
  `uvm_info("REPORT", $sformatf("Test %s", 
    (errors==0)?"PASSED":"FAILED"), UVM_LOW)
endfunction

Key Points:

  • Call super.xxx_phase() FIRST in build/connect (bottom-up)
  • Call super.xxx_phase() LAST in final_phase (top-down)
  • Use objections in run_phase to control when it ends
  • Match every raise_objection() with drop_objection()

3. Transaction and Sequence

Transaction Template

class apb_transaction extends uvm_sequence_item;
  
  // Data members
  rand bit [31:0] addr;
  rand bit [31:0] wdata;
  rand bit        write;
       bit [31:0] rdata;
  
  // Constraints
  constraint addr_c {
    addr inside {[32'h0000:32'hFFFF]};
  }
  
  // Factory registration
  `uvm_object_utils_begin(apb_transaction)
    `uvm_field_int(addr,  UVM_ALL_ON)
    `uvm_field_int(wdata, UVM_ALL_ON)
    `uvm_field_int(write, UVM_ALL_ON)
    `uvm_field_int(rdata, UVM_ALL_ON)
  `uvm_object_utils_end
  
  function new(string name = "apb_transaction");
    super.new(name);
  endfunction
  
endclass

Sequence Template

class apb_sequence extends uvm_sequence#(apb_transaction);
  `uvm_object_utils(apb_sequence)
  
  function new(string name = "apb_sequence");
    super.new(name);
  endfunction
  
  task body();
    apb_transaction req;
    
    repeat(10) begin
      req = apb_transaction::type_id::create("req");
      start_item(req);  // Get grant [BLOCKS]
      assert(req.randomize());
      finish_item(req); // Send txn [BLOCKS]
    end
  endtask
  
  // Optional: Objection handling
  task pre_body();
    if (starting_phase != null)
      starting_phase.raise_objection(this);
  endtask
  
  task post_body();
    if (starting_phase != null)
      starting_phase.drop_objection(this);
  endtask
  
endclass

Key Points:

  • start_item(req) – Request grant, BLOCKS until granted
  • randomize() – Between start_item and finish_item
  • finish_item(req) – Send transaction, BLOCKS until done
  • Use pre_body()/post_body() for automatic objection handling

4. Driver

Driver Template

class apb_driver extends uvm_driver#(apb_transaction);
  `uvm_component_utils(apb_driver)
  
  virtual apb_if vif;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db#(virtual apb_if)::get(this, "", "vif", vif))
      `uvm_fatal("DRIVER", "No virtual interface!")
  endfunction
  
  task run_phase(uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);  // [BLOCKS]
      drive_transaction(req);
      seq_item_port.item_done();         // Signal complete
    end
  endtask
  
  task drive_transaction(apb_transaction txn);
    @(posedge vif.pclk);
    vif.paddr  <= txn.addr;
    vif.pwdata <= txn.wdata;
    vif.pwrite <= txn.write;
    vif.psel   <= 1;
    vif.penable <= 0;
    
    @(posedge vif.pclk);
    vif.penable <= 1;
    wait(vif.pready);
    
    if (!txn.write)
      txn.rdata = vif.prdata;
    
    @(posedge vif.pclk);
    vif.psel <= 0;
    vif.penable <= 0;
  endtask
  
endclass

Key Points:

  • Get VIF from config_db in build_phase
  • Use get_next_item(req) – BLOCKS until transaction available
  • Call item_done() after driving
  • Alternative: try_next_item(req) – non-blocking, returns null if no txn

5. Monitor

Monitor Template

class apb_monitor extends uvm_monitor;
  `uvm_component_utils(apb_monitor)
  
  virtual apb_if vif;
  uvm_analysis_port#(apb_transaction) ap;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db#(virtual apb_if)::get(this, "", "vif", vif))
      `uvm_fatal("MON", "No VIF!")
    ap = new("ap", this);
  endfunction
  
  task run_phase(uvm_phase phase);
    forever begin
      collect_transaction();
    end
  endtask
  
  task collect_transaction();
    apb_transaction txn;
    
    @(posedge vif.pclk);
    if (vif.psel && !vif.penable) begin
      txn = apb_transaction::type_id::create("txn");
      
      // Capture setup phase
      txn.addr = vif.paddr;
      txn.write = vif.pwrite;
      if (txn.write)
        txn.wdata = vif.pwdata;
      
      // Wait for access phase
      @(posedge vif.pclk);
      wait(vif.pready);
      
      if (!txn.write)
        txn.rdata = vif.prdata;
      
      // Broadcast to subscribers
      ap.write(txn);
    end
  endtask
  
endclass

Key Points:

  • Create analysis_port in build_phase
  • Observe VIF, reconstruct transaction
  • Broadcast via ap.write(txn) – non-blocking
  • Don’t modify DUT, only observe

6. Sequencer

Sequencer Template

class apb_sequencer extends uvm_sequencer#(apb_transaction);
  `uvm_component_utils(apb_sequencer)
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
endclass

// Usually no custom code needed!
// Handles:
// - Arbitration between sequences
// - Transaction queuing
// - Grant/done signaling

Key Points:

  • Usually just inherit from uvm_sequencer#(TXN_TYPE)
  • No custom code needed in most cases
  • Handles arbitration automatically
  • Provides seq_item_export for driver connection

7. Agent

Agent Template

class apb_agent extends uvm_agent;
  `uvm_component_utils(apb_agent)
  
  apb_sequencer seqr;
  apb_driver    drv;
  apb_monitor   mon;
  apb_config    cfg;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    
    // Get configuration
    if (!uvm_config_db#(apb_config)::get(this, "", "cfg", cfg))
      `uvm_fatal("AGENT", "No config!")
    
    // Always create monitor
    mon = apb_monitor::type_id::create("mon", this);
    
    // Create active components if needed
    if (cfg.is_active == UVM_ACTIVE) begin
      seqr = apb_sequencer::type_id::create("seqr", this);
      drv = apb_driver::type_id::create("drv", this);
    end
  endfunction
  
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    
    if (cfg.is_active == UVM_ACTIVE) begin
      drv.seq_item_port.connect(seqr.seq_item_export);
    end
  endfunction
  
endclass

Key Points:

  • Contains sequencer, driver, monitor
  • Check is_active before creating driver/sequencer
  • Monitor always present (passive mode = monitor only)
  • Connect driver to sequencer in connect_phase

8. Scoreboard

Scoreboard Template

class apb_scoreboard extends uvm_scoreboard;
  `uvm_component_utils(apb_scoreboard)
  
  uvm_analysis_imp#(apb_transaction, apb_scoreboard) analysis_imp;
  
  int match_count = 0;
  int mismatch_count = 0;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    analysis_imp = new("analysis_imp", this);
  endfunction
  
  // Called by monitor's analysis_port
  virtual function void write(apb_transaction txn);
    apb_transaction expected;
    
    // Get expected from reference model
    expected = predict(txn);
    
    // Compare
    if (txn.compare(expected)) begin
      match_count++;
      `uvm_info("SCBD", "MATCH", UVM_HIGH)
    end else begin
      mismatch_count++;
      `uvm_error("SCBD", $sformatf("MISMATCH: exp=%h act=%h", 
                 expected.data, txn.data))
    end
  endfunction
  
  function apb_transaction predict(apb_transaction txn);
    // Reference model logic
    apb_transaction exp = new();
    // ... prediction logic
    return exp;
  endfunction
  
  function void report_phase(uvm_phase phase);
    super.report_phase(phase);
    `uvm_info("SCBD_REPORT", 
      $sformatf("Matches: %0d, Mismatches: %0d", 
                match_count, mismatch_count), UVM_LOW)
  endfunction
  
endclass

Key Points:

  • Use uvm_analysis_imp to receive transactions
  • Implement write() function (called by monitor)
  • Compare actual vs expected (reference model)
  • Report statistics in report_phase

9. Environment

Environment Template

class apb_env extends uvm_env;
  `uvm_component_utils(apb_env)
  
  apb_agent      agent;
  apb_scoreboard scbd;
  apb_coverage   cov;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    
    agent = apb_agent::type_id::create("agent", this);
    scbd  = apb_scoreboard::type_id::create("scbd", this);
    cov   = apb_coverage::type_id::create("cov", this);
  endfunction
  
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    
    // Connect monitor to scoreboard
    agent.mon.ap.connect(scbd.analysis_imp);
    
    // Connect monitor to coverage
    agent.mon.ap.connect(cov.analysis_export);
  endfunction
  
endclass

Key Points:

  • Contains agents, scoreboard, coverage
  • Create all in build_phase
  • Connect analysis ports in connect_phase
  • One environment per DUT or protocol

10. Test

Test Template

class apb_test extends uvm_test;
  `uvm_component_utils(apb_test)
  
  apb_env env;
  apb_config cfg;
  virtual apb_if vif;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    
    // Get VIF from top module
    if (!uvm_config_db#(virtual apb_if)::get(this, "", "vif", vif))
      `uvm_fatal("TEST", "No VIF!")
    
    // Create and configure
    cfg = apb_config::type_id::create("cfg");
    cfg.vif = vif;
    cfg.is_active = UVM_ACTIVE;
    
    // Set config for agent
    uvm_config_db#(apb_config)::set(this, "env.agent", "cfg", cfg);
    
    // Create environment
    env = apb_env::type_id::create("env", this);
  endfunction
  
  task run_phase(uvm_phase phase);
    apb_sequence seq;
    
    phase.raise_objection(this);
    
    seq = apb_sequence::type_id::create("seq");
    seq.start(env.agent.seqr);
    
    #100ns; // Drain time
    
    phase.drop_objection(this);
  endtask
  
endclass

Key Points:

  • Top-level component in UVM hierarchy
  • Get VIF from config_db
  • Create and distribute configuration
  • Set factory overrides here
  • Start sequences in run_phase
  • Manage objections

11. Configuration

Config Object Template

class apb_config extends uvm_object;
  `uvm_object_utils(apb_config)
  
  virtual apb_if vif;
  uvm_active_passive_enum is_active = UVM_ACTIVE;
  int num_trans = 100;
  bit checks_enable = 1;
  bit coverage_enable = 1;
  
  function new(string name = "apb_config");
    super.new(name);
  endfunction
endclass

Config DB Usage

// SET configuration (in test/top)
uvm_config_db#(TYPE)::set(
  this,              // Context (uvm_component)
  "path.to.comp",    // Instance path (use wildcards)
  "field_name",      // Field identifier
  value);            // Value to set

// Example
uvm_config_db#(apb_config)::set(this, "env.agent*", "cfg", cfg);
uvm_config_db#(virtual apb_if)::set(null, "uvm_test_top", "vif", vif);

// GET configuration (in components)
if (!uvm_config_db#(TYPE)::get(
      this,           // Context
      "",             // Instance ("" = this level)
      "field_name",   // Field identifier
      value))         // Variable to receive value
  `uvm_fatal("TAG", "Config not found!")

// Example
if (!uvm_config_db#(apb_config)::get(this, "", "cfg", cfg))
  `uvm_fatal("AGENT", "No config!")

Key Points:

  • Set config BEFORE creating components
  • Most specific path wins (wildcards: **.agent*)
  • Always check get() return value
  • VIF must be set in top module before run_test()

12. Factory

Factory Registration

// Register object
class apb_transaction extends uvm_sequence_item;
  `uvm_object_utils(apb_transaction)
  // ...
endclass

// Register component
class apb_driver extends uvm_driver#(apb_transaction);
  `uvm_component_utils(apb_driver)
  // ...
endclass

Factory Creation

// Create via factory (enables overrides)
comp = apb_driver::type_id::create("drv", this);  // Component
obj  = apb_transaction::type_id::create("req");   // Object

// DON'T use new() directly (bypasses factory)
// comp = new("drv", this);  // BAD - can't override!

Factory Override

// Type override (affects ALL instances)
function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  
  // By type
  apb_driver::type_id::set_type_override(
    enhanced_apb_driver::get_type());
  
  // By name
  set_type_override_by_name("apb_driver", "enhanced_apb_driver");
  
  // Create components (will use override)
  env = apb_env::type_id::create("env", this);
endfunction

// Instance override (specific instance only)
set_inst_override_by_type(
  "env.master_agent.drv",        // Instance path
  apb_driver::get_type(),        // Original type
  debug_apb_driver::get_type()); // Override type

// Debug factory
factory.print();  // Print all overrides

Key Points:

  • Always use type_id::create(), never new()
  • Set overrides BEFORE creating components
  • Type override: all instances replaced
  • Instance override: specific path only
  • Instance override takes precedence over type override

13. TLM Ports

TLM Port Types

// Port Types:
// - uvm_analysis_port      (1→N broadcast)
// - uvm_seq_item_pull_port (get/put, blocking)
// - uvm_blocking_put_port  (blocking put)
// - uvm_blocking_get_port  (blocking get)

// Analysis Port (Monitor → Scoreboard/Coverage)
class monitor;
  uvm_analysis_port#(txn_t) ap;
  
  function void build_phase(uvm_phase phase);
    ap = new("ap", this);
  endfunction
  
  task run_phase(uvm_phase phase);
    ap.write(txn);  // Broadcast to all connected
  endtask
endclass

class scoreboard;
  uvm_analysis_imp#(txn_t, scoreboard) analysis_imp;
  
  function void build_phase(uvm_phase phase);
    analysis_imp = new("analysis_imp", this);
  endfunction
  
  function void write(txn_t txn);
    // Called when monitor does ap.write(txn)
  endfunction
endclass

// Connection
monitor.ap.connect(scoreboard.analysis_imp);

// Multiple subscribers
uvm_analysis_imp_decl(_scbd)
uvm_analysis_imp_decl(_cov)

class scoreboard;
  uvm_analysis_imp_scbd#(txn_t, scoreboard) scbd_imp;
  uvm_analysis_imp_cov#(txn_t, scoreboard) cov_imp;
  
  function void write_scbd(txn_t txn);
    // From scoreboard connection
  endfunction
  
  function void write_cov(txn_t txn);
    // From coverage connection
  endfunction
endclass

Key Points:

  • analysis_port: 1-to-many, non-blocking broadcast
  • seq_item_port: 1-to-1, blocking get/put
  • Port in producer, Export/Imp in consumer
  • Connect in connect_phase

14. UVM Macros

Essential Macros

//=============================================================================
// Registration Macros
//=============================================================================

// Object registration (minimal)
`uvm_object_utils(apb_transaction)

// Object with field automation
`uvm_object_utils_begin(apb_transaction)
  `uvm_field_int(addr, UVM_ALL_ON)
  `uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end

// Component registration
`uvm_component_utils(apb_driver)

//=============================================================================
// Messaging Macros
//=============================================================================

`uvm_info(ID, MSG, VERBOSITY)
`uvm_warning(ID, MSG)
`uvm_error(ID, MSG)
`uvm_fatal(ID, MSG)

// Examples
`uvm_info("DRIVER", "Driving transaction", UVM_HIGH)
`uvm_error("SCBD", $sformatf("Mismatch: exp=%h act=%h", exp, act))
`uvm_fatal("BUILD", "Component creation failed!")

// Verbosity levels: UVM_NONE, UVM_LOW, UVM_MEDIUM, UVM_HIGH, UVM_FULL, UVM_DEBUG

//=============================================================================
// Sequence Macros
//=============================================================================

// Simple sequence item generation
`uvm_do(req)
// Equivalent to:
//   start_item(req);
//   assert(req.randomize());
//   finish_item(req);

// With inline constraints
`uvm_do_with(req, {addr < 100; write == 1;})

// Create and do in one step
`uvm_create(req)
// Creates: req = type::create("req")

// Send on specific sequencer
`uvm_do_on(req, seqr)

// Priority sequencing
`uvm_do_pri(req, priority)

//=============================================================================
// Field Macros
//=============================================================================

// Field automation flags
UVM_ALL_ON      // All operations
UVM_COPY        // Enable copy
UVM_COMPARE     // Enable compare
UVM_PRINT       // Enable print
UVM_PACK        // Enable pack/unpack
UVM_DEFAULT     // Default set
UVM_NOCOMPARE   // Disable compare
UVM_NOPRINT     // Disable print

`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_object(sub_obj, UVM_ALL_ON)
`uvm_field_array_int(array, UVM_ALL_ON)
`uvm_field_queue_int(queue, UVM_ALL_ON)
`uvm_field_enum(state_t, state, UVM_ALL_ON)
`uvm_field_string(name, UVM_ALL_ON)

Key Macro Patterns:

// Typical transaction
class my_txn extends uvm_sequence_item;
  rand bit [7:0] addr;
  rand bit [31:0] data;
  
  `uvm_object_utils_begin(my_txn)
    `uvm_field_int(addr, UVM_ALL_ON)
    `uvm_field_int(data, UVM_ALL_ON)
  `uvm_object_utils_end
  
  function new(string name = "my_txn");
    super.new(name);
  endfunction
endclass

// Typical component
class my_comp extends uvm_component;
  `uvm_component_utils(my_comp)
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    // Build code
  endfunction
endclass

15. Quick Patterns

15.1 Complete Minimal UVM Testbench

//=============================================================================
// Transaction
//=============================================================================
class txn extends uvm_sequence_item;
  rand bit [7:0] addr;
  rand bit [31:0] data;
  `uvm_object_utils_begin(txn)
    `uvm_field_int(addr, UVM_ALL_ON)
    `uvm_field_int(data, UVM_ALL_ON)
  `uvm_object_utils_end
  function new(string name = "txn");
    super.new(name);
  endfunction
endclass

//=============================================================================
// Sequence
//=============================================================================
class seq extends uvm_sequence#(txn);
  `uvm_object_utils(seq)
  function new(string name = "seq");
    super.new(name);
  endfunction
  
  task body();
    repeat(10) `uvm_do(req)
  endtask
endclass

//=============================================================================
// Driver
//=============================================================================
class drv extends uvm_driver#(txn);
  `uvm_component_utils(drv)
  virtual dut_if vif;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db#(virtual dut_if)::get(this, "", "vif", vif))
      `uvm_fatal("DRV", "No VIF!")
  endfunction
  
  task run_phase(uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);
      @(posedge vif.clk);
      vif.addr <= req.addr;
      vif.data <= req.data;
      seq_item_port.item_done();
    end
  endtask
endclass

//=============================================================================
// Monitor
//=============================================================================
class mon extends uvm_monitor;
  `uvm_component_utils(mon)
  virtual dut_if vif;
  uvm_analysis_port#(txn) ap;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db#(virtual dut_if)::get(this, "", "vif", vif))
      `uvm_fatal("MON", "No VIF!")
    ap = new("ap", this);
  endfunction
  
  task run_phase(uvm_phase phase);
    forever begin
      txn t = txn::type_id::create("t");
      @(posedge vif.clk);
      t.addr = vif.addr;
      t.data = vif.data;
      ap.write(t);
    end
  endtask
endclass

//=============================================================================
// Agent
//=============================================================================
class agt extends uvm_agent;
  `uvm_component_utils(agt)
  drv d;
  mon m;
  uvm_sequencer#(txn) seqr;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    d = drv::type_id::create("d", this);
    m = mon::type_id::create("m", this);
    seqr = uvm_sequencer#(txn)::type_id::create("seqr", this);
  endfunction
  
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    d.seq_item_port.connect(seqr.seq_item_export);
  endfunction
endclass

//=============================================================================
// Environment
//=============================================================================
class env extends uvm_env;
  `uvm_component_utils(env)
  agt agent;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    agent = agt::type_id::create("agent", this);
  endfunction
endclass

//=============================================================================
// Test
//=============================================================================
class test extends uvm_test;
  `uvm_component_utils(test)
  env e;
  
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    e = env::type_id::create("e", this);
  endfunction
  
  task run_phase(uvm_phase phase);
    seq s = seq::type_id::create("s");
    phase.raise_objection(this);
    s.start(e.agent.seqr);
    phase.drop_objection(this);
  endtask
endclass

//=============================================================================
// Top Module
//=============================================================================
module top;
  logic clk;
  dut_if dut_if_inst(clk);
  dut dut_inst(dut_if_inst);
  
  initial begin
    uvm_config_db#(virtual dut_if)::set(null, "uvm_test_top", "vif", dut_if_inst);
    run_test("test");
  end
  
  initial begin
    clk = 0;
    forever #5ns clk = ~clk;
  end
endmodule

15.2 Sequence-Driver-Sequencer Handshake

// SEQUENCE side:
task body();
  req = txn::type_id::create("req");
  start_item(req);           // ① Request grant [BLOCKS]
  assert(req.randomize());   // ② Randomize after grant
  finish_item(req);          // ③ Send txn [BLOCKS until done]
endtask

// SEQUENCER side (automatic):
// - Receives request from sequence
// - Arbitrates if multiple sequences
// - Grants access to sequence
// - Queues transaction for driver
// - Signals driver
// - Waits for done from driver
// - Signals sequence completion

// DRIVER side:
task run_phase(uvm_phase phase);
  forever begin
    seq_item_port.get_next_item(req);  // ④ Get txn [BLOCKS]
    drive_txn(req);                    // ⑤ Drive DUT
    seq_item_port.item_done();         // ⑥ Signal done
  end
endtask

15.3 Top Module Pattern

module top;
  
  // Clock
  logic clk = 0;
  always #5ns clk = ~clk;
  
  // Interface
  apb_if apb_if_inst(clk);
  
  // DUT
  apb_slave dut(
    .pclk(apb_if_inst.pclk),
    .preset_n(apb_if_inst.preset_n),
    .paddr(apb_if_inst.paddr),
    .psel(apb_if_inst.psel),
    .penable(apb_if_inst.penable),
    .pwrite(apb_if_inst.pwrite),
    .pwdata(apb_if_inst.pwdata),
    .prdata(apb_if_inst.prdata),
    .pready(apb_if_inst.pready)
  );
  
  // UVM
  initial begin
    // Set VIF in config_db
    uvm_config_db#(virtual apb_if)::set(
      null, 
      "uvm_test_top", 
      "vif", 
      apb_if_inst);
    
    // Run test
    run_test("apb_test");
  end
  
endmodule

Quick Reference Tables

UVM Component Checklist

ComponentExtendsKey MethodsTLM Ports
Transactionuvm_sequence_itemrandomize()
Sequenceuvm_sequencebody(), pre_body(), post_body()
Driveruvm_driverrun_phase(), drive_txn()seq_item_port
Monitoruvm_monitorrun_phase(), collect()analysis_port
Sequenceruvm_sequencer(none usually)seq_item_export
Agentuvm_agentbuild(), connect()
Scoreboarduvm_scoreboardwrite(), check()analysis_imp
Coverageuvm_subscriberwrite()analysis_export
Environmentuvm_envbuild(), connect()
Testuvm_testbuild(), run_phase()

Phase Order Quick Ref

PhaseTypeDirectionPurpose
buildFunctionBottom-upCreate components
connectFunctionBottom-upConnect ports
end_of_elaborationFunctionBottom-upChecks
start_of_simulationFunctionBottom-upDisplay
runTaskParallelMain test
extractFunctionBottom-upGet stats
checkFunctionBottom-upVerify
reportFunctionBottom-upPrint report
finalFunctionTop-downCleanup

Common Code Patterns

// Pattern 1: Get from config_db
if (!uvm_config_db#(TYPE)::get(this, "", "name", var))
  `uvm_fatal("TAG", "Not found!")

// Pattern 2: Set to config_db
uvm_config_db#(TYPE)::set(this, "path", "name", value);

// Pattern 3: Create via factory
comp = TYPE::type_id::create("name", this);

// Pattern 4: Sequence execution
seq = SEQ_TYPE::type_id::create("seq");
seq.start(seqr);

// Pattern 5: Objection management
phase.raise_objection(this);
// Do work
phase.drop_objection(this);

// Pattern 6: Analysis port broadcast
ap.write(txn);

// Pattern 7: Connect ports
port.connect(export);

Command-Line Options

# Run specific test
vsim top +UVM_TESTNAME=apb_test

# Set verbosity
+UVM_VERBOSITY=UVM_HIGH
+UVM_VERBOSITY=UVM_LOW

# Timeout
+UVM_TIMEOUT=1000000

# Set config from command line
+uvm_set_config_int=*,num_trans,500
+uvm_set_config_string=*,test_name,"my_test"

# Factory override
+uvm_set_type_override=apb_driver,enhanced_driver

# Config DB trace
+UVM_CONFIG_DB_TRACE

# Factory trace
+UVM_FACTORY_TRACE

# Phase trace
+UVM_PHASE_TRACE

# Objection trace
+UVM_OBJECTION_TRACE

Summary – UVM in 1 Page

//=============================================================================
// COMPLETE UVM TESTBENCH IN ONE VIEW
//=============================================================================

// 1. TRANSACTION (data)
class txn extends uvm_sequence_item;
  rand bit[7:0] addr;
  `uvm_object_utils(txn)
endclass

// 2. SEQUENCE (generate transactions)
class seq extends uvm_sequence#(txn);
  `uvm_object_utils(seq)
  task body();
    repeat(10) `uvm_do(req)
  endtask
endclass

// 3. DRIVER (drive DUT)
class drv extends uvm_driver#(txn);
  `uvm_component_utils(drv)
  virtual dut_if vif;
  task run_phase(uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);
      @(posedge vif.clk); vif.addr <= req.addr;
      seq_item_port.item_done();
    end
  endtask
endclass

// 4. MONITOR (observe DUT)
class mon extends uvm_monitor;
  `uvm_component_utils(mon)
  uvm_analysis_port#(txn) ap;
  task run_phase(uvm_phase phase);
    forever begin
      @(posedge vif.clk);
      t = txn::type_id::create("t");
      t.addr = vif.addr;
      ap.write(t);
    end
  endtask
endclass

// 5. SEQUENCER (mediator)
typedef uvm_sequencer#(txn) seqr;

// 6. AGENT (container)
class agt extends uvm_agent;
  drv d; mon m; seqr s;
  `uvm_component_utils(agt)
  function void build_phase(uvm_phase phase);
    d = drv::type_id::create("d", this);
    m = mon::type_id::create("m", this);
    s = seqr::type_id::create("s", this);
  endfunction
  function void connect_phase(uvm_phase phase);
    d.seq_item_port.connect(s.seq_item_export);
  endfunction
endclass

// 7. SCOREBOARD (check)
class scbd extends uvm_scoreboard;
  `uvm_component_utils(scbd)
  uvm_analysis_imp#(txn, scbd) imp;
  function void write(txn t);
    // Check transaction
  endfunction
endclass

// 8. ENVIRONMENT (integration)
class env extends uvm_env;
  agt agent; scbd sb;
  `uvm_component_utils(env)
  function void build_phase(uvm_phase phase);
    agent = agt::type_id::create("agent", this);
    sb = scbd::type_id::create("sb", this);
  endfunction
  function void connect_phase(uvm_phase phase);
    agent.m.ap.connect(sb.imp);
  endfunction
endclass

// 9. TEST (top-level)
class test extends uvm_test;
  env e;
  `uvm_component_utils(test)
  function void build_phase(uvm_phase phase);
    e = env::type_id::create("e", this);
  endfunction
  task run_phase(uvm_phase phase);
    seq s = seq::type_id::create("s");
    phase.raise_objection(this);
    s.start(e.agent.s);
    phase.drop_objection(this);
  endtask
endclass

// 10. TOP MODULE
module top;
  dut_if dif(clk);
  dut dut_inst(dif);
  initial begin
    uvm_config_db#(virtual dut_if)::set(null, "*", "vif", dif);
    run_test("test");
  end
endmodule

Common Mistakes to Avoid

// ❌ DON'T: Use new() directly
drv = new("drv", this);

// ✅ DO: Use factory
drv = apb_driver::type_id::create("drv", this);


// ❌ DON'T: Create before setting config
env = apb_env::type_id::create("env", this);
uvm_config_db#(cfg)::set(this, "env", "cfg", cfg);

// ✅ DO: Set config before creating
uvm_config_db#(cfg)::set(this, "env", "cfg", cfg);
env = apb_env::type_id::create("env", this);


// ❌ DON'T: Forget objections
task run_phase(uvm_phase phase);
  seq.start(seqr);  // Phase ends immediately!
endtask

// ✅ DO: Use objections
task run_phase(uvm_phase phase);
  phase.raise_objection(this);
  seq.start(seqr);
  phase.drop_objection(this);
endtask


// ❌ DON'T: Ignore get() return value
uvm_config_db#(vif)::get(this, "", "vif", vif);

// ✅ DO: Check return value
if (!uvm_config_db#(vif)::get(this, "", "vif", vif))
  `uvm_fatal("TAG", "VIF not found!")


// ❌ DON'T: Call super last in build
function void build_phase(uvm_phase phase);
  comp = my_comp::type_id::create("comp", this);
  super.build_phase(phase);  // Too late!
endfunction

// ✅ DO: Call super FIRST in build
function void build_phase(uvm_phase phase);
  super.build_phase(phase);  // First!
  comp = my_comp::type_id::create("comp", this);
endfunction

UVM Execution Flow Summary

1. Top module:
   - Create interface
   - Set VIF in config_db
   - run_test("test_name")

2. UVM starts test:
   - Create test component

3. build_phase (bottom-up):
   - Create all components
   - Get config_db values

4. connect_phase (bottom-up):
   - Connect TLM ports

5. end_of_elaboration:
   - Print topology

6. start_of_simulation:
   - Print banners

7. run_phase (parallel):
   - All components run simultaneously
   - Sequences generate stimulus
   - Driver drives DUT
   - Monitor observes DUT
   - Controlled by objections

8. extract_phase:
   - Collect coverage/stats

9. check_phase:
   - Verify results

10. report_phase:
    - Print reports

11. final_phase:
    - Cleanup

12. $finish

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top