Skip to content

UVM RAL · Chapter 0 · Foundation

The Register-Modeling Mindset

RAL stops feeling like a bag of surprising API calls the moment you think in three values every field carries at once. The desired value is what you intend to program, the mirrored value is what RAL believes the hardware holds, and the actual value is what the silicon really holds. Every register operation is just a movement between those three. The one thing that keeps the mirror honest as they move is each field's access policy and its hardware-versus-software ownership, meaning whether a bit is read-write, read-only status, write-one-to-clear, or clear-on-read, and who is allowed to change it. This page installs that mindset, then breaks a write-one-to-clear register on purpose to show why the access policy is the load-bearing part of the model.

Foundation12 min readUVM RALMental ModelAccess PolicyW1CMirroruvm_reg_field

Chapter 0 · Section 0.2 · Foundation

1. Why Should I Learn This?

The most common way a RAL environment goes wrong is not a syntax error — it is a modelling error. The code compiles, the sequence runs, and then a read mismatches, or a coverage hole never closes, or a W1C interrupt test passes when it should fail, and the engineer stares at correct-looking API calls with no idea what is wrong. The reason is almost always that the mental model in the engineer's head does not match the three-value model RAL actually runs.

Learning the mindset first is what makes every later chapter — adapters, predictors, sequences, coverage — feel obvious instead of arbitrary. Once you think in desired / mirrored / actual and in access policy, you can predict what RAL will do before you run it, explain any mismatch in one sentence, and design a register model that self-checks correctly instead of one that happens to pass. This page is short on code and long on the one idea that pays off for the rest of the track.

2. Industry Story — the interrupt that would not clear, again

A verification engineer picks up a block with an INT_STATUS register. The spec is clear: each bit is write-one-to-clear — hardware sets a bit when its event fires, and software clears it by writing a 1 to that bit; writing 0 does nothing. The engineer, moving fast, builds the RAL field the way they build everything: access "RW". The test writes 1 to clear a pending interrupt, reads back, and RAL raises a mismatch: mirrored says 1 (because to a plain RW field, writing 1 means the field is now 1), but the DUT reads 0 (because to real W1C hardware, writing 1 cleared it).

The engineer, trusting the model, files a DUT bug: 'INT_STATUS bit does not hold the written value.' The designer bounces it: 'It is W1C — writing 1 clears it, that is correct.' A day is lost to a ticket that was really a one-word fix in the model: the access policy. The deeper cost is that until the policy is right, every interrupt test in the suite is checking against a wrong expectation — some pass by luck, some fail spuriously, and none of them actually verify the clear behaviour the spec promises. The access policy is not metadata about the field; it is the field's behaviour, and the mirror is only honest when it matches.

3. Concept — three values and the policy that connects them

Every uvm_reg_field carries three conceptual values at all times:

  • Desired — the value you intend the field to have. set() changes the desired value in the model without touching hardware; update() later pushes any field whose desired differs from mirrored out to the DUT.
  • Mirrored — RAL's running estimate of what the hardware holds right now. This is the mirror from 0.1. It is updated by write (RAL knows what it drove), by prediction on observed reads, and by explicit predict().
  • Actual — the value the silicon (or RTL) genuinely holds. RAL never sees this directly except by reading the DUT; a read fetches actual and, with checking on, compares it against mirrored.

The access policy is the rule that says how a field's mirrored (and desired) value should change when a read or write happens — and therefore what the mirror must predict. A few you will meet constantly:

  • RW — reads return the value, writes set it. Mirror after write of v is v.
  • RO — read-only status; software writes are ignored. Mirror is driven by hardware, not by writes.
  • W1C — write-one-to-clear; writing 1 clears the bit, writing 0 leaves it. Mirror after writing 1 is 0.
  • RC — read-to-clear; the act of reading clears the field. Mirror after a read is 0.
  • WO — write-only; you can write it but a read does not return it.

