Part 9 · Register Model (RAL) · Intermediate
Generated vs Handwritten RAL: Workflow and Extension Strategy
Trade-offs between generated and handcrafted RAL models, plus safe extension via sidecar classes and callbacks.
Why generation dominates real projects
Most production SoCs use generated RAL because register specs evolve frequently. Tools consume IP-XACT or SystemRDL and emit consistent block/register/field classes, reducing manual drift and ensuring naming and access policies match the source spec.
Handwritten RAL is still useful for small prototypes, educational setups, or custom behaviors , but scale quickly favors generation due to volume, churn, and cross-team consistency requirements.
[RAL] generation pipeline
spec source:
IP-XACT XML / SystemRDL
│
▼
generator tool
- emits uvm_reg_block / uvm_reg / field configure code
- emits maps, offsets, policies, reset values
│
▼
generated package in repo (read-only by policy)
│
▼
integration layer + tests consume generated model[UVM] decision heuristic
if register count < 20 and spec stable:
handwritten can be acceptable
if register count is large or spec churn is high:
generated model is strongly preferred
if mixed:
generate baseline, add handwritten wrappers/extensionsGeneration minimizes human error in repetitive field and map boilerplate.
Source-of-truth stays in spec artifacts rather than scattered model edits.
The key challenge is extension strategy, not raw generation itself.
Generated code is read-only: extension patterns
Never hand-edit generated classes. Regeneration will overwrite local changes and create hard-to-review diffs. Instead, add extension logic in sidecar classes, adapter policies, callbacks, and helper utilities that attach externally.
[RAL] safe extension layers (outside generated files)
1) model wrapper class
- creates generated root block
- applies env-specific setup
2) callback/policy layer
- register access logging
- custom validation hooks
3) helper utilities
- typed access APIs
- debug dump and consistency checks
4) env wiring
- adapter/predictor connections
- frontdoor/backdoor defaultsclass ral_model_wrapper extends uvm_object;
`uvm_object_utils(ral_model_wrapper)
generated_chip_block model;
function new(string name = "ral_model_wrapper");
super.new(name);
endfunction
function void build_model();
model = generated_chip_block::type_id::create("model");
model.build();
model.lock_model();
endfunction
function void apply_defaults();
// Non-generated customization entry point
model.default_map.set_auto_predict(0);
endfunction
endclass[UVM][RAL] extension boundary rule
generated files:
- class structure
- field configure calls
- map offsets
- reset/policy boilerplate
custom files:
- scenario utilities
- access wrappers
- diagnostics/callbacks
- integration policiesTreat generated artifacts as immutable outputs of a reproducible tool flow.
Put all custom behavior in version-controlled handwritten sidecar files.
Review extension APIs to survive generator version upgrades safely.
IP-XACT vs SystemRDL in practice
Both formats can describe register structure, fields, reset values, and addressing, but teams choose based on existing tooling and ecosystem. What matters most is consistent generation and CI checks that flag divergences.
Spec Source Typical Strength Typical Concern
---------------------------------------------------------------------------------------------
IP-XACT Broad tool ecosystem and integration metadata Verbose XML and style variance
SystemRDL Register-centric authoring and concise semantics Toolchain compatibility choices
Common best practice:
normalize style + validate generated output in CI[UVM] CI regeneration workflow
commit spec changes
│
▼
run generator in CI
│
├─ if generated files differ unexpectedly -> fail with diff
└─ if expected diff -> review + merge
objective:
keep source spec and RAL code synchronized continuously// Example CI check pseudo-flow
// 1) run_ral_generator.sh
// 2) git diff --exit-code generated/ral_pkg.sv
// 3) fail build if mismatch and no approved regeneration commitChoose one canonical spec input per IP and enforce it across teams.
Automate regeneration in CI so stale models are caught early.
Keep generated diff reviews mechanical and extension reviews semantic.
Walkthrough: extending generated model with callback-style hooks
Suppose verification wants write-audit hooks on selected registers without modifying generated register classes. Add a wrapper utility that routes register operations through helper functions and triggers callback listeners.
class ral_access_cb extends uvm_callback;
virtual function void pre_write(string reg_name, uvm_reg_data_t data); endfunction
virtual function void post_write(string reg_name, uvm_status_e st); endfunction
endclass
class ral_access_helper extends uvm_object;
`uvm_object_utils(ral_access_helper)
`uvm_register_cb(ral_access_helper, ral_access_cb)
generated_chip_block model;
function new(string name = "ral_access_helper");
super.new(name);
endfunction
task write_reg(uvm_reg rg, uvm_reg_data_t d);
uvm_status_e st;
`uvm_do_callbacks(ral_access_helper, ral_access_cb,
pre_write(rg.get_full_name(), d))
rg.write(st, d, UVM_FRONTDOOR, .parent(this));
`uvm_do_callbacks(ral_access_helper, ral_access_cb,
post_write(rg.get_full_name(), st))
endtask
endclass[RAL] extension walkthrough (no generated edits)
generated model remains unchanged
│
handwritten helper wraps accesses
│
callback listeners provide project policy
│
tests consume helper APIs
result:
regeneration-safe customization path[UVM][BUS] observability gain
before helper:
tests call reg.write directly; limited centralized logging
after helper:
pre/post callback events for every write
-> unified audit trail
-> custom assertions on access sequences
-> no forked generated classesKey takeaways
Use generation for scale and consistency; use handwritten layers for behavior.
Never modify generated RAL files directly - keep them reproducible and disposable.
Extension by wrappers/callbacks keeps custom logic stable across regenerations.
CI regeneration checks prevent spec-model drift from reaching regressions.
Common pitfalls
Mixing generated and handwritten edits in same file - impossible regeneration hygiene.
No CI regeneration gate - stale model silently diverges from latest spec.
Over-engineering handwritten model for large designs - maintenance burden explodes.
Putting verification policy into generator templates without ownership control.