What are registers ?
Registers are essential components in hardware designs, used to store configuration settings, control information, and status data. In modern designs, these registers are often accessed by software or firmware using bus protocols like AXI/APB and can be programmed with certain values. For example, there could be a 32-bit register with several individual fields within it. Each field represents a particular feature that can be configured by software when required.

The figure above is an example of a single register within the design with five different functional fields.
Bit Offset | Name | Read/Write | Width | Description |
---|---|---|---|---|
0 | En | RW | 1 | Enable. Set this bit to 1 to turn on the entire module, set it to 0 to disable |
1 | Mode | RW | 3 | Supports the following modes :
|
4 | Halt | RW | 1 | Halt. Set this bit to 1 to stop this module temporarily and set it to 0 to resume |
5 | Auto | RW | 1 | Auto shutdown mode. Set this bit to 1 to start auto shutdown after 5 min |
6 | Reserved | RO | 5 | Reserved for future additions |
11 | Speed | RW | 5 | Set a value to control the speed from 100 rpm to 2000 rpm. |
16 | Reserved | RO | 16 | Reserved for future additions |
The design files may have a module in RTL to implement these registers.
// RTL representation
module reg_block (...);
wire [31:0] reg_ctl;
// Declare reg variables to store register field values
reg ctl_en; // Enable for the module
reg [2:0] ctl_mode; // Mode
reg ctl_halt; // Halt
reg ctl_auto; // Auto shutdown
reg [4:0] ctl_speed; // Speed control
assign reg_ctl = {16'b0, ctl_speed, 5'b0, ctl_auto, ctl_halt, ctl_mode, ctl_en};
// Logic for getting individual fields from the bus
...
endmodule
To model registers using the UVM RAL, you create a register model class hierarchy that reflects the registers and their fields in your design. Each register corresponds to a class, and each field within the register corresponds to a field within that class. A register class is derived from uvm_reg
and a register field is derived from uvm_reg_field
.
What is a register block ?
A register block is a higher-level abstraction that represents a collection of registers and memory-mapped elements within a digital design. It provides a way to organize and encapsulate related registers, making it easier to manage and verify complex designs that consist of multiple registers and associated logic.
For example, REG_CTL could be placed at an offset address of 0x0 to emphasize that it is the main control register for the module. Because it takes 32 bits (4 bytes), the next register REG_STAT would be at 0x4 and hold the design's status related flags.
A register block class is derived from uvm_reg_block
base class in UVM.
What is a memory map ?
A memory map refers to the arrangement of memory and memory-mapped peripheral registers within the address space of the SoC's memory hierarchy. It defines the logical addresses at which various components, such as memory regions, registers, and peripherals, are accessible by the processor and other devices in the system.
For example, a System-On-Chip or SoC normally has one or more processor cores, DMA engines, bus network interconnects and many peripheral modules. Each peripheral module would have an associated register block and they are all laid out in a memory map. The processor would have access to these register blocks through a peripheral bus protocol like APB, or Wishbone. So each peripheral block would require a base address on which respective register blocks can reside.

Assume the register block described above to be a part of the Timer design module which has a base address of 0xE7B3_0000. In order to access REG_CTL of the Timer block, the core would have to send a transaction with an address of 0xE7B3_0000 since REG_CTL has a base address offset of 0x0. To access REG_DMACTL, the core would send a transaction with address of (0xE7B3_0000 + 0xC) because REG_DMACTL has an offset of 0xC.
What is Register Abstraction Layer ?
The purpose of Register Abstraction Layer or RAL is to provide a structured and standardized way to model and verify registers and memory-mapped structures within a digital design. Verification of register behavior can include testing different access scenarios, checking field values after resets, verifying register side-effects, and more.
It defines many base classes that abstract the read and write operations to registers and memories in a DUT, when properly extended. This allows many verification environments to be reused from block level to sub-system level environments to full chip or SoC testbenches without any modifications.
The register model object can be used in a UVM sequence to write or read from a target register.
class my_sequence extends uvm_sequence;
...
regmodel m_regmodel;
virtual task body();
// Get regmodel from config_db
// Use register model handle to write into the DUT register
m_regmodel.reg_ctl.write(uvm_status, 8'h3A);
// Use register model handle to read from the DUT register
m_regmodel.reg_ctl.read(uvm_status, rdata);
endtask
endclass
Why is RAL useful ?
It would be very cumbersome to write and read from registers without RAL. User will have to create a uvm_sequence_item
and execute the item on the targeted bus agent. Such code cannot be reused as easily as it is with RAL and there would be no good way to know the current state of the design at any point in time.
class write_sequence extends uvm_sequence;
int m_addr;
int m_wdata;
...
virtual task body();
bus_item m_item;
m_item = bus_item::type_id::create("my_item");
m_item.randomize() with { m.wdata == m_wdata;
m.write == 1;
m.addr == m_addr;
};
start_item(m_item);
...
endtask
endclass