Skip to content

UVM RAL · Chapter 1 · Register Specification & CSR Thinking

Hardware vs Software Ownership

For every field, ask who writes it. A control enable bit is written only by software over the bus, so software owns it. A status busy bit is written only by hardware from inside the block, so hardware owns it and software only observes. An interrupt pending bit is written by both, so it is shared. Ownership is not a cosmetic label; it decides how RAL keeps its mirror honest, because the mirror is only trustworthy if RAL knows who can change a field and when. A software-owned field can be mirrored confidently, but a hardware-owned or shared field can change behind RAL's back, so it must be marked volatile and have a predictor watching the bus. This lesson classifies fields as software-owned, hardware-owned, or shared, maps each onto the volatile flag and prediction strategy, then breaks a hardware-owned status field modelled non-volatile so RAL returns a stale value.

Foundation12 min readUVM RALOwnershipVolatilePredictionMirrorStatus

Chapter 1 · Section 1.6 · Register Specification & CSR Thinking

1. Why Should I Learn This?

Ownership is the lens that makes access policies, volatile, and prediction stop feeling like a pile of separate flags and start feeling like one question: who writes this field, and when? Get the ownership right and the rest follows — a software-owned field is RW and non-volatile, a hardware-owned field is RO and volatile, a shared field is W1C-style and volatile with prediction. Get the ownership wrong and you produce the most confusing bugs in register verification: a mirror that drifts even though your code is correct, a status read that returns a value the hardware has already moved past, a coverage hole where a hardware-set bit is never modelled.

Learning to classify fields by ownership gives you a fast, reliable way to decide whether a field needs volatile and a predictor, to explain any mirror-drift bug in one sentence ('the mirror trusted an estimate a hardware writer had already invalidated'), and to review a model for the whole class of hardware-independence errors at a glance. It is the capstone idea of reading a spec like an engineer.

2. Industry Story — the status bit that was already stale

A block has a STATUS.done bit: hardware sets it when a transfer completes and holds it until software reads STATUS (the spec says done is RC-cleared, hardware-owned). The verification engineer models done correctly as far as access policy, but models it non-volatile — an easy omission, because from the spec's field table it looks like just another status bit.

A test kicks off a transfer and then polls STATUS.done in a loop, expecting to see it go from 0 to 1 when hardware finishes. But RAL, told the field is non-volatile, believes its mirror is still authoritative: it read done = 0 once, nothing in RAL wrote it since, so RAL sees no reason to go back to the DUT and returns the cached 0 on subsequent 'reads' — the poll never sees the 1 the hardware set. The test hangs or times out, and the engineer chases a phantom DUT bug ('done never asserts') for a day before discovering the hardware asserted it right on schedule; RAL simply never looked, because a non-volatile field told it not to bother. The lesson, written in bold in the team's RAL guide: a field any writer other than RAL can change is volatile — and forgetting the volatile flag makes RAL trust a snapshot the hardware has already invalidated.

3. Concept — three ownership classes and what each needs

Classify every field by who writes it, and the modelling requirements fall out:

  • Software-owned — only software (via the bus) writes it; hardware only reads it to do its job. Config fields: CTRL.enable, CFG.mode, clk_div. Policy is usually RW. It is non-volatile: nothing changes it except writes RAL performs, so the mirror is trustworthy without going back to the DUT. Minimal prediction needed.
  • Hardware-owned — only hardware writes it; software only observes. Status fields: STATUS.busy, raw interrupt line, a hardware-maintained counter. Policy is usually RO (or RC). It is volatile: hardware can change it at any moment, independent of anything RAL does, so RAL must never trust a cached mirror and must read the DUT (or have a predictor updating from observed activity).
  • Shared — both write it, by different rules. The interrupt/flag family: pending (hardware sets on event, software clears with W1C), a sticky error bit, a doorbell. Policy encodes the software side (W1C/W1S); ownership adds the hardware side. It is volatile, and it genuinely needs a predictor so the mirror tracks both the hardware sets and the software clears.

