What is the UVM register layer ?

The UVM register layer classes are used to create a high-level, object-oriented model for memory-mapped registers and memories in a design under verification (DUV). The register layer defines many base classes which can be extended appropriately to abstract read and write operations to the DUV. Before we go into the details of UVM register layer, let's first review how registers are organized and how they function in a digital design.

What are registers ?

Most digital design blocks have software controllable registers that can be accessed via a peripheral bus. These registers allow the hardware to behave in certain ways when 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.


hardware-register-example

The figure above is an example of a single register within the design with five different functional fields. Field properties may be specified by the designer as below.

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 :
  • Low Energy : 000
  • Medium Energy : 001
  • High Speed : 010
  • Auto Adjust : 011
  • Cruise Mode : 100
  • Balanced : 101
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

  

What is a register block ?

There would be a collection of such registers where each register has a different set of fields and configurations. 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.

hardware-register-block-example

What is a memory map ?

An 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 something known as a memory map. Memory map is like a massive table that defines address ranges for the various memories and peripheral/device registers on a processor bus. 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.

memory-map

Let's consider 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.