UVM RAL · Chapter 2 · Register Model Basics
Modeling Field Access Policies
Section 1.5 gave you the catalog of access policies; this page shows how to model them and what to do when a field's behaviour is not in the catalog. Most of the time modelling a policy is just passing the right access string to configure. UVM ships built-in support for RW, RO, W1C, W1S, RC, WO, and many combinations, and the field applies that policy to predict its mirrored value on every operation. That automatic prediction is the whole mechanism. The interesting case is a field the catalog does not name, such as a bit that toggles on a write of one or a counter that saturates. For those you must not approximate with the nearest built-in, because it mispredicts the exact operations that make the field special. Instead you define a custom policy that teaches RAL the real transition rule. This page breaks a toggle field modelled as RW, so the mirror mispredicts every write.
Foundation12 min readUVM RALAccess Policydefine_accessCustom PolicyPredictMirror
Chapter 2 · Section 2.4 · Register Model Basics
1. Why Should I Learn This?
Modelling a policy correctly is what makes the mirror honest, and the mirror is what turns a read into a check. For the common policies this is free — the right access string and RAL predicts perfectly. The trap is the field whose behaviour is almost a built-in: a toggle that is almost W1S, a conditional clear that is almost W1C. Approximating it with the nearest built-in is the most seductive modelling error, because it compiles, it runs, and it is wrong on exactly the operations that field exists to perform.
Learning how policies are applied — and how to define a custom one — lets you refuse the approximation and model the field's actual transition rule, so the mirror predicts what the hardware really does. It is the difference between a model that verifies the field and a model that agrees with a fiction.
2. Industry Story — the bit that would not stay set
A block has a LED control bit specified as write-one-to-toggle: writing a 1 flips the bit's state, writing a 0 leaves it — a common hardware idiom for a single-line toggle. There is no W1T in the team's built-in set that the engineer remembers, so, under deadline, they model it as RW because 'writing sets it, close enough.'
The test writes 1 to turn the LED on, and the mirror — being RW — predicts the bit is now 1; the DUT, being a toggle, also goes to 1 (it was 0). It matches. Then the test writes 1 again to turn the LED off (toggle back to 0): the DUT toggles to 0, but the RW mirror predicts 1 (it wrote 1, so RW says the bit is 1). Mismatch. Every second write mismatches, in a pattern that looks like an intermittent hardware fault but is perfectly deterministic: the model and the DUT agree on the first toggle and disagree on the second, agree on the third, disagree on the fourth. Days go into 'the toggle bit is flaky' before someone notices the model's policy is not the hardware's policy — RW predicts assignment, the field does toggle, and the two only coincide when the toggle happens to land on the value RW assumed. The fix is to model the field's actual rule with a custom policy. The lesson: when the catalog does not name your field's behaviour, define the behaviour — do not approximate it with the nearest built-in, because the nearest built-in mispredicts exactly the operations that make the field special.
3. Concept — applying a policy, and defining one
Modelling a policy has two cases:
- Built-in policies (the common case). UVM ships a set of access strings —
RW,RO,W1C,W1S,W0C,W0S,RC,RS,WO,WC,WS, and combinations likeW1SRC,WRC,WSRC— and passing the string toconfigure()is all it takes. The field then applies the policy to predict its mirrored value on every access: a write goes through the policy's write rule, a read through its read rule, and the mirror is updated accordingly. This prediction is automatic and is the mechanism the whole mirror rests on. - Custom policies (the catalog gap). When a field's behaviour is not a built-in — write-one-to-toggle, saturating counter, conditional clear — you register a user-defined access policy with
uvm_reg_field::define_access("W1T")and provide the transition rule (via a custom field subtype that overrides the prediction, or a policy hook), so RAL predicts the field by your rule rather than a built-in one. The point is to make the mirror apply the field's real(on_read, on_write)function, whatever it is.
The pivotal idea is that a policy is applied to the mirror on every operation. Here is a W1C write flowing through the field's policy to update the mirror and drive the bus:
4. Mental Model — the policy is the field's transition rule, and RAL runs it
5. Working Example — a built-in applied, and a custom policy defined
The built-in case is a string; the field applies it automatically:
// Built-in: W1C. Passing the string is the entire modelling step.
pending.configure(this, 1, 0, "W1C", 0, 1, 0, 0);
// On a write of 1, the field applies W1C and predicts the mirror cleared to 0 — automatically.
pending.write(s, 1'b1); // mirror(pending) predicted 0; no custom code neededThe custom case teaches RAL a rule the catalog does not have — here, write-one-to-toggle:
// 1. Register the new access name once (e.g., in an initial block or package init).
initial void'(uvm_reg_field::define_access("W1T")); // write-1-to-toggle
// 2. Provide the transition rule. A focused approach: a field subtype whose
// post-predict adjusts the mirror to the field's real behaviour.
class w1t_field extends uvm_reg_field;
`uvm_object_utils(w1t_field)
function new(string name = "w1t_field"); super.new(name); endfunction
// Apply the toggle rule: on a write, each written 1 flips the bit; 0 leaves it.
virtual function void do_predict(uvm_reg_item rw,
uvm_predict_e kind = UVM_PREDICT_DIRECT,
uvm_reg_byte_en_t be = -1);
if (rw.kind == UVM_WRITE) begin
// toggle = current XOR write-data; model it, then let the base bookkeeping run.
rw.value[0] = get_mirrored_value() ^ rw.value[0];
end
super.do_predict(rw, kind, be);
endfunction
endclass// 3. Use the custom field + access. Now the mirror toggles like the hardware.
led = w1t_field::type_id::create("led");
led.configure(this, 1, 0, "W1T", 0, 0, 1, 0);
led.write(s, 1'b1); // DUT toggles 0->1; mirror predicts 1 (0 XOR 1) -> match
led.write(s, 1'b1); // DUT toggles 1->0; mirror predicts 0 (1 XOR 1) -> match (RW would have said 1)The built-in path is a string; the custom path is the field's real transition function taught to RAL, so the mirror predicts a toggle on every write instead of an assignment on every other one.
6. Debugging Session — the toggle modelled as read-write
A write-one-to-toggle field modelled RW because it was the closest built-in makes the mirror mispredict every write
NEAREST-MATCH POLICY// LED is write-one-to-toggle in hardware, but modelled with the nearest built-in:
led.configure(this, 1, 0, "RW", 0, 0, 1, 0); // BUG: RW predicts assignment, not toggle
led.write(s, 1'b1); // DUT: 0 -> 1 (toggle). RW mirror: predicts 1. MATCH (by luck)
led.write(s, 1'b1); // DUT: 1 -> 0 (toggle). RW mirror: predicts 1. MISMATCH
led.write(s, 1'b1); // DUT: 0 -> 1 (toggle). RW mirror: predicts 1. MATCH (by luck)The toggle bit mismatches on every other write in a perfectly regular pattern — match, mismatch, match, mismatch — which reads as an intermittent or flaky hardware fault because the mismatches are periodic rather than constant. The DUT is toggling exactly as specified; the confusion is that the model agrees on the writes where a toggle happens to land on the value RW assumed (going to 1) and disagrees on the writes where the toggle goes the other way (back to 0). Time is lost hunting a hardware race that does not exist.
The field's modelled policy is not its hardware policy. RW predicts that a write assigns the written value, so after writing 1 it always predicts 1. The hardware toggles: writing 1 flips the bit, so the true value alternates 1, 0, 1, 0. The two coincide only when the toggle happens to produce the value RW assumed — every time the bit goes to 1 — which is every other write, producing the periodic mismatch. The DUT is correct; the model applied the wrong transition function because it approximated a behaviour the catalog did not name with the nearest one that did. A nearest-match policy is wrong precisely on the operations that distinguish the real field from the approximation.
Model the field's actual rule with a custom policy, as in Section 5: register a W1T access and provide the toggle transition (mirror XOR write-data) so the field predicts a flip on every write. Now the mirror alternates with the DUT and every write matches. The rule the bug teaches: when the catalog does not name your field's behaviour, define the behaviour with a custom policy — never approximate with the nearest built-in, because the approximation mispredicts exactly the operations that make the field special, and a model that is right by coincidence fails the moment the coincidence breaks.
7. Common Mistakes
- Approximating a non-catalog behaviour with the nearest built-in. A toggle as
RW, a conditional clear asW1C— right by coincidence, wrong on the defining operations. - Writing a custom policy for a plain built-in. Over-engineering; if the behaviour is
W1C, use the string. - Forgetting to
define_accessbefore using a custom access name. The name must be registered or the field rejects it. - Putting the transition rule in the test instead of the model. Predicting the field's behaviour by hand in stimulus, rather than in the field, means every test re-implements it and the mirror is not self-consistent.
- Not testing the custom policy's boundary behaviour. A saturating or toggling field needs a test that exercises the transition the built-in would get wrong.
8. Industry Best Practices
- Use built-in access strings for catalog behaviours. Select the policy by name; let RAL apply it automatically.
- Define a custom policy for anything the catalog does not name. Register the access and provide the real transition rule in a field subtype so the mirror predicts correctly.
- Keep the transition rule in the model, not the stimulus. The field owns its behaviour; tests should not hand-predict it.
- Write a policy behaviour test that targets the divergence. Exercise the second toggle, the saturation, the conditional clear — the operations a nearest-match policy would fail.
- Prefer generated models where the generator supports custom policies. IP-XACT/RALF can carry non-standard access definitions consistently (Chapter 13).
9. Interview / Review Questions
10. Key Takeaways
- Modelling a built-in policy is just the access string — the field automatically applies the policy to predict the mirror on every operation, which is the mechanism the whole mirror rests on.
- UVM ships
RW,RO,W1C,W1S,RC,WO, and many combinations; select the one that is the behaviour. - For behaviour the catalog does not name, define a custom policy (
define_accessplus a transition rule in a field subtype) — teach RAL the field's real(on_read, on_write)function. - Never approximate a non-catalog field with the nearest built-in — it mispredicts exactly the operations that make the field special, producing a periodic, misleading mismatch (the toggle-as-
RWbug). - The transition rule belongs to the model, not the test, so the field's mirror is self-consistent and every read self-checks.