Ownership sits underneath all of this: a bit is either software-owned (software's write is what determines it, like a CTRL bit) or hardware-owned (hardware sets or updates it, like a STATUS bit), and often both interact. The policy encodes that interaction. Here is the three-value model as a stack, from the intent you express down to the reality RAL is trying to track:

Three-value RAL model: desired at top, mirrored in the middle, actual at the bottom, with the operations that move between themDesired — what you intendset() changes it in the model only; update() pushes fields whose desired differs from mirrored out to the DUTset() changes it in the model only; update() pushes fields whose desired differs from mirrored out to the DUTMirrored — RAL's estimate of the hardwareupdated by write() (RAL knows what it drove), by prediction on observed reads, and by explicit predict(); this is the reference a read is checked againstupdated by write() (RAL knows what it drove), by prediction on observed reads, and by explicit predict(); this is the reference a read is checked againstActual — what the DUT really holdsseen only by reading the DUT; a read fetches it and compares against mirrored; backdoor peek observes it without bus activityseen only by reading the DUT; a read fetches it and compares against mirrored; backdoor peek observes it without bus activity
Figure 1 — the three values every field carries, and the operations that move between them. You express intent at the top (set/update change desired and push it down). RAL maintains its estimate in the middle (write and predict update mirrored). The DUT holds reality at the bottom (read fetches actual; mirror reconciles the two). The access policy is the rule that says how each layer must change on a read or write — it is what keeps mirrored a faithful estimate of actual.

4. Mental Model — you are the keeper of a promise

5. Working Example — a STATUS register modelled honestly

A realistic STATUS register mixes ownership and policy: a hardware-owned busy bit (read-only to software), and a W1C done bit that hardware sets and software clears. Modelling the behaviour, not just the bits, is the whole exercise:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class status_reg extends uvm_reg;
  `uvm_object_utils(status_reg)
  uvm_reg_field busy;   // 1 bit, RO  — hardware owns it, software only observes
  uvm_reg_field done;   // 1 bit, W1C — hardware sets it, software clears with a 1
 
  function new(string name = "status_reg");
    super.new(name, .n_bits(32), .has_coverage(UVM_NO_COVERAGE));
  endfunction
 
  virtual function void build();
    busy = uvm_reg_field::type_id::create("busy");
    done = uvm_reg_field::type_id::create("done");
    //          parent size lsb access reset volatile rand can_cover
    busy.configure(this, 1,  0, "RO",  0, 1, 0, 0);   // volatile: HW can change it any time
    done.configure(this, 1,  1, "W1C", 0, 1, 0, 0);   // write 1 clears
  endfunction
endclass

Now watch the three values move, and note that the policy — not the API — decides each outcome:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
uvm_status_e s;
 
// 'done' fired in hardware. A frontdoor read observes actual=1; with prediction on,
// RAL updates mirrored=1. desired is irrelevant for a HW-owned event.
status.read(s, /*value*/ , UVM_FRONTDOOR);      // mirrored(done) becomes 1
 
// Software clears it the spec's way: write a 1 to a W1C bit.
status.done.set(1);          // desired(done) = 1  (intent: 'clear this')
status.update(s);            // pushes the write; because policy is W1C, RAL predicts mirrored(done)=0
 
// Read back. RAL compares actual vs mirrored(done)=0 — and passes, because the model
// encoded the clear. Had 'done' been modelled RW, mirrored would be 1 and this would 'fail'.
status.read(s, /*value*/ );

The exact same sequence of calls, against a field wrongly typed RW, produces a mismatch — proving the calls are not the behaviour. The policy is.

6. Debugging Session — the W1C bit modelled as RW

1

A write-one-to-clear interrupt bit modelled as plain read-write makes the mirror predict the opposite of the hardware

ACCESS POLICY
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// INT_STATUS bit is write-one-to-clear per the spec, but modelled as RW:
irq.configure(this, 1, 0, "RW", 0, 1, 1, 0);   // WRONG policy
// ... in the test: clear a pending interrupt the spec's way ...
int_status.irq.set(1);
int_status.update(s);        // RW model predicts mirrored(irq) = 1
int_status.read(s, got);     // DUT is W1C hardware: writing 1 CLEARED it, actual = 0
// UVM_ERROR: INT_STATUS.irq mismatch: mirrored 'h1 got 'h0
Symptom

Every test that clears an interrupt raises a mirror mismatch where mirrored is 1 and actual is 0. Superficially it looks like 'the DUT will not hold the value we wrote', so it gets filed as an RTL bug — and bounced by the designer, because clearing on a 1 write is exactly what W1C hardware is supposed to do. Time drains into a ticket that is really a modelling defect.

Root Cause

The field's access policy in the model does not match the field's behaviour in the hardware. Modelled RW, the mirror's promise is 'writing 1 makes the bit 1', so after the clearing write it predicts 1. The real W1C bit does the opposite — writing 1 makes it 0. The mismatch is not the DUT disagreeing with the spec; it is the mirror disagreeing with the spec because the contract printed on the field is wrong. This is the three-value model catching a modelling error: desired and actual are both correct for a clear; only mirrored is wrong, and only because the policy is wrong.

Fix

Model the field with the policy the spec defines: irq.configure(this, 1, 0, "W1C", 0, 1, 1, 0);. Now update() after set(1) predicts mirrored = 0, the read reconciles cleanly, and — crucially — the test now actually verifies the clear behaviour instead of accidentally checking a wrong expectation. The general rule the bug teaches: before ever suspecting the RTL on a register mismatch, confirm the field's access policy matches the programmer's guide. More register 'DUT bugs' are wrong access policies than are real.

7. Common Mistakes

  • Defaulting every field to RW. It is the policy that costs you nothing to type and everything to get wrong. Read the spec and encode RO, W1C, RC, WO where they belong.
  • Confusing desired with mirrored. set() changes intent, not hardware; nothing reaches the DUT until update(). Expecting a set() to change what a read returns is a classic first-week bug.
  • Ignoring volatile on hardware-updated fields. A status bit hardware can change at any moment must be marked volatile, or RAL may skip a read or trust a stale mirror.
  • Blaming the DUT before naming which of the three values is wrong. Most register mismatches are the mirror being wrong (a policy or prediction error), not the actual value.

8. Industry Best Practices

  • Derive the model from the programmer's guide's behaviour column, not just its address column. The access policy and side-effects are the load-bearing fields.
  • Make the predictor own the mirror. Let observed bus activity update mirrored automatically (Chapter 6) rather than hand-maintaining it — hand-maintenance is how mirrors drift.
  • Keep desired and mirrored straight in reviews. In a code review, a set() with no matching update(), or an expectation that a set() changed hardware, is an immediate flag.
  • Write one deliberate policy test per exotic field. For each W1C/RC/WO field, write a test that exercises the clear/side-effect behaviour, so a wrong policy fails loudly instead of passing by luck.

9. Interview / Review Questions

10. Key Takeaways

  • Think in three valuesdesired (intent), mirrored (RAL's estimate), actual (the DUT) — not in API calls. Every register operation is a movement between them.
  • A field's access policy (RW, RO, W1C, RC, WO, …) is its behaviour, and the mirror is a promise to honour that behaviour in software.
  • set() changes intent; update() reaches hardware. Confusing desired with mirrored is a classic first-week bug.
  • Mark hardware-updated fields volatile and model their ownership, or the mirror drifts the first time hardware acts.
  • On any mismatch, name which of the three values is wrong before suspecting the RTL — more register 'DUT bugs' are wrong access policies than real hardware defects.