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.

diagram
[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 update
  • Backdoor 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.

systemverilog
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
diagram
[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/write
  • Slice 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.

systemverilog
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
diagram
[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

diagram
[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 timepoint
systemverilog
function 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)
endfunction

Key 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.