UVM RAL – First Register Implementation (Part 1)

Step-by-step implementation of a 32-bit register in a UVM verification environment.

Objective

In this lesson, we implement a 32-bit DUT register named slave_reg_zero inside the verification environment using UVM RAL.

  • Width: 32 bits
  • Single field covering bits [31:0]
  • Read/Write access
  • Reset value = 0

Step 1 – Include Mandatory UVM Files

Before creating any RAL component, we must include:

  • uvm_macros.svh
  • uvm_pkg

These provide access to UVM base classes, macros, and RAL utilities.

Step 2 – Extend uvm_reg

Every register in UVM RAL must extend the uvm_reg class.

This base class provides:

  • Frontdoor and backdoor access methods
  • Prediction and mirroring support
  • Built-in register utilities

We also register the class with the factory:


class reg0 extends uvm_reg;
  `uvm_object_utils(reg0)

Step 3 – Declare the Register Field

Since this register has a single 32-bit field, we declare one uvm_reg_field.


rand uvm_reg_field slv_reg0;

The rand modifier allows randomization when calling randomize().

Step 4 – Constructor

The uvm_reg constructor requires:

  • Instance name
  • Total number of bits (including reserved bits)
  • Coverage option

function new(string name = "reg0");
  super.new(name, 32, UVM_NO_COVERAGE);
endfunction

We disable coverage for now using UVM_NO_COVERAGE.

Step 5 – Build and Configure the Field

Inside the build() method we:

  1. Create the field using the factory
  2. Configure its properties using configure()

Understanding configure()

The configure() function defines how the field behaves, matching DUT behavior exactly.

Arguments Explained:

  1. parent – Parent register (use this)
  2. size – Field width
  3. lsb_pos – Starting bit position
  4. access – "RW", "RO", etc.
  5. volatile – 0 = changes only on write
  6. reset – Expected reset value
  7. has_reset – Field supports reset
  8. is_rand – Field can be randomized
  9. individually_accessible – Independent field access

These parameters ensure correct prediction and mirroring behavior.

Complete Example


`include "uvm_macros.svh"
import uvm_pkg::*;

// =============================================
// Register Class
// =============================================
class reg0 extends uvm_reg;

  `uvm_object_utils(reg0)

  rand uvm_reg_field slv_reg0;

  function new(string name = "reg0");
    super.new(name, 32, UVM_NO_COVERAGE);
  endfunction

  function void build;

    slv_reg0 = uvm_reg_field::type_id::create("slv_reg0");

    slv_reg0.configure(
      .parent(this),
      .size(32),
      .lsb_pos(0),
      .access("RW"),
      .volatile(0),
      .reset('h0),
      .has_reset(1),
      .is_rand(1),
      .individually_accessible(1)
    );

  endfunction

endclass


// =============================================
// Testbench
// =============================================
module tb;

  reg0 r1;

  initial begin
    r1 = new("r1");
    r1.build();

    if (r1.randomize())
      $display("Register randomized successfully");
  end

endmodule

Run This Example on EDA Playground

Execute this example directly in your browser.

▶ Run on EDA Playground
Summary
  • Registers extend uvm_reg
  • Fields extend uvm_reg_field
  • configure() defines DUT behavior
  • All 9 parameters must match DUT specification
  • Accurate configuration ensures correct mirroring and prediction

Proper field configuration is the foundation of a robust UVM RAL model.