UVM RAL · Chapter 11 · Debugging RAL
Backdoor Path Debug
Backdoor peek and poke reach a register's RTL storage directly through its HDL path, bypassing the bus, adapter, mirror, and prediction, so a backdoor bug lives in one place: the path does not resolve to the storage you intended. The discipline is simple. Never trust a backdoor value you have not proven resolves. The symptom family is small too. A peek that reads X or a poke with no effect means the path reaches nothing. A value that stays constant regardless of index means a memory path was not indexed. A value that disagrees with a known-good frontdoor read means the path resolves, but to the wrong place. This lesson teaches proving resolution with a known-value probe and the built-in path check, and breaks a peek X from a wrong root that gets misread as a reset bug.
Foundation12 min readUVM RALdebuggingbackdoorhdl_pathresolution
Chapter 11 · Section 11.4 · Debugging RAL
1. Why Should I Learn This?
The backdoor bypasses the bus, adapter, mirror, and prediction, so when a backdoor value is wrong the cause is almost always the hdl_path not resolving — and a backdoor value you have not proven resolves can silently mislead every setup and check that relies on it (8.4). Knowing the small symptom family (X/no-effect, stale-regardless-of-index, disagrees-with-frontdoor) and the prove-it-resolves discipline is what keeps you from building on a path that reaches nothing or the wrong thing.
Learning backdoor path debugging completes the debug quartet: 11.1–11.3 handle the bus-path layers, and this handles the HDL-path layer that sits entirely outside them — and it is the one whose failures most often masquerade as DUT bugs.
2. Industry Story — the reset 'bug' that was an X from nowhere
A team's backdoor peek of a register out of reset returns X. The reading is immediate: 'the DUT is not resetting this register — bit-level X means uninitialized hardware,' and a reset bug is filed against the RTL. A designer investigates correct reset logic for a day, because the register does reset properly.
The peek returned X not because the register held X, but because the hdl_path did not resolve — the hdl_path root was wrong (a mis-named hierarchy level), so the backdoor read reached nothing, and 'nothing' reads as X. The X was not a value the register held; it was the absence of a resolved path. The team misread an unresolved path as a DUT reset bug, chasing hardware that was fine. Running the built-in HDL-path check would have flagged the path as unresolvable in seconds; a known-value probe (poke a value, peek it back) would have shown the poke had no effect — the tell of a path reaching nothing. Once the root was corrected, the peek returned the register's real (correct) reset value. The post-mortem lesson: a backdoor X is usually an unresolved hdl_path (wrong root/hierarchy/slice), not a DUT value — an X is the absence of a resolved path, not 'the register holds X'; never read meaning into a backdoor value you have not proven resolves, and verify paths with the built-in HDL-path check or a known-value probe before trusting (or blaming the DUT for) any backdoor result.
3. Concept — prove resolution; separate 'unresolved' from 'wrong place'
A backdoor failure is a path-resolution failure. The method: prove the path resolves, and classify the symptom.
- The discipline: prove it resolves first. Do not read meaning into any backdoor value until the path is proven to resolve. Two tools:
- the built-in HDL-path check (
uvm_reg_mem_hdl_paths_seq, 4.7) — validates that every register's path resolves; - a known-value probe —
pokea known value,peekit back, and cross-check a frontdoor read; agreement proves the path reaches the right storage.
- the built-in HDL-path check (
- Symptom triage:
peekreads X /pokehas no effect -> the path does not resolve to real storage: a typo, wronghdl_pathroot, missing hierarchy level, or wrong slice width. The X is absence of a path, not a held value.- Value stale/constant regardless of index -> for a memory, the path is not indexed per location (8.4); or the path resolves to a constant signal.
- Backdoor disagrees with a known-good frontdoor -> the path resolves, but to the wrong register/bit.
- The key distinction: does not resolve (X / no-effect — loud, obviously broken) vs resolves to the wrong place (a consistent, plausible, wrong value — subtle and dangerous, because it looks like a real value).
Here is the backdoor symptom-triage flow:
4. Mental Model — a backdoor value is only meaningful once the address is proven real
5. Working Example — proving resolution with a known-value probe
Prove the path resolves before trusting it, and classify a failure by symptom:
// PROVE RESOLUTION with a known-value probe: poke a chosen value, peek it back, cross-check frontdoor.
uvm_reg_data_t pk, fd; uvm_status_e s;
reg_h.poke(s, 32'hA5A5_1234); // write a KNOWN value directly to storage
reg_h.peek(s, pk); // read it back the backdoor way
reg_h.read(s, fd); // and a frontdoor read for cross-check
if (pk !== 32'hA5A5_1234)
`uvm_error("BKDDBG", "poke had NO EFFECT / peek != poked value -> path does NOT resolve (wrong root/slice)")
else if (fd !== pk)
`uvm_error("BKDDBG", "peek != frontdoor -> path RESOLVES but to the WRONG register/bit")
else
`uvm_info("BKDDBG", "poke==peek==frontdoor -> path PROVEN to resolve to the intended storage", UVM_LOW)// Or use the built-in HDL-path check to validate ALL paths resolve before relying on any of them (4.7):
uvm_reg_mem_hdl_paths_seq hp = uvm_reg_mem_hdl_paths_seq::type_id::create("hp");
hp.model = reg_model;
hp.start(null); // reports registers whose hdl_path does not resolve — run this BEFORE trusting backdoor// SYMPTOM triage once you observe a failure:
// peek X / poke no-effect -> UNRESOLVED path (typo, wrong root, missing hierarchy, wrong slice)
// stale/constant regardless of i -> memory path NOT INDEXED (8.4) or a constant signal
// backdoor != known-good frontdr -> resolves to the WRONG register/bit
// An X is the ABSENCE of a resolved path — NOT 'the register holds X'. Do not file a DUT bug on an X.The known-value probe (poke/peek/frontdoor agreement) proves the path reaches the intended storage; without that proof, a backdoor value — especially a plausible one — means nothing. The next section is an X misread as a DUT bug.
6. Debugging Session — a peek X misread as a reset bug
A backdoor peek returns X because the hdl_path root is wrong, so the path resolves to nothing — and the X is misread as a DUT reset bug instead of an unresolved path
X = UNRESOLVED PATH, NOT A HELD VALUE// The hdl_path ROOT is wrong (mis-named hierarchy level), so the backdoor reaches NOTHING:
reg_model.default_map.set_hdl_path_root("tb.dutt"); // BUG: 'dutt' — real hierarchy is 'tb.dut'
status_reg.add_hdl_path_slice("status_q", 0, 32);
// A backdoor peek of status_reg resolves to nothing -> returns X. The register itself resets fine.A backdoor peek of a register out of reset returns X. The immediate (wrong) reading is 'the DUT is not resetting this register — X means uninitialized hardware,' and a reset bug is filed against the RTL. A designer investigates the reset logic — which is correct — and finds nothing, because the register does reset properly. The X is constant (every peek returns X, regardless of DUT state), and a poke to the same register has no effect on a subsequent peek — both tells of a path reaching nothing, but they are easy to miss if you have already decided the X is a held value.
The hdl_path did not resolve: the hdl_path root was mis-named (tb.dutt instead of tb.dut), so the backdoor read reached no signal at all, and an unresolved backdoor read returns X. The X is therefore the absence of a resolved path — 'there is nothing at this address' — not the register's value; the register itself holds its correct reset value, reachable only if the path resolves. The failure was misdiagnosed because X was read as a held value (uninitialized hardware -> reset bug) rather than as unresolved-path. Confirming would have been instant: the built-in HDL-path check would flag status_reg's path as unresolvable, and a known-value probe would show a poke has no effect (peek still X) — the definitive signature of a path reaching nothing. It is not a DUT bug, a mirror bug (11.1), a prediction bug (11.2), or an adapter bug (11.3) — those are all bypassed by the backdoor; it is a path-resolution bug in the HDL-path layer.
Correct the hdl_path root to the real hierarchy (tb.dut), so the path resolves to the register's actual storage, and the peek returns the correct reset value. Then prove it with a known-value probe (poke/peek/frontdoor agreement) and run the built-in HDL-path check (uvm_reg_mem_hdl_paths_seq) to validate all paths resolve. The method the debug teaches: a backdoor X is almost always an unresolved hdl_path (wrong root/hierarchy/slice), not a DUT value — an X is the absence of a resolved path, so never file a DUT/reset bug on a backdoor X without first proving the path resolves. More generally: prove resolution (HDL-path check or known-value probe) before trusting any backdoor value, and distinguish unresolved (X / no-effect — loud) from resolves-to-the-wrong-place (plausible but wrong — subtle, caught only by cross-checking against a known-good frontdoor).
7. Common Mistakes
- Reading a backdoor X as a held value. An X is almost always an unresolved path (wrong root/hierarchy/slice) — the absence of a path, not 'the register holds X.' Prove resolution before blaming the DUT.
- Trusting a plausible backdoor value without proof. A path can resolve to the wrong register and return a believable-but-wrong value — cross-check against a known-good frontdoor.
- Not proving resolution first. Run the built-in HDL-path check or a poke-known-value/peek-back probe before relying on any backdoor read.
- Missing memory indexing. A backdoor value stale/constant regardless of index is an unindexed memory path (8.4), not a data bug.
- Confusing a path bug with mirror/prediction/adapter bugs. The backdoor bypasses all of those — a backdoor failure is a path-resolution bug.
8. Industry Best Practices
- Prove the path resolves before trusting any backdoor value. Known-value probe (poke/peek/frontdoor agreement) or the built-in HDL-path check (4.7).
- Treat a backdoor X as an unresolved path. Check the root, hierarchy, and slice before considering a DUT/reset bug.
- Cross-check backdoor against a known-good frontdoor. Catches a path that resolves to the wrong register — the subtle, plausible-but-wrong case.
- Run
uvm_reg_mem_hdl_paths_seqin bring-up. Validate that every register's path resolves before any test relies on backdoor. - Distinguish unresolved from wrong-place. X/no-effect is loud; a consistent wrong value is subtle — different symptoms, both path bugs.
9. Interview / Review Questions
10. Key Takeaways
- Backdoor
peek/pokereach RTL storage through thehdl_path, bypassing the bus, adapter, mirror, and prediction — so a backdoor failure is an HDL-path resolution bug, a layer apart from 11.1/11.2/11.3. - Never trust a backdoor value you have not proven resolves — use a known-value probe (poke known value / peek back / cross-check frontdoor) or the built-in HDL-path check (
uvm_reg_mem_hdl_paths_seq, 4.7). - Symptom triage:
peekX /pokeno-effect = path does not resolve (wrong root/hierarchy/slice/typo); stale/constant regardless of index = memory path not indexed (8.4) or a constant signal; disagrees with a known-good frontdoor = resolves to the wrong register/bit. - A backdoor X is the absence of a resolved path, not 'the register holds X' — the signature bug is an X misread as a DUT/reset bug when the
hdl_pathroot/hierarchy is wrong; never file a DUT bug on an unproven backdoor X. - Distinguish 'does not resolve' (loud: X/no-effect) from 'resolves to the wrong place' (subtle: plausible-but-wrong) — the second is more dangerous and is caught only by cross-checking against an independent known-good frontdoor, since a backdoor self-round-trip agrees with itself.