Skip to content

UVM RAL · Chapter 11 · Debugging RAL

Adapter Bug Debug

The adapter is the two-way translator that lets the register model speak to a real bus: reg2bus turns a register operation into a bus transaction on the way out, and bus2reg turns the bus transaction back into a register result on the way in. An adapter bug is a translation bug, so the fast way to root-cause one is to treat reg2bus and bus2reg as a round trip and check three fidelities on their own: data, does it survive unchanged through byte lanes and alignment; address, does it map to the right register; and status, does bus2reg map the bus response faithfully. This page also shows the frontdoor-versus-backdoor test that pins the fault on the bus path, then breaks the signature bug where bus2reg hardcodes OK status and silently swallows every bus error.

Foundation12 min readUVM RALdebuggingadapterreg2busbus2regstatus

Chapter 11 · Section 11.3 · Debugging RAL

1. Why Should I Learn This?

The adapter sits on the path every frontdoor access takes, so a bug in it corrupts data, misroutes addresses, or — most insidiously — swallows errors, and none of those are the register's fault. Knowing to first localize to the bus path (frontdoor wrong, backdoor right) and then check the three fidelities — data, address, status — across the reg2bus/bus2reg round trip is what turns a confusing access-path failure into a precise adapter fix.

Learning adapter debugging completes the mirror (11.1) and prediction (11.2) methods: the frontdoor-vs-backdoor test that those methods use to rule out the bus path is exactly the one that rules in the adapter here, and the round-trip check localizes which translation broke.

2. Industry Story — the negative tests that always passed

A team's negative register tests — the ones that write an illegal address or a protected register and expect a bus errorall pass. That looks like good news, until someone notices they pass too reliably: even a deliberately-broken DUT that should error still reports the access as successful. The negative tests were not verifying anything; they were incapable of failing.

The adapter's bus2reg was not mapping the bus error response to status: it hardcoded UVM_IS_OK (it ignored the transaction's response field entirely). So every access — including ones the bus errored — came back to the register layer as UVM_IS_OK. The negative tests, which check that an illegal access returns UVM_NOT_OK, could never see a NOT_OK, so they 'passed' by never detecting the error they existed to detect — and, worse, real bus errors in positive tests were silently masked too. It was not a DUT bug or a test bug; it was a status-fidelity bug in the adapter, swallowing every error at the translation boundary. Once bus2reg mapped the protocol error response to UVM_NOT_OK, the negative tests started actually failing on non-errors and passing on real errors — verifying, at last. The post-mortem lesson: an adapter's bus2reg must faithfully map the bus response to the register status, or bus errors are silently reported as OK — negative tests pass wrongly and real errors are masked; check status fidelity as a first-class part of adapter debugging, because a swallowed-error adapter has no visible symptom until you test that an error actually produces UVM_NOT_OK.

3. Concept — three fidelities across the round trip, localized by frontdoor-vs-backdoor

An adapter bug is a translation bug. The method has two moves: localize to the adapter, then check the three fidelities.

  • Localize with frontdoor-vs-backdoor. Read/write a register frontdoor (through the adapter) and backdoor (peek/poke, bypassing it, 8.4). If the frontdoor is wrong but the backdoor is right, the bus path is at fault, and the adapter is the prime suspect (this is the same test that 11.1 uses to rule out the bus path).
  • Then check the three fidelities across reg2bus -> bus -> bus2reg:
    • Data fidelity. Does data survive the round trip unchanged? Byte-lane, alignment, and width errors corrupt read/write data. Test: write a known value, confirm it arrives (and reads back) bit-exact.
    • Address fidelity. Does reg2bus place the register's address correctly? A wrong address hits the wrong register — looks like an addressing bug but lives in the adapter.
    • Status fidelity. Does bus2reg map the bus response to the register status faithfully? An error response must become UVM_NOT_OK; if bus2reg ignores it (or hardcodes OK), errors are silently swallowed.
  • The invisible one is status. Data and address bugs usually show wrong values; a status bug shows nothing until you specifically test that an error produces UVM_NOT_OK — so test it explicitly.

Here is the round trip with the status link that silently drops the error highlighted:

