RAL Rework Deep Dive – Code Examples and Migration Strategies
FROM THE CTO'S DESK
"Theory tells you what's changing. Code shows you how to survive it."
Three months ago, we shared our analysis of the Accellera UVM Register Layer rework. The response was immediate—verification leads from five of the top ten semiconductor companies reached out asking the same question: "Where's the code?"
This edition delivers exactly that. Before/after examples. Migration scripts. Performance benchmarks. And an exclusive interview with an Accellera working group member who has been shaping these changes from the inside.
If you manage a verification team with 10,000+ registers under test, this is required reading.
PART I: BEFORE / AFTER CODE COMPARISONS
THE SCENARIO
A typical SoC verification environment with 15 IP blocks, each containing 200–500 registers, accessed via AXI, APB, and backdoor paths.
1. REGISTER BLOCK CONSTRUCTION
LEGACY (UVM 1.2 / Current RAL)
// Legacy approach: Hard-coded addresses, manual field definitions
class legacy_reg_block extends uvm_reg_block;
`uvm_object_utils(legacy_reg_block)
// Register declarations
rand uvm_reg_field reserved;
rand uvm_reg_field enable;
rand uvm_reg_field mode;
virtual function void build();
// Manually create each register
uvm_reg reg_control = uvm_reg::type_id::create("control_reg", , get_full_name());
reg_control.configure(this, 32, 0, "RW", 1);
// Manually add each field
reserved = uvm_reg_field::type_id::create("reserved", , get_full_name());
enable = uvm_reg_field::type_id::create("enable", , get_full_name());
mode = uvm_reg_field::type_id::create("mode", , get_full_name());
reserved.configure(reg_control, 31, 28, "RW", 0, 1'b1, 1, 0, 1);
enable.configure (reg_control, 0, 1, "RW", 0, 1'b0, 1, 0, 1);
mode.configure (reg_control, 2, 2, "RW", 0, 2'b00, 1, 0, 1);
// Add to default map
default_map.add_reg(reg_control, 32'h0000, "RW");
endfunction
endclass
Problems: Manual coding for every register. Addresses hard-coded. No runtime introspection. Specification changes require recompilation.
FUTURE (New RAL with IP-XACT Introspection)
// New approach: Specification-driven, introspectable
class ipxact_aware_block extends uvm_reg_block;
`uvm_object_utils(ipxact_aware_block)
virtual function void build();
// Load IP-XACT specification at runtime
ipxact_spec_t spec = ipxact_loader::load("block_spec.xml");
// Register model built from specification
foreach (spec.registers[i]) begin
uvm_reg reg = uvm_reg::type_id::create(spec.registers[i].name, , get_full_name());
reg.configure(this, spec.registers[i].width, 0, spec.registers[i].access, 1);
foreach (spec.registers[i].fields[j]) begin
uvm_reg_field field = uvm_reg_field::type_id::create(spec.registers[i].fields[j].name);
field.configure(reg,
spec.registers[i].fields[j].lsb_pos,
spec.registers[i].fields[j].width,
spec.registers[i].fields[j].access,
0, spec.registers[i].fields[j].reset_val, 1, 0, 1);
end
// Address mapping from spec
default_map.add_reg(reg, spec.registers[i].address, spec.registers[i].rights);
end
// Runtime introspection enabled
introspection_enable = 1;
endfunction
// Query register properties at runtime
function string get_reg_access(string reg_name);
return spec.get_access(reg_name);
endfunction
endclass
What changed: The register model is now built from a machine-readable specification (IP-XACT) rather than hand-coded. Addresses, field widths, access policies, and reset values are consumed directly. Runtime introspection enables sequences that adapt to the actual register configuration.
2. FRONTDOOR ACCESS (SIMPLIFIED)
LEGACY
class legacy_adapter extends uvm_reg_adapter;
virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
bus_transaction bus_tx = bus_transaction::type_id::create("bus_tx");
bus_tx.address = rw.addr;
bus_tx.data = rw.data;
bus_tx.kind = (rw.kind == UVM_READ) ? READ : WRITE;
return bus_tx;
endfunction
virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
bus_transaction bus_tx;
if (!$cast(bus_tx, bus_item)) begin
`uvm_fatal("ADAPTER", "Failed to cast")
end
rw.addr = bus_tx.address;
rw.data = bus_tx.data;
rw.kind = (bus_tx.kind == READ) ? UVM_READ : UVM_WRITE;
rw.status = UVM_IS_OK;
endfunction
endclass
Problems: Every bus protocol requires a custom adapter. Casting overhead. Manual mapping between register operations and bus transactions.
FUTURE
class simplified_adapter extends uvm_reg_adapter_new;
virtual function void configure();
// Declarative mapping – no per-transaction conversion logic
set_address_mapping(AXI_PROTOCOL, address_alignment = WORD_ALIGNED);
set_data_mapping(endianness = LITTLE_ENDIAN);
set_response_handling(AUTO_RESPONSE);
endfunction
// No reg2bus/bus2reg required – framework handles standard protocols
endclass
What changed: For standard bus protocols, the new RAL eliminates the need for custom adapters entirely. Declarative configuration replaces imperative conversion logic.
3. PREDICTOR CONFIGURATION
LEGACY
// Legacy: Three confusing predictor options
class legacy_env extends uvm_env;
uvm_reg_predictor #(bus_transaction) predictor;
function void connect_phase();
predictor.map = reg_model.default_map;
predictor.adapter = adapter;
predictor.predict();
// But wait – was that auto_predict or explicit?
// Did we need to call predict() or not?
endfunction
endclass
FUTURE
// New: Unified prediction model
class modern_env extends uvm_env;
function void connect_phase();
// Single call configures all prediction
reg_model.set_prediction_policy(UVM_UNIFIED_PREDICTION);
// Or use the simpler auto-sync model
reg_model.enable_auto_sync();
endfunction
endclass
What changed: The confusing distinction between implicit, explicit, and passive prediction has been replaced by a single unified model. The working group eliminated the set_auto_predict ambiguity that has caused countless verification bugs.
PART II: MIGRATION SCRIPTS
SCRIPT 1: LEGACY RAL DETECTION AND REPORTING
#!/usr/bin/env python3
# detect_legacy_ral.py
# Scans UVM testbench for methods targeted for deprecation
import re
import os
import sys
DEPRECATED_METHODS = [
'set_auto_predict',
'add_reg', # in uvm_reg_map
'add_mem', # in uvm_reg_map
'get_submap',
'uvm_reg_map::configure', # specific signature
]
VULNERABLE_PATTERNS = [
(r'\.set_auto_predict\s*\(', 'set_auto_predict() – replace with unified prediction'),
(r'default_map\.add_reg\s*\(', 'add_reg() – will be deprecated, use IP-XACT generation'),
(r'\.get_submap\s*\(', 'get_submap() – hierarchy model changing'),
]
def scan_file(filepath):
issues = []
with open(filepath, 'r') as f:
for line_num, line in enumerate(f, 1):
for pattern, msg in VULNERABLE_PATTERNS:
if re.search(pattern, line):
issues.append((line_num, line.strip(), msg))
return issues
def main():
print("=" * 70)
print("Suresh Chips: Legacy RAL Migration Scanner")
print("Identifies code patterns affected by UVM RAL rework")
print("=" * 70)
total_issues = 0
for root, dirs, files in os.walk(sys.argv[1]):
for file in files:
if file.endswith(('.sv', '.svh', '.v', '.vh')):
filepath = os.path.join(root, file)
issues = scan_file(filepath)
if issues:
print(f"\n📁 {filepath}")
for line_num, line, msg in issues:
print(f" Line {line_num}: {line[:60]}...")
print(f" → {msg}")
total_issues += 1
print("\n" + "=" * 70)
print(f"Migration Readiness Summary:")
print(f" Total legacy patterns detected: {total_issues}")
print(f" Estimated migration effort: {total_issues * 2.5} hours")
print("=" * 70)
if __name__ == "__main__":
main()
SCRIPT 2: IP-XACT GENERATOR WRAPPER
#!/usr/bin/env python3
# ipxact_to_ral_wrapper.py
# Generates new-style RAL models from IP-XACT while maintaining legacy compatibility
import xml.etree.ElementTree as ET
import sys
def generate_ral_model(ipxact_file, output_dir):
tree = ET.parse(ipxact_file)
root = tree.getroot()
namespace = {'spirit': 'http://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009'}
ral_code = []
ral_code.append("// Auto-generated from IP-XACT: " + ipxact_file)
ral_code.append("// Compatible with both legacy and new RAL APIs")
ral_code.append("")
for address_block in root.findall('.//spirit:addressBlock', namespace):
block_name = address_block.get('name')
base_addr = address_block.find('spirit:baseAddress', namespace).text
ral_code.append(f"class {block_name}_reg_block extends uvm_reg_block;")
ral_code.append(" `uvm_object_utils({0}_reg_block)".format(block_name))
ral_code.append("")
ral_code.append(" function new(string name = \"{0}\");".format(block_name))
ral_code.append(" super.new(name);")
ral_code.append(" endfunction")
ral_code.append("")
ral_code.append(" virtual function void build();")
ral_code.append(" // Legacy-compatible map")
ral_code.append(" default_map = uvm_reg_map::type_id::create(\"default_map\", this);")
ral_code.append(f" default_map.configure(this, '{h.base_addr}', 4, UVM_LITTLE_ENDIAN);")
ral_code.append("")
ral_code.append(" // Future: Enable introspection")
ral_code.append(" `ifdef UVM_NEW_RAL")
ral_code.append(" this.set_introspection_enabled(1);")
ral_code.append(" `endif")
ral_code.append(" endfunction")
ral_code.append("endclass")
with open(f"{output_dir}/{block_name}_reg_block.sv", 'w') as f:
f.write("\n".join(ral_code))
print(f"Generated: {output_dir}/{block_name}_reg_block.sv")
if __name__ == "__main__":
generate_ral_model(sys.argv[1], sys.argv[2])
SCRIPT 3: BACKWARD COMPATIBILITY WRAPPER
// backward_compatibility_shim.sv
// Wraps legacy register map calls to work with new architecture
`ifdef UVM_USE_LEGACY_RAL
// No changes needed – legacy behavior
`else
// Shim to map legacy calls to new APIs
function void uvm_reg_map::add_reg(uvm_reg rg, uvm_reg_addr_t offset, string rights);
uvm_address_descriptor desc;
desc = uvm_address_descriptor::type_id::create("desc");
desc.set_register(rg);
desc.set_offset(offset);
desc.set_rights(rights);
this.add_address_descriptor(desc);
endfunction
function void uvm_reg_map::set_auto_predict(bit enable);
if (enable) begin
this.get_parent_block().enable_auto_sync();
end
endfunction
`endif
PART III: PERFORMANCE BENCHMARKS
The following data is based on simulations run by the Suresh Chips verification team across three real-world SoC projects, each containing between 8,000 and 25,000 registers.
TEST CONFIGURATION
RESULTS
Recommended by LinkedIn
KEY OBSERVATIONS
ACCELERA PUBLIC GITHUB MIGRATION AIDS
As highlighted in the DVCon 2025 workshop, the public GitHub repository now supports faster delivery of bug fixes and migration aids. Our benchmarks confirm that teams adopting the reference implementation directly from GitHub gain access to critical performance enhancements months before EDA vendor rollups.
PART IV: INTERVIEW WITH ACCELLERA WORKING GROUP MEMBER
The following is a condensed transcript of an interview conducted with a senior verification architect who has served on the Accellera UVM working group for the past four years. The participant has requested anonymity due to ongoing standardization discussions.
Q: What motivated the RAL rework after all these years?
A: The short answer is that the industry outgrew the original design. When RAL was first introduced, a typical SoC might have a few hundred registers. Today, we see designs with 50,000 to 100,000 registers. The original O(n²) traversal patterns in address map resolution simply don't scale. We also saw that teams were spending 30–40% of their verification effort just maintaining register models—not testing registers, maintaining them. That's a failure of methodology.
Q: What's the one feature you wish you could have included but couldn't?
A: Full runtime reconfiguration of address maps. We explored allowing the register model to dynamically rebind address ranges during simulation—imagine an FPGA that reconfigures its memory map on the fly. The technical challenge wasn't the implementation; it was the backward compatibility impact. Too many existing testbenches assume that once build_phase completes, the address map is frozen. Breaking that assumption would have made migration impossible. So we deferred it to a future revision.
Q: Why were certain legacy methods kept vs. deprecated?
A: We evaluated every public method in uvm_reg_map, uvm_reg_block, and uvm_reg based on actual usage across 50+ companies. Methods like get_registers() and get_fields() were heavily used—they stay. Methods like set_auto_predict() and add_reg() with the old signature were either redundant or causing more problems than they solved. The deprecation list is actually shorter than many expected because we found that most teams only use a small subset of the RAL API. The rest of the complexity is internal.
Q: What's coming after this rework—2028–2029 roadmap?
A: Two things. First, tighter integration with PSS (Portable Stimulus Standard). Matthew Ballance's work on PSS register test generation showed the way. The new introspection APIs we're adding now are the foundation for PSS to generate register tests directly from the same IP-XACT specification. Second, we're looking at multi-threaded register access. Today, RAL serializes all accesses through a single map. For designs with multiple independent register interfaces, that's a performance bottleneck we'd like to eliminate.
Q: What's the single biggest mistake you see teams making when preparing for this transition?
A: Waiting. I see teams that know the rework is coming, but they keep building new register models with the old methodology, knowing they'll have to rewrite them in two years. That's false economy. The migration path is straightforward: start generating your models from IP-XACT today. Even if you wrap them in the legacy API for now, you'll have a much easier transition when the new APIs arrive. The teams that are doing this are already seeing benefits from spec-driven verification, even before the RAL changes.
CONCLUSION: THE MIGRATION ROADMAP
PHASE 1: NOW – IMMEDIATE ACTIONS
PHASE 2: Q3 2026 – PILOT
PHASE 3: 2027 – FULL ADOPTION
ABOUT SURESH CHIPS AND SEMICONDUCTOR
We provide verification methodology consulting, training, and audit services to semiconductor companies worldwide. Our team includes former Accellera working group members and verification architects with decades of experience.
Contact us for:
Coming in May: "RAL Rework – The Complete Migration Toolkit" A downloadable package containing all scripts, shims, and examples from this newsletter, plus a detailed migration guide for large teams.
Contributing Editors: Suresh Chips CTO Office, with technical references from DVCon 2025–2026 proceedings and the Accellera UVM working group.
© 2026 Suresh Chips and Semiconductor. All rights reserved.
*UVM, IEEE 1800.2, IP-XACT, and Accellera are trademarks of their respective holders.*