Part 9 · Register Model (RAL) · Intermediate
reg_adapter reg2bus: Frontdoor Translation
Translate protocol-neutral uvm_reg_bus_op into concrete bus items with a full APB adapter walkthrough and mapping checklist.
What reg2bus must do
RAL calls reg2bus whenever a frontdoor operation needs to become a protocol item. reg2bus receives a fully specified abstract operation and must produce a sequence item the driver can send exactly once.
At minimum, map kind/addr/data correctly. In richer protocols, map byte enables, protection bits, burst hints, and sideband metadata that your bus item requires.
[RAL] abstract op entering reg2bus
rw.kind : UVM_READ or UVM_WRITE
rw.addr : absolute map address
rw.data : write payload (or placeholder for read)
rw.byte_en: optional lane mask
rw.n_bits : operation width
reg2bus output:
concrete [BUS] sequence item for driverNever mutate map-level semantics (addressing, policy) inside adapter logic.
Preserve width and lane intent if protocol supports byte enables.
Create fresh bus items per request; avoid stale handle reuse.
Full APB adapter example
APB is a clean first adapter because each transaction is simple: one address, one data payload, read/write direction, and optional strobe. The pattern below scales to AXI/AHB by extending item fields.
class apb_item extends uvm_sequence_item;
`uvm_object_utils(apb_item)
rand bit [31:0] addr;
rand bit [31:0] wdata;
bit [31:0] rdata;
rand bit write;
rand bit [3:0] strb;
bit slv_err;
function new(string name = "apb_item");
super.new(name);
endfunction
endclass
class apb_reg_adapter extends uvm_reg_adapter;
`uvm_object_utils(apb_reg_adapter)
function new(string name = "apb_reg_adapter");
super.new(name);
supports_byte_enable = 1;
provides_responses = 0;
endfunction
virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
apb_item tr;
tr = apb_item::type_id::create("tr");
tr.addr = rw.addr[31:0];
tr.write = (rw.kind == UVM_WRITE);
tr.wdata = rw.data[31:0];
tr.strb = (rw.byte_en == '0) ? 4'hF : rw.byte_en[3:0];
return tr;
endfunction
virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
apb_item tr;
if (!$cast(tr, bus_item)) begin
rw.status = UVM_NOT_OK;
return;
end
rw.kind = tr.write ? UVM_WRITE : UVM_READ;
rw.addr = tr.addr;
rw.data = tr.write ? tr.wdata : tr.rdata;
rw.byte_en= tr.strb;
rw.status = tr.slv_err ? UVM_NOT_OK : UVM_IS_OK;
endfunction
endclass[RAL] -> [BUS] APB translation
RAL write op:
kind = UVM_WRITE, addr = 0x1004, data = 0xA5A5A5A5, byte_en = 0xF
|
v
reg2bus()
|
v
APB item:
write = 1, addr = 0x1004, wdata = 0xA5A5A5A5, strb = 0xF
|
v
driver performs APB setup/access phases[BUS] APB field mapping checklist
rw.kind -> tr.write
rw.addr -> tr.addr
rw.data -> tr.wdata (writes)
rw.byte_en-> tr.strb (if supported)
for reads:
rw.data gets filled later by bus2reg from tr.rdataDefault byte enables only when policy requires full-lane writes.
Do not silently truncate wide addresses unless architecture guarantees width.
Surface protocol error bits so upper layers can fail loudly.
Frontdoor wiring and walkthrough
Translation alone is not enough. The map must point to sequencer and adapter so RAL knows where to send frontdoor operations.
class reg_env extends uvm_env;
`uvm_component_utils(reg_env)
apb_agent apb;
apb_reg_adapter adapter;
my_reg_block rm;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
apb = apb_agent ::type_id::create("apb", this);
adapter = apb_reg_adapter::type_id::create("adapter");
rm = my_reg_block ::type_id::create("rm");
rm.build();
rm.lock_model();
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
rm.default_map.set_sequencer(apb.sqr, adapter);
endfunction
endclass
task smoke_frontdoor(uvm_reg rg, uvm_sequence_base parent);
uvm_status_e status;
uvm_reg_data_t data;
rg.write(status, 'h55AA11EE, UVM_FRONTDOOR, parent);
rg.read (status, data, UVM_FRONTDOOR, parent);
endtask[UVM] frontdoor call stack with reg2bus
test: rg.write(..., UVM_FRONTDOOR)
|
v
[RAL] map builds uvm_reg_bus_op
|
v
adapter.reg2bus(rw)
|
v
[BUS] item starts on sequencer
|
v
driver transacts with DUTKey takeaways
reg2bus is the frontdoor translation point from abstract op to protocol item.
A complete adapter maps direction, address, data, lanes, and error semantics.
APB adapter pattern is a reusable baseline for more complex protocols.
Frontdoor works only when map->sequencer->adapter wiring is correct.
Common pitfalls
Returning null from reg2bus under unsupported conditions instead of failing clearly.
Using stale item handles across calls and leaking previous transaction state.
Hard-coding byte-enable values that conflict with narrow writes.
Forgetting set_sequencer(), causing frontdoor operations to stall or noop.