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.

diagram
[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
diagram
[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/extensions
  • Generation 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.

diagram
[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 defaults
systemverilog
class 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
diagram
[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 policies
  • Treat 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.

diagram
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
diagram
[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
systemverilog
// 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 commit
  • Choose 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.

systemverilog
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
diagram
[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
diagram
[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 classes

Key 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.