HomeProblemsTheoryUVM
Advanced3 min readChapter 11

Register Abstraction Layer (RAL)

Model DUT registers in UVM using the RAL for automated read/write/check operations.

Register Abstraction Layer (RAL)

The UVM RAL provides a high-level, object-oriented model of the DUT's registers. It enables automated register testing, front-door and back-door access, and register coverage.


Why RAL?

Without RAL — raw address-based access:

systemverilog
write_reg(32'h1000_0004, 32'h0000_00FF); // What register is this?

With RAL — self-documenting, type-safe access:

systemverilog
reg_model.CTRL_REG.write(status, 32'h00FF); reg_model.CTRL_REG.ENABLE.set(1); reg_model.CTRL_REG.update(status);

RAL Class Hierarchy

text
uvm_reg_block ← Register block (top container) ├── uvm_reg ← Individual register │ └── uvm_reg_field ← Bit field within a register ├── uvm_mem ← Memory model └── uvm_reg_map ← Address map

Step 1: Define a Register

systemverilog
class ctrl_reg extends uvm_reg; `uvm_object_utils(ctrl_reg) rand uvm_reg_field ENABLE; rand uvm_reg_field MODE; rand uvm_reg_field IRQ_MASK; function new(string name = "ctrl_reg"); super.new(name, 32, UVM_NO_COVERAGE); endfunction virtual function void build(); ENABLE = uvm_reg_field::type_id::create("ENABLE"); MODE = uvm_reg_field::type_id::create("MODE"); IRQ_MASK = uvm_reg_field::type_id::create("IRQ_MASK"); // parent, size, lsb, access, volatile, reset, has_reset ENABLE.configure (this, 1, 0, "RW", 0, 1'b0, 1, 0, 0); MODE.configure (this, 2, 1, "RW", 0, 2'b0, 1, 0, 0); IRQ_MASK.configure(this, 8, 8, "RW", 0, 8'b0, 1, 0, 0); endfunction endclass

Step 2: Define the Register Block

systemverilog
class my_reg_block extends uvm_reg_block; `uvm_object_utils(my_reg_block) rand ctrl_reg CTRL; rand status_reg STATUS; uvm_reg_map default_map; function new(string name = "my_reg_block"); super.new(name); endfunction virtual function void build(); CTRL = ctrl_reg::type_id::create("CTRL"); STATUS = status_reg::type_id::create("STATUS"); CTRL.configure(this); STATUS.configure(this); CTRL.build(); STATUS.build(); // Create address map default_map = create_map( "default_map", 0, // Base address 4, // Bus width (bytes) UVM_LITTLE_ENDIAN ); default_map.add_reg(CTRL, 'h0000, "RW"); default_map.add_reg(STATUS, 'h0004, "RO"); endfunction endclass

Step 3: Connect RAL to the Bus

systemverilog
// Adapter converts between generic reg transactions and bus transactions class apb_reg_adapter extends uvm_reg_adapter; `uvm_object_utils(apb_reg_adapter) function new(string name = "apb_reg_adapter"); super.new(name); endfunction virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); apb_txn txn = apb_txn::type_id::create("txn"); txn.addr = rw.addr; txn.write = (rw.kind == UVM_WRITE); txn.data = rw.data; return txn; endfunction virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); apb_txn txn; if (!$cast(txn, bus_item)) `uvm_fatal("CAST", "Failed to cast bus item") rw.addr = txn.addr; rw.data = txn.data; rw.kind = txn.write ? UVM_WRITE : UVM_READ; rw.status = UVM_IS_OK; endfunction endclass // In the environment's connect_phase: function void connect_phase(uvm_phase phase); reg_model.default_map.set_sequencer( agent.sequencer, adapter ); endfunction

Using RAL in Tests

systemverilog
task run_phase(uvm_phase phase); uvm_status_e status; uvm_reg_data_t rdata; phase.raise_objection(this); // Direct register write env.reg_model.CTRL.write(status, 32'h0000_0001); // Direct register read env.reg_model.STATUS.read(status, rdata); `uvm_info("TEST", $sformatf("STATUS = 0x%h", rdata), UVM_NONE) // Field-level access (read-modify-write) env.reg_model.CTRL.ENABLE.set(1); env.reg_model.CTRL.MODE.set(2'b10); env.reg_model.CTRL.update(status); // Writes all modified fields // Mirror: read from DUT and update model env.reg_model.STATUS.mirror(status, UVM_CHECK); phase.drop_objection(this); endtask

Built-in Register Test Sequences

UVM provides pre-built register tests:

SequenceWhat It Tests
uvm_reg_hw_reset_seqAll registers read their reset values
uvm_reg_bit_bash_seqWalking 1s/0s to verify all bits work
uvm_reg_access_seqRead/write access of all registers
systemverilog
// Run reset value test: uvm_reg_hw_reset_seq rst_seq; rst_seq = uvm_reg_hw_reset_seq::type_id::create("rst_seq"); rst_seq.model = env.reg_model; rst_seq.start(null);

Key Concepts

ConceptDescription
Desired valueWhat you want the register to be (set())
Mirrored valueWhat UVM thinks the register currently is
Front-doorAccess via the bus (uses adapter + sequencer)
Back-doorAccess via DPI/hierarchy path (instantaneous)