Part 9 · Register Model (RAL) · Intermediate
Backdoor HDL Path
Model and use HDL path access with add_hdl_path_slice, including direct uvm_hdl_read and uvm_hdl_deposit behavior.
Backdoor path fundamentals
Backdoor accesses bypass the bus and operate directly on RTL storage elements through hierarchical HDL paths. This yields near-zero simulation-time setup and quick snapshots.
The key dependency is path correctness. If the path is stale after RTL refactor, backdoor reads and writes silently target wrong logic unless your checks catch it.
[RAL][HDL] backdoor operation chain
RAL write/read with UVM_BACKDOOR
|
v
register resolves HDL path slices
|
v
uvm_hdl_deposit / uvm_hdl_read
|
v
simulator VPI/DPI bridge
|
v
RTL variable update or read
|
v
mirror/predict policy updateBackdoor speed is excellent for large reset-state initialization.
Backdoor does not prove bus decode, protocol timing, or access arbitration.
Keep path registration close to model build for maintainability.
Modeling with add_hdl_path_slice
Use add_hdl_path_slice to map register bits to concrete RTL fields. This is common when one architectural register spans multiple HDL signals.
class my_block extends uvm_reg_block;
`uvm_object_utils(my_block)
rand ctrl_reg ctrl;
rand status_reg status;
virtual function void build();
ctrl = ctrl_reg::type_id::create("ctrl");
status = status_reg::type_id::create("status");
ctrl.configure(this);
status.configure(this);
ctrl.build();
status.build();
default_map = create_map("default_map", 0, 4, UVM_LITTLE_ENDIAN);
default_map.add_reg(ctrl, 'h00, "RW");
default_map.add_reg(status, 'h04, "RO");
// HDL root for backdoor resolution
add_hdl_path("tb_top.dut.u_regfile");
// ctrl register slices
ctrl.add_hdl_path_slice("ctrl_q", 0, 32);
// status register composed from two separate HDL fields
status.add_hdl_path_slice("status_low_q", 0, 16);
status.add_hdl_path_slice("status_hi_q", 16, 16);
lock_model();
endfunction
endclass[HDL] slice mapping example
Architectural register: status[31:0]
status[15:0] -> dut.u_regfile.status_low_q[15:0]
status[31:16] -> dut.u_regfile.status_hi_q[15:0]
RAL composes/decomposes these slices for backdoor read/writeSlice offsets and widths must match the spec-level register layout exactly.
Composite mappings are powerful for split-status implementations.
Path naming should remain stable across RTL hierarchy changes when possible.
Using uvm_hdl_read and uvm_hdl_deposit
RAL backdoor APIs call HDL access under the hood. Direct uvm_hdl_read and uvm_hdl_deposit are still useful for targeted debug probes and triage scripts.
task backdoor_probe();
uvm_status_e status;
uvm_reg_data_t v;
uvm_hdl_data_t raw;
string hpath = "tb_top.dut.u_regfile.ctrl_q";
// RAL backdoor write and read
ral.ctrl.write(status, 32'h0000_0003, UVM_BACKDOOR, .parent(this));
ral.ctrl.read(status, v, UVM_BACKDOOR, .parent(this));
`uvm_info("BD", $sformatf("RAL backdoor ctrl=0x%08h", v), UVM_LOW)
// Direct HDL helpers
if (!uvm_hdl_read(hpath, raw))
`uvm_error("BD", $sformatf("uvm_hdl_read failed path=%s", hpath))
else
`uvm_info("BD", $sformatf("HDL read raw=0x%08h", raw), UVM_LOW)
if (!uvm_hdl_deposit(hpath, 32'h0000_00AA))
`uvm_error("BD", $sformatf("uvm_hdl_deposit failed path=%s", hpath))
endtask[HDL] read/deposit semantics
uvm_hdl_read(path, value):
returns current resolved HDL value
uvm_hdl_deposit(path, value):
deposits value now (normal drivers may later overwrite)
In force-like use cases, simulator-specific force/release APIs may be needed.Direct HDL functions are useful when isolating path failures from RAL logic.
Deposit semantics differ from force semantics; know which behavior you need.
Always log path strings in failures to speed hierarchy debug.
Backdoor debugging checklist
[RAL][HDL] backdoor triage flow
backdoor read returns wrong value
|
+--> verify add_hdl_path root and slice paths
+--> verify offsets and widths for each slice
+--> run direct uvm_hdl_read on each leaf path
+--> check simulator visibility/optimization switches
+--> confirm reset/clock logic is not immediately rewriting value
+--> compare with waveform at same timepointfunction void dump_status_slices();
uvm_hdl_data_t lo, hi;
if (!uvm_hdl_read("tb_top.dut.u_regfile.status_low_q", lo))
`uvm_error("BD", "status_low_q read failed")
if (!uvm_hdl_read("tb_top.dut.u_regfile.status_hi_q", hi))
`uvm_error("BD", "status_hi_q read failed")
`uvm_info("BD", $sformatf("slice lo=0x%04h hi=0x%04h", lo, hi), UVM_LOW)
endfunctionKey takeaways
Backdoor power comes from accurate HDL path and slice modeling.
uvm_hdl_read and uvm_hdl_deposit are core tools for backdoor triage.
Treat path definitions as first-class verification assets and review them regularly.
Common pitfalls
Assuming a single add_hdl_path handles split registers without per-slice mapping.
Using outdated hierarchical paths after RTL refactors.
Confusing deposit with persistent force and misreading post-clock behavior.