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 explicitpredict(). - Actual — the value the silicon (or RTL) genuinely holds. RAL never sees this directly except by reading the DUT; a
readfetches 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 ofvisv.RO— read-only status; software writes are ignored. Mirror is driven by hardware, not by writes.W1C— write-one-to-clear; writing1clears the bit, writing0leaves it. Mirror after writing1is0.RC— read-to-clear; the act of reading clears the field. Mirror after a read is0.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:
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:
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
endclassNow watch the three values move, and note that the policy — not the API — decides each outcome:
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
A write-one-to-clear interrupt bit modelled as plain read-write makes the mirror predict the opposite of the hardware
ACCESS POLICY// 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 'h0Every 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.
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.
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 encodeRO,W1C,RC,WOwhere they belong. - Confusing desired with mirrored.
set()changes intent, not hardware; nothing reaches the DUT untilupdate(). Expecting aset()to change what a read returns is a classic first-week bug. - Ignoring
volatileon 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 matchingupdate(), or an expectation that aset()changed hardware, is an immediate flag. - Write one deliberate policy test per exotic field. For each
W1C/RC/WOfield, 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 values — desired (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.