Part 9 · Register Model (RAL) · Intermediate

uvm_reg_map Addressing: Offsets, Endianness, and Byte Width

How map parameters define address interpretation: base offsets, n_bytes granularity, endianness, and disciplined add_reg usage.

Why map parameters matter

A register model can have perfectly correct fields but still fail if map metadata is wrong . Address offsets, byte width, and endianness jointly define how abstract reads/writes become bus transactions.

Misconfigured map values are dangerous because accesses still execute, but hit wrong byte lanes, wrong aligned addresses, or incorrect multi-byte ordering. Failures then look random unless map assumptions are explicit.

diagram
[RAL] create_map key inputs

 create_map(name, base_addr, n_bytes, endian)
   base_addr : local base for this map
   n_bytes   : bus byte width per access unit
   endian    : byte ordering for packed data transfer

 add_reg(reg, offset, rights):
   absolute_addr = map_base + offset (+ parent submap offsets)
diagram
[UVM][RAL][BUS] addressing path

 [UVM] test calls reg.write(data)
          │
          ▼
 [RAL] map resolves local offset + hierarchy bases
          │
          ▼
 [RAL] adapter receives uvm_reg_bus_op(addr,data,kind)
          │
          ▼
 [BUS] driver sends protocol item to DUT
  • Offsets are relative to the map where add_reg is called.

  • n_bytes must match the bus data granularity used for frontdoor accesses.

  • Endianness defines byte packing order for multi-byte fields and registers.


Offsets and add_reg discipline

Use add_reg consistently with spec-defined offsets. Keep one source of truth for offsets to avoid drift between documentation and model implementation.

systemverilog
class cfg_block extends uvm_reg_block;
  `uvm_object_utils(cfg_block)

  rand cfg_ctrl_reg ctrl;
  rand cfg_stat_reg stat;
  rand cfg_intr_reg intr;
  uvm_reg_map default_map;

  localparam int unsigned CTRL_OFS = 'h000;
  localparam int unsigned STAT_OFS = 'h004;
  localparam int unsigned INTR_OFS = 'h008;

  function new(string name = "cfg_block");
    super.new(name, UVM_NO_COVERAGE);
  endfunction

  virtual function void build();
    ctrl = cfg_ctrl_reg::type_id::create("ctrl");
    stat = cfg_stat_reg::type_id::create("stat");
    intr = cfg_intr_reg::type_id::create("intr");

    ctrl.configure(this); ctrl.build();
    stat.configure(this); stat.build();
    intr.configure(this); intr.build();

    default_map = create_map("default_map", 'h0, 4, UVM_LITTLE_ENDIAN);
    default_map.add_reg(ctrl, CTRL_OFS, "RW");
    default_map.add_reg(stat, STAT_OFS, "RO");
    default_map.add_reg(intr, INTR_OFS, "RW");
  endfunction
endclass
diagram
[RAL] offset table example

 register   offset   rights   note
 ----------------------------------------------
 ctrl       0x000    RW       control and mode bits
 stat       0x004    RO       status and sticky indicators
 intr       0x008    RW       interrupt mask/status controls

 gaps are legal; overlapping offsets are not
diagram
[BUS] overlap failure pattern

 if ctrl and stat both mapped at 0x004:
   - writes to ctrl unexpectedly alter stat location
   - mirror mismatches look non-deterministic
   - bit-bash fails unrelated fields

 add map collision checks early during build
  • Use named constants for offsets and keep them grouped by block.

  • Assign map rights to match expected access style, even if field policy is richer.

  • Validate no overlap and no accidental misalignment in integration tests.


Endianness and byte width walkthrough

Endianness bugs often surface only on multi-byte fields. Demonstrate and test byte-lane assumptions explicitly, especially on bridges where register bus width and CPU width differ.

systemverilog
function void build_maps();
  // APB control domain: 32-bit little-endian
  apb_map = create_map("apb_map", 'h0, 4, UVM_LITTLE_ENDIAN);

  // Legacy sideband domain: 16-bit big-endian
  sb_map  = create_map("sb_map",  'h0, 2, UVM_BIG_ENDIAN);

  apb_map.add_reg(ctrl, 'h00, "RW");
  sb_map.add_reg(legacy_cfg, 'h20, "RW");
endfunction
diagram
[RAL][BUS] byte-lane view for 32'hA1B2C3D4

 little-endian (n_bytes=4):
   addr+0 -> D4
   addr+1 -> C3
   addr+2 -> B2
   addr+3 -> A1

 big-endian (n_bytes=4):
   addr+0 -> A1
   addr+1 -> B2
   addr+2 -> C3
   addr+3 -> D4
diagram
[UVM] practical verification tactic

 1) choose a pattern with distinct bytes (A1 B2 C3 D4)
 2) write through frontdoor
 3) monitor observed [BUS] bytes/lane placement
 4) compare against map endian assumption
 5) run readback to ensure mirror and DUT agree
  • Use distinct-byte patterns for endian debug, not symmetric values like 0x0000FFFF.

  • Confirm adapter bus item fields preserve address and byte-enable semantics.

  • Document map width assumptions per bus domain and review during integration.


Debugging map/addressing failures

Addressing bugs manifest as wrong register hits, stale mirror values, and unpredictable bit-bash failures. Correlate requested register name, resolved address, adapter output, and monitor capture in one log stream.

systemverilog
task debug_one_write(uvm_reg rg, uvm_reg_data_t d);
  uvm_status_e status;
  `uvm_info("RAL_ADDR_DBG",
            $sformatf("writing %s with data 0x%0h", rg.get_full_name(), d),
            UVM_MEDIUM)
  rg.write(status, d, UVM_FRONTDOOR, .parent(this));
endtask
diagram
[RAL] address debug checklist

 expected:
   reg full name
   map name
   local offset
   effective absolute address
   adapter item address/data
   monitor observed address/data

 if any stage differs, isolate at that boundary

Key takeaways

  • Map correctness is foundational: offsets, n_bytes, and endianness define real hardware touch points.

  • Use disciplined add_reg tables with named constants and collision checks.

  • Exercise endian assumptions using distinct-byte patterns and monitor correlation.

  • When debuging failures, trace name->map->adapter->monitor as one chain.

Common pitfalls

  • Copying offsets from outdated spec revision - silent incorrect accesses.

  • Mismatching n_bytes with actual bus width - split/packed transfers break.

  • Assuming adapter logic can compensate for wrong map configuration.

  • Ignoring right/readonly mismatch - tests write fields that should never move.