The two levers ownership pulls are volatile (the configure() argument that tells RAL 'a writer other than me can change this') and prediction (Chapter 6 — a predictor watching the bus updates the mirror from observed traffic). Here are the classes and their consequences:

Ownership classes: software-owned (non-volatile), hardware-owned (volatile), shared (volatile plus predictor)Software-owned — non-volatileonly software writes it (config: enable, mode, clk_div); usually RW; the mirror is trustworthy because nothing changes it but RAL's own writesonly software writes it (config: enable, mode, clk_div); usually RW; the mirror is trustworthy because nothing changes it but RAL's own writesHardware-owned — volatileonly hardware writes it (status: busy, raw line, HW counter); usually RO/RC; RAL must read the DUT, never trust a cached mirroronly hardware writes it (status: busy, raw line, HW counter); usually RO/RC; RAL must read the DUT, never trust a cached mirrorShared — volatile + predictorboth write it by different rules (interrupt pending: HW sets, SW W1C-clears); needs a predictor so the mirror tracks both sidesboth write it by different rules (interrupt pending: HW sets, SW W1C-clears); needs a predictor so the mirror tracks both sides
Figure 1 — the three ownership classes and what each requires. Software-owned fields (only software writes) are non-volatile and need minimal prediction — the mirror is trustworthy. Hardware-owned fields (only hardware writes) are volatile — RAL must read the DUT rather than trust a cached mirror. Shared fields (both write, by different rules) are volatile and need a predictor to track hardware sets and software clears together. Ownership is the question 'who writes this field, and when?' — and volatile plus prediction are the answer.

4. Mental Model — ownership is the answer to 'can the mirror be trusted?'

5. Working Example — a register across all three classes

