UVM RAL · Chapter 8 · Memories
Memory Backdoor Access
Memory backdoor access reaches a location's RTL storage directly through the memory's HDL path, so a peek reads it and a poke writes it without any bus traffic. For memories this is essential, not just convenient. Poke seeds a large memory in simulation time instead of issuing thousands of slow frontdoor writes. Peek supplies the check that a memory model's missing mirror cannot: read a location by backdoor and compare it against the frontdoor to get an independent view of the storage. The catch is that a memory's HDL path must resolve to an addressable array that is indexed per location. If the path is written as a flat scalar, every peek and poke reaches the same one cell, silently seeding and reading the wrong place.
Foundation12 min readUVM RALbackdoorpeekpokememory hdl_path
Chapter 8 · Section 8.4 · Memories
1. Why Should I Learn This?
For memories the backdoor is not a niche convenience — it is how you set up a large memory at all (seeding a million locations through the bus is infeasible) and how you check one at all independently (because uvm_mem keeps no mirror, 8.1). Understanding the memory hdl_path — which must index into an RTL array — and the seed-then-verify and backdoor-versus-frontdoor patterns is what makes memory verification both feasible and trustworthy.
Learning memory backdoor access — indexed paths, fast seeding, and content checking against an independent view — builds on register backdoor (4.7) and the missing-mirror reality of uvm_mem (8.1), and it is the checking mechanism the memory-debugging strategies of 8.5 rely on.
2. Industry Story — the backdoor that seeded one cell a million times
A team uses poke to seed a large lookup memory before each test — far faster than frontdoor writes. The hdl_path for the memory was written pointing at the RTL array's name as if it were a single signal, with no per-location indexing. Seeding 'worked' in the sense that poke returned OK, and an early smoke test that only checked location 0 passed, so the setup was trusted.
But because the path did not index per location, every poke — for every location index — resolved to the same single cell (or, on some simulators, to X): the entire 'seed the memory' loop wrote location 0 a million times and left every other location un-seeded. Tests that read other locations then saw garbage, and a peek-based check read that same one cell regardless of the index requested, so it 'confirmed' the wrong data. The whole backdoor path was silently addressing one location instead of the array — invisible because location 0 happened to be correct and nobody checked the rest. The post-mortem lesson: a memory's hdl_path must index into the RTL array per location; written as a flat scalar, every backdoor peek/poke reaches the same one cell (or X) regardless of index, silently seeding and reading the wrong place — a path error unique to memories, caught only by exercising indices other than the one the broken path happens to hit.
3. Concept — an indexed path, fast seeding, and the check the mirror does not give
Memory backdoor access is register backdoor (4.7) with one memory-specific requirement and two memory-specific payoffs:
- The path must be indexed. A register's storage is a scalar; a memory's is an array, so its
hdl_pathmust resolve toarray[index]— it indexes per location. UVM substitutes the location index into the path when it peeks/pokes; if the path names only the array (a flat scalar), every access collapses to one cell or resolves to X. pokeseeds fast. Setting up a large memory through the frontdoor is thousands/millions of bus transactions — infeasible.pokewrites RTL storage directly, seeding the whole memory in simulation time.peekreads it instantly and side-effect-free.peeksupplies the check the mirror does not. Becauseuvm_memkeeps no mirror (8.1), a frontdoor read auto-checks nothing. A backdoorpeekgives an independent read of the storage, so a backdoor-versus-frontdoor compare verifies the bus/addressing path against the actual storage — the check for memories that a register gets from its mirror.
Here is frontdoor versus backdoor for a memory, the backdoor reaching the indexed storage directly:
Memory frontdoor vs backdoor — the backdoor indexes into the RTL array
uvm ral4. Mental Model — an indexed teleporter, and the only independent witness a memory has
5. Working Example — an indexed path, seed with poke, verify with peek
Configure an indexed hdl_path, seed the memory fast, and check the frontdoor against the backdoor:
// The memory's hdl_path must INDEX into the RTL array. UVM substitutes the location index per access.
// (API varies by version; the essential point is the path resolves to array[index], not a flat signal.)
buffer.configure(this, 1024, 32, "RW");
buffer.add_hdl_path_slice("mem_array", 0, 32); // storage is tb.dut.mem_array[<index>]
default_map.set_hdl_path_root("tb.dut");
// A CORRECT path yields tb.dut.mem_array[i] for location i — different cell per index.// SEED a large memory fast with poke — RTL-direct, no bus. Frontdoor writes would be infeasible here.
uvm_status_e s;
foreach (seed[i]) buffer.poke(s, i, seed[i]); // each i pokes a DIFFERENT cell (indexed path)
// If the path were a flat scalar, every poke would hit the SAME cell — the bug in the next section.// CHECK contents with a backdoor-vs-frontdoor compare — the independent view uvm_mem's missing mirror
// (8.1) does not give you. Read the SAME location both ways and compare.
uvm_reg_data_t fd, bd;
buffer.read(s, idx, fd); // frontdoor: exercises bus/addressing
buffer.peek(s, idx, bd); // backdoor: independent read of the storage
if (fd !== bd)
`uvm_error("MEMBKD", $sformatf("frontdoor/backdoor mismatch at %0d: fd %h bd %h", idx, fd, bd))
// Agreement cross-checks the access path against the actual storage — the memory's substitute for a mirror.The indexed path makes each poke/peek hit the right cell; the backdoor-versus-frontdoor compare is the independent check memories otherwise lack. The next section is what happens when the path does not index.
6. Debugging Session — a memory hdl_path with no per-location indexing
A memory hdl_path written as a flat scalar makes every backdoor peek/poke reach the same one cell (or X), silently seeding and reading the wrong location regardless of index
MEMORY PATH MUST INDEX// The hdl_path names the array as if it were a single signal — no per-location indexing:
buffer.configure(this, 1024, 32, "RW");
buffer.add_hdl_path_slice("mem_array_flat", 0, 32); // BUG: resolves to ONE signal, not array[index]
// Seeding loop LOOKS right but every poke hits the same cell (or X), because the path never indexes:
foreach (seed[i]) buffer.poke(s, i, seed[i]); // writes location 0's cell 1024 times; others un-seededpoke and peek return OK, and a smoke test that only checks location 0 passes — so seeding is trusted. But tests that read other locations see garbage (those locations were never actually seeded), and a peek-based check reads the same one cell no matter which index it asks for, so it 'confirms' correct data for locations that are actually wrong. On some simulators the flat path resolves to X, so peeks read X and pokes go nowhere. The unifying tell: backdoor behaviour is independent of the index — every index seems to hit the same place — which no test that only touches location 0 (the one the broken path happens to land on) will ever reveal.
A memory's RTL storage is an array, so its hdl_path must resolve to array[index] — UVM substitutes the location index into the path on each backdoor access so that location i reaches mem_array[i]. Here the path named the array as a flat scalar (mem_array_flat) with no indexing, so UVM had nothing to substitute the index into: every poke and peek, for every location index, resolved to the same single cell (or, where the simulator cannot resolve a flat name to array storage, to X). The seeding loop therefore wrote location 0's cell repeatedly and left the rest un-seeded, and the checker read that one cell regardless of the requested index. Nothing errored because each individual poke/peek is a valid HDL access to a signal — just the wrong, non-indexed one. It stayed hidden because the one cell the broken path hits (location 0) was correct, and only accesses to other indices expose that the path never varied with the index. This is a failure mode unique to memories: registers have a scalar path with no index to get wrong.
Write the hdl_path so it indexes into the array per location — resolving to mem_array[index], with UVM substituting the location index on each access (the exact API for indexed slices varies by UVM version, but the requirement is that the path varies with the index). Then verify the path across multiple indices, not just location 0: peek several locations you have poked with distinct values and confirm each reads back its own value — if they all read the same, the path is not indexing. The rule the bug teaches: a memory hdl_path must index the RTL array per location; a flat, un-indexed path makes every backdoor access hit the same cell (or X) regardless of index, silently seeding and reading the wrong place. Always test backdoor access at indices other than the one a broken path would happen to hit, because a location-0-only check cannot distinguish a correct indexed path from a broken flat one.
7. Common Mistakes
- Writing the memory
hdl_pathas a flat scalar. It must index the RTL array (array[index]); a non-indexed path hits one cell or X for every location. - Verifying backdoor access only at location 0. Location 0 is exactly the cell a broken flat path tends to hit — test other indices, with distinct values, to expose an indexing bug.
- Seeding a large memory through the frontdoor. Thousands/millions of bus transactions is infeasible —
pokeseeds RTL storage directly in simulation time. - Assuming a frontdoor memory read self-checks.
uvm_memkeeps no mirror (8.1); a backdoor-versus-frontdoor compare is how you check contents independently. - Trusting
peekfor a value the bus should have set without also checking the frontdoor. Backdoor bypasses the protocol; use it as the independent view, not a substitute for exercising the bus (4.7).
8. Industry Best Practices
- Index the memory
hdl_pathper location, and verify it across indices. Peek/poke distinct values at several indices and confirm each is independent (not all the same cell). - Seed large memories with
poke. RTL-direct seeding makes large-memory setup feasible; frontdoor seeding does not scale. - Make backdoor-versus-frontdoor compare your standard memory check. It is the independent verification
uvm_mem's missing mirror does not provide (8.1). - Verify the memory HDL path before relying on it. Confirm indexed reads/writes resolve to real, distinct storage — not one cell or X (4.7).
- Keep frontdoor for path verification, backdoor for setup and observation. The backdoor never exercises the protocol; use each for its job (4.7).
9. Interview / Review Questions
10. Key Takeaways
- Memory backdoor
peek/pokereach a location's RTL storage directly through the memory'shdl_path, bypassing the bus — same idea as register backdoor (4.7), but the path must index into the RTL array (array[index]) per location. - The backdoor is essential, not just convenient, for memories:
pokeseeds a large memory fast (frontdoor seeding does not scale), andpeeksupplies the independent check thatuvm_mem's missing mirror (8.1) does not give you. - A backdoor-versus-frontdoor compare is the memory's substitute for a register mirror — read a location both ways and assert agreement to cross-check the bus/addressing path against the storage.
- The signature bug is a flat, un-indexed
hdl_path: every backdoor access hits the same one cell (or X) regardless of index, silently seeding and reading the wrong location — a failure unique to memories. - Verify the path across multiple indices (distinct values at several locations), not just location 0 — the one cell a broken flat path happens to hit — or an indexing bug stays hidden.