Adapter round trip: reg2bus builds the bus txn, bus returns an error response, bus2reg drops the error and reports OKregister modeladapter (reg2bus /bus2reg)bus / DUTwrite(addr, data)reg2bus -> bus txn (ADDRESS + DATA fidelity)reg2bus -> bus txn(ADDRESS + DATA…response = ERROR(SLVERR/DECERR)bus2reg -> status = UVM_IS_OK (BUG: error dropped)bus2reg -> status =UVM_IS_OK (BUG:…negative test sees OK -> passes wrongly; real errors maskednegative test seesOK -> passes…
Figure 1 — the adapter round trip and the three fidelities. reg.write goes through reg2bus (register op -> bus txn: check ADDRESS + DATA fidelity), onto the bus, which returns a response; bus2reg converts it back (bus txn -> register result: check DATA + STATUS fidelity). The signature bug is in the STATUS link: if bus2reg does not map the bus ERROR response to UVM_NOT_OK — here it hardcodes OK — the error is silently dropped, the register layer sees UVM_IS_OK, and negative tests pass wrongly while real errors are masked. Localize to the adapter first with frontdoor-vs-backdoor (frontdoor wrong, backdoor right = bus path), then round-trip-check data, address, and status.

4. Mental Model — the adapter is a translator; check it word-for-word, both directions, including the tone

5. Working Example — the round-trip check, including a forced error

Localize to the adapter, then check data, address, and status fidelity — forcing an error for the silent one:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// LOCALIZE: frontdoor vs backdoor. If frontdoor is wrong but backdoor is right, it's the BUS PATH (adapter).
uvm_reg_data_t fd, bd;  uvm_status_e s;
reg_h.write(s, 32'hA5A5_1234);
reg_h.read(s, fd);           // frontdoor: through the adapter
reg_h.peek(s, bd);           // backdoor: bypasses the adapter (8.4)
if (fd !== bd)
  `uvm_info("ADPDBG", "frontdoor != backdoor -> bus path -> suspect the ADAPTER (not mirror/prediction)", UVM_LOW)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// DATA + ADDRESS fidelity: write a known value, confirm it round-trips bit-exact to the right register.
reg_h.write(s, 32'hDEAD_BEEF);
reg_h.read(s, fd);
if (fd !== 32'hDEAD_BEEF)
  `uvm_error("ADPDBG", "data not preserved round-trip -> reg2bus/bus2reg byte-lane/alignment/width bug")
// (a wrong-register response instead would indicate an ADDRESS-fidelity bug in reg2bus)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// STATUS fidelity — the SILENT one: FORCE a bus error and confirm it becomes UVM_NOT_OK.
// Drive an access the DUT should error on (illegal/protected), and check the status:
reg_h.write(s, .value(32'h0), .path(UVM_FRONTDOOR));   // an access the bus should ERROR
if (s != UVM_NOT_OK)
  `uvm_error("ADPDBG", "bus errored but status is not UVM_NOT_OK -> bus2reg is SWALLOWING the error response")
// This test is the ONLY way to catch a status-fidelity bug: it has no wrong-value symptom.

The frontdoor-vs-backdoor localizes to the adapter; the round trip checks data and address by value; and the forced error is the only way to check status — because a swallowed error produces no wrong value, just a wrong (OK) status. The next section is that exact bug.

6. Debugging Session — a bus2reg that swallows every error

1

A bus2reg that ignores the response field and hardcodes OK status makes every errored access return UVM_IS_OK, so negative tests pass wrongly and real errors are masked

MAP THE BUS RESPONSE TO STATUS
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// bus2reg builds the register op from the bus txn but IGNORES the response field, hardcoding OK:
virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
  bus_txn t;  $cast(t, bus_item);
  rw.addr   = t.addr;
  rw.data   = t.data;
  rw.kind   = t.write ? UVM_WRITE : UVM_READ;
  rw.status = UVM_IS_OK;    // BUG: hardcoded OK — the bus ERROR response (t.resp) is never mapped
endfunction
// Every access — including ones the bus ERRORED — returns UVM_IS_OK to the register layer.
Symptom

Negative tests — which drive an illegal or protected access and expect UVM_NOT_OKall pass, even against a DUT deliberately broken to error, because they never see a NOT_OK. The tests are incapable of failing: they pass by never detecting the error they exist to detect. Simultaneously, real bus errors in positive tests are silently masked — an access that errored on the bus reports success to the register layer, with no wrong data value to notice (the data may even be valid). There is no loud symptom; the only tell is that no access ever returns UVM_NOT_OK, which you see only if you specifically test for it.

Root Cause

A status-fidelity bug in the adapter's bus2reg. bus2reg's job is to translate the bus transaction — including its response — back into a register result, and the response must be mapped to the register status (UVM_IS_OK for a normal response, UVM_NOT_OK for a protocol error like SLVERR/DECERR). Here bus2reg ignored the transaction's response field entirely and hardcoded rw.status = UVM_IS_OK, so every access — errored or not — returned OK to the register layer. Negative tests, which assert UVM_NOT_OK on an illegal access, could never observe one, so they 'passed' vacuously; and genuine errors in normal tests were swallowed, masking real failures. It is not the mirror (the model was never even told an error occurred) and not prediction (the pipeline faithfully carried a wrong status); it is the translation layer dropping the error tone. The failure is uniquely silent because a swallowed error produces no wrong value — data and address may be perfectly fine — so only a test that forces an error and checks for UVM_NOT_OK can reveal it. The frontdoor-vs-backdoor localizer would also implicate the adapter (backdoor has no status/response concept; the frontdoor status is wrong), and the round-trip check's status leg is what pins it.

Fix

Map the bus response to the register status in bus2reg: set rw.status = (t.resp == ERROR) ? UVM_NOT_OK : UVM_IS_OK (translating SLVERR/DECERR or the protocol's error encoding to UVM_NOT_OK), so errored accesses reach the register layer as UVM_NOT_OK. After the fix, negative tests actually verify (failing on a non-error, passing on a real error) and real errors surface in positive tests. The method the debug teaches: adapter debugging checks three fidelities across the reg2bus/bus2reg round trip — data (unchanged?), address (right register?), and status (does bus2reg map the bus response to UVM_NOT_OK?) — and status is the silent one: a swallowed error has no wrong-value symptom, so you must force a bus error and confirm it produces UVM_NOT_OK. Localize to the adapter first with frontdoor-vs-backdoor (frontdoor wrong, backdoor right = bus path), then round-trip-check data, address, and — explicitly — status.

7. Common Mistakes

  • Not testing status fidelity. A bus2reg that swallows errors has no wrong-value symptom — force a bus error and confirm it returns UVM_NOT_OK, or the bug hides.
  • Trusting negative tests that always pass. Negative tests that cannot fail (never see NOT_OK) are a status-fidelity red flag, not good news.
  • Blaming the register/DUT for a bus-path failure. Frontdoor wrong but backdoor right = the adapter, not the register (11.1) or prediction (11.2).
  • Overlooking byte-lane/alignment in reg2bus/bus2reg. Data-fidelity bugs corrupt values on the round trip — test bit-exact preservation.
  • Assuming address bugs are 'addressing' bugs. A reg2bus that mis-places the address hits the wrong register but lives in the adapter.

8. Industry Best Practices

  • Localize with frontdoor-vs-backdoor first. Frontdoor wrong, backdoor right = the bus path (adapter) — before checking the register or prediction.
  • Round-trip-check all three fidelities. Data (bit-exact), address (right register), status (response mapped) across reg2bus/bus2reg.
  • Test status explicitly by forcing an error. The only way to catch a swallowed-error bus2reg — drive an erroring access and assert UVM_NOT_OK.
  • Map every protocol response encoding. SLVERR/DECERR (or the protocol's errors) must become UVM_NOT_OK; do not hardcode status.
  • Distrust negative tests that never fail. A negative test incapable of producing NOT_OK is not verifying error handling.

9. Interview / Review Questions

10. Key Takeaways

  • The adapter is the two-way translator between register ops and bus transactions — reg2bus outbound, bus2reg inbound (5.x) — so an adapter bug is a translation bug on the path every frontdoor access takes.
  • Localize to the adapter with frontdoor-vs-backdoor: if the frontdoor is wrong but the backdoor is right, the bus path is at fault (not the mirror 11.1 or prediction 11.2) and the adapter is the prime suspect.
  • Then check three fidelities across the round trip: data (survives reg2bus->bus->bus2reg bit-exact?), address (right register?), and status (bus2reg maps the bus response to UVM_IS_OK/UVM_NOT_OK?).
  • Status is the silent one: a bus2reg that swallows errors (hardcodes OK) produces no wrong value — negative tests pass wrongly and real errors are masked; the only way to catch it is to force a bus error and confirm UVM_NOT_OK.
  • Map every protocol error encoding (SLVERR/DECERR) to UVM_NOT_OK, distrust negative tests that never fail, and treat wrong-value round-trip failures as data/address fidelity bugs in the adapter, not the register.