A single DMA register can carry all three ownership classes, and the volatile argument is where ownership enters the model:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class dma_reg extends uvm_reg;
  `uvm_object_utils(dma_reg)
  rand uvm_reg_field start;    // [0]   RW   SW-owned    — software writes 1 to launch
       uvm_reg_field busy;     // [1]   RO   HW-owned    — hardware sets while running
       uvm_reg_field done;     // [2]   W1C  SHARED      — HW sets on finish, SW clears
       uvm_reg_field err;      // [3]   W1C  SHARED      — HW sets on error, SW clears
 
  function new(string name = "dma_reg");
    super.new(name, .n_bits(32), .has_coverage(UVM_NO_COVERAGE));
  endfunction
 
  virtual function void build();
    start = uvm_reg_field::type_id::create("start");
    busy  = uvm_reg_field::type_id::create("busy");
    done  = uvm_reg_field::type_id::create("done");
    err   = uvm_reg_field::type_id::create("err");
    //             parent size lsb access reset volatile rand indiv
    start.configure(this, 1, 0, "RW",  0, 0, 1, 0);   // SW-owned  -> volatile = 0
    busy.configure (this, 1, 1, "RO",  0, 1, 0, 0);   // HW-owned  -> volatile = 1
    done.configure (this, 1, 2, "W1C", 0, 1, 0, 0);   // SHARED    -> volatile = 1
    err.configure  (this, 1, 3, "W1C", 0, 1, 0, 0);   // SHARED    -> volatile = 1
  endfunction
endclass

The volatile argument (the sixth) is exactly the ownership statement: 0 for the software-owned start, 1 for everything hardware can touch. With the field marked volatile and a predictor connected (Chapter 6), a poll behaves correctly:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
uvm_status_e s;  logic [31:0] got;
 
dma.start.set(1); dma.update(s);          // SW launches: mirror(start)=1, trustworthy
do dma.read(s, got);                      // busy is VOLATILE, so each read goes to the DUT
while (dma.busy.get() == 1);              // ...and actually observes hardware clearing busy
 
if (dma.done.get() == 1)                   // done was set by HW, tracked because it is volatile
  dma.done.write(s, 1);                    // SW clears it (W1C); predictor keeps mirror honest

Because busy is volatile, RAL reads the DUT on every poll and sees hardware clear it; had it been non-volatile, RAL would have trusted its first read forever — the next section.

6. Debugging Session — the hardware-owned field that RAL stopped reading

1

A hardware-owned status field modelled non-volatile makes RAL trust a stale mirror, so a poll never sees hardware change it

MISSING VOLATILE
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// busy is hardware-owned (HW sets/clears it), but modelled non-volatile:
busy.configure(this, 1, 1, "RO", 0, 0, 0, 0);   // BUG: volatile = 0 on a HW-owned field
// A test polls busy, expecting hardware to clear it when the transfer finishes:
do dma.read(s, got);
while (dma.busy.get() == 1);      // may spin forever: RAL trusts the cached busy=1
Symptom

A poll on a hardware-updated status bit never observes the update — the loop spins forever waiting for busy to clear, or a wait-for-done times out even though the hardware asserted done exactly on time. It looks like the DUT never changed the bit, so the investigation goes straight to the RTL, which is behaving perfectly. The tell is that a backdoor peek or a fresh forced read shows the correct current value while RAL's frontdoor path keeps returning the old one — RAL is not re-reading the DUT because a non-volatile field told it the mirror is still authoritative.

Root Cause

The field is hardware-owned but modelled non-volatile, which tells RAL a falsehood: 'nothing but RAL's own writes changes this field, so the mirror is always current.' Acting on that, RAL may return the cached mirror instead of going back to the DUT — so hardware's change to the field is invisible through the frontdoor. The access policy (RO) was right; the ownership fact (volatile) was wrong, and volatile is precisely the flag that says 'a writer other than RAL can change this field, so do not trust the mirror without reading.' The DUT changed the bit on schedule; RAL simply stopped looking.

Fix

Mark the field volatile — busy.configure(this, 1, 1, "RO", 0, 1, 0, 0) — and, for shared fields, connect a predictor (Chapter 6) so observed bus and internal activity keep the mirror current. Now every read of busy consults the DUT and the poll observes hardware clearing it. The durable habit is the chapter's whole thesis: for every field, ask who writes it — any writer other than RAL means volatile = 1, and a hardware-owned or shared field additionally wants a predictor. A mirror is a cache, and a cache with a second writer is only safe if you either re-read or watch — volatile is how you tell RAL which.

7. Common Mistakes

  • Modelling a hardware-owned field non-volatile. The stale-mirror trap: RAL trusts a cached value the hardware has moved past.
  • Treating shared fields as software-only. A W1C interrupt bit that hardware sets needs volatile and a predictor, not just the write-clear policy.
  • Confusing ownership with access policy. Policy is how a field responds; ownership is who writes it and when. A field is RO and volatile if hardware owns it.
  • Assuming config fields need prediction. Software-owned fields are non-volatile and trustworthy; adding volatility there just forces needless re-reads.
  • Forgetting the predictor for shared fields. Without it, the mirror tracks only the software side and drifts on the first hardware set.

8. Industry Best Practices

  • Classify every field by writer before choosing flags. Software-owned, hardware-owned, or shared — the class dictates volatile and prediction.
  • Set volatile from ownership, mechanically. Any writer other than RAL means volatile; make this a review checklist item.
  • Connect a predictor for hardware-owned and shared fields. It keeps the mirror honest under hardware activity and other bus masters (Chapter 6).
  • Poll volatile status via the frontdoor, observe non-perturbing values via peek. Volatile ensures the poll re-reads; peek observes without side effects for debug.
  • Review status registers specifically for volatility. They are where the non-volatile-by-omission bug concentrates.

9. Interview / Review Questions

10. Key Takeaways

  • For every field, ask who writes it — software (via the bus), hardware (internally), or both. Ownership is the fact that decides how RAL keeps its mirror honest.
  • Software-owned fields are non-volatile and trustworthy; hardware-owned fields are volatile (RAL must read the DUT); shared fields are volatile and need a predictor.
  • The volatile flag is the ownership statement: any writer other than RAL means volatile = 1, full stop.
  • Ownership is not access policy — a status field is RO and volatile; the policy says how it responds, ownership says who changes it and when.
  • The signature bug is a hardware-owned field modelled non-volatile, which makes RAL trust a stale mirror so a poll never sees hardware change the field — the mirror is a cache, and a cache with a second writer is only safe if you re-read or predict.