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:
systemverilogwrite_reg(32'h1000_0004, 32'h0000_00FF); // What register is this?
With RAL — self-documenting, type-safe access:
systemverilogreg_model.CTRL_REG.write(status, 32'h00FF); reg_model.CTRL_REG.ENABLE.set(1); reg_model.CTRL_REG.update(status);
RAL Class Hierarchy
textuvm_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
systemverilogclass 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
systemverilogclass 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
systemverilogtask 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:
| Sequence | What It Tests |
|---|---|
uvm_reg_hw_reset_seq | All registers read their reset values |
uvm_reg_bit_bash_seq | Walking 1s/0s to verify all bits work |
uvm_reg_access_seq | Read/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
| Concept | Description |
|---|---|
| Desired value | What you want the register to be (set()) |
| Mirrored value | What UVM thinks the register currently is |
| Front-door | Access via the bus (uses adapter + sequencer) |
| Back-door | Access via DPI/hierarchy path (instantaneous) |