Skip to content

AMBA AHB · Module 18

Wrong HRDATA Timing

Diagnosing read data returned a cycle early or late — HRDATA must be valid in the cycle the read completes (HREADY high), since the master samples it exactly then. Too early: the slave drives the data before HREADY high then changes it (not held). Too late: valid data arrives only after HREADY high (classically a registered read adding a cycle the HREADYOUT logic didn't account for), so the master sampled stale/undefined data. Diagnose by finding the completing cycle (HREADY high) and checking HRDATA holds the correct value exactly then. Distinct from misalignment (the value is right, but the cycle is off). Fix: align data validity with HREADY high — HREADYOUT and HRDATA from matching pipeline depths.

The incorrect HSEL (18.4) sent a transfer to the wrong slave; this chapter covers a read where the right slave returns valid data but at the wrong cycle: wrong HRDATA timing. The rule is precise: HRDATA must be valid in the cycle the read completes — when HREADY is high — because the master samples it exactly then (chapters 16.5, 6.1). Wrong HRDATA timing is when the read data is presented a cycle early or late relative to that sampling point, so the master captures the wrong value. Two cases: too early (the slave drives the data in a cycle before HREADY goes high, then changes it — so by the time HREADY is high, the bus holds a different value; cause: the data isn't held until completion); and too late (valid data appears only after HREADY has already gone high — so the master sampled stale/undefined data in the completing cycle; cause, classically: a registered read output adding a cycle the HREADYOUT logic didn't account for). The diagnosis: find the completing cycle (the one where HREADY is high for this read) and check that HRDATA holds the correct value exactly thenearly/late by one cycle is the bug. This is distinct from misalignment (18.3): there the value pairs with the wrong address; here the value is right but the cycle is off. The fix is to align the data validity with HREADY highHREADYOUT and HRDATA must come from matching pipeline depths. This chapter builds the diagnosis.

1. What Is It?

Wrong HRDATA timing is read data presented a cycle off from the completing cycle; debugging it means checking the data at the HREADY-high cycle. Its parts:

  • The ruleHRDATA must be valid in the cycle HREADY is high (the master samples exactly then).
  • Too early — the slave drives the data before HREADY high, then changes it → the value at completion is wrong (not held).
  • Too late — valid data arrives only after HREADY high → the master sampled stale/undefined (classically a registered read +1 cycle not in HREADYOUT).
  • The diagnosis — find the completing cycle (HREADY high) and check HRDATA holds the correct value exactly then; early/late = the bug.
The HRDATA-high rule, the too-early and too-late cases, the diagnosis, and the common causes.
Figure 1 — diagnosing wrong HRDATA timing. The rule: HRDATA must be valid in the cycle HREADY is HIGH (the master samples then). Too EARLY: the slave drives data before HREADY high then changes it → by the time HREADY is high, the bus holds a different (wrong) value (cause: data not held until completion). Too LATE: valid data appears only after HREADY high → the master sampled stale/undefined data in the completing cycle (cause: registered read +1 cycle not in HREADYOUT). Diagnosis: find the completing cycle (HREADY high for this read) and check HRDATA holds the correct value exactly then; early/late by one cycle = the bug. Distinct from misalignment (18.3): here the value is right but the cycle is off. Common causes → align data validity with HREADY high: registered read +1 not in HREADYOUT, combinational path too slow/not held, HREADY/HRDATA different timing, data released early. The fix is in the slave: make HRDATA valid (and held) exactly when its HREADYOUT goes high.

So wrong HRDATA timing is a data-valid-window bug — the read data is correct but presented in the wrong cycle, so it's not valid when the master samples it. The key to debugging it is the sampling rule: the master samples HRDATA only in the cycle HREADY is high (the completing cycle of the read). HRDATA outside that cycle is don't-care — but HRDATA in that cycle must be correct. So you find the completing cycle and check HRDATA exactly there. Too early (the data was driven and then changed before completion — not held) and too late (the data arrives after completion — the registered-read lag) are the two ways the data is valid at the wrong cycle. The crucial distinction from misalignment (18.3): in misalignment, the data is paired with the wrong address (a pipeline-pairing error); in wrong-timing, the data is the right value for the right address but in the wrong cycle (a data-valid-window error). So wrong HRDATA timing is the data-valid-window bug debugged by checking the completing cycle. So it's a right-value-wrong-cycle read bug.

2. Why Does It Exist?

Wrong HRDATA timing exists because the read has two signals — the data (HRDATA) and the completion (HREADY/HREADYOUT) — that must be co-timed (the data valid exactly when completion fires), and these come from potentially different paths/depths (the read mux vs the HREADYOUT logic), so a mismatch (a register added to one but not the other) de-co-times them — valid data at the wrong cycle.

The two co-timed signals is the root: a read transfer is defined by two things — what data (HRDATA) and when it's valid (HREADY high, the completing cycle). For a correct read, these are co-timed: the data must be valid exactly when HREADY is high. So the read's correctness depends on the relationship between two signals. So a bug in either's timing breaks the read. So wrong HRDATA timing exists because the read needs two co-timed signals. So it's a co-timing requirement. So two signals must align.

The they come from different paths drives the mismatch: HRDATA comes from the read path (the mux, possibly registered — 16.5); HREADY/HREADYOUT comes from the completion logic (the FSM/counter — 16.4). These are different logic with potentially different pipeline depths. If a register is added to one (e.g. the read path, for timing closure) but the other's timing isn't updated (the HREADYOUT still completes as if combinational), they de-co-time — the data is valid a cycle after completion (too late). So wrong HRDATA timing exists because the two signals come from paths that can drift apart. So it's a path-depth mismatch. So drift causes the bug.

The the master samples a fixed point is why it matters: the master samples HRDATA at a fixed point — the cycle HREADY is high. It can't sample "whenever the data happens to be valid"; it samples at completion. So the data must be valid at that point. If it's not (early or late), the master gets the wrong value. So wrong HRDATA timing matters because the master's sample point is fixed (at completion). So wrong HRDATA timing exists because: a read needs two co-timed signals — data and completion (the data valid exactly when HREADY is high — the why); these come from different paths/depths (read mux vs HREADYOUT logic) that can drift apart (a register on one but not the other — the mismatch); and the master samples at a fixed point (the completing cycle — so the data must be valid there — the consequence). So wrong HRDATA timing is the co-timing bug — the data and the completion de-aligned (the data valid at the wrong cycle), debugged by checking HRDATA at the completing cycle, and fixed by matching the HREADYOUT timing to the read-path depth. So this chapter teaches the completing-cycle check. So co-time the data with completion.

3. Mental Model

Model debugging wrong HRDATA timing as finding why a relay runner is grabbing the baton at the wrong instant — the baton (data) and the handoff signal (HREADY) aren't synchronized. The incoming runner must hold the baton out exactly when the "take it" whistle blows. If they wave it early and pull it back (too early — not held), the receiver grabs air. If they extend it a beat after the whistle (too late — the handoff was delayed by an extra step), the receiver already grabbed and missed it. To debug, you watch the whistle (HREADY high) and check the baton is right there, steady, at that instant.

A relay race where the handoff is governed by a "take it" whistle (the HREADY-high completing cycle). The incoming runner (the slave) must hold the baton out (drive valid HRDATA) exactly when the whistle blows (when HREADY is high), and the receiver (the master) grabs at the whistle (samples at completion). For a clean handoff, the baton is steady in the handoff zone at the whistle. Now, wrong timing is when the baton and the whistle aren't synchronized. Too early: the incoming runner waves the baton out early (drives the data before HREADY high) and then pulls it back / swaps it (changes it) before the whistle — so when the whistle blows, the receiver grabs air (or the wrong baton) — the baton wasn't held through the handoff. Too late: the incoming runner extends the baton a beat after the whistle (drives valid data after HREADY high) — because their handoff has an extra step (a registered read stage) that the whistle-timing didn't account for — so the receiver, grabbing at the whistle, gets nothing yet (stale/the previous baton). To debug, you watch the whistle (find the HREADY-high cycle) and check the baton is right there, steady, at that exact instant — if it's early-and-gone or not-yet-there, that's the bug. And the fix is to synchronize the baton with the whistle: if the handoff gained an extra step (a register), the whistle must be delayed to match (add the wait), so the baton is steady exactly when the whistle blows.

This captures wrong-HRDATA-timing debug: the relay handoff = the read transfer; the baton = HRDATA; the "take it" whistle = HREADY high (completion); the receiver grabbing at the whistle = the master sampling at completion; the baton steady at the whistle = HRDATA valid at the completing cycle; waving early and pulling back = driving data early then changing it (too early, not held); grabbing air = sampling the wrong/changed value; extending a beat after the whistle = data valid after completion (too late); the extra handoff step = the registered read stage; the whistle not accounting for it = HREADYOUT not matching the read-path depth; watching the whistle and checking the baton there = checking HRDATA at the HREADY-high cycle; delaying the whistle to match = adding the matching wait. Watch the whistle, check the baton is steady right there, and synchronize them if not.

Watch wrong HRDATA timing on the waveform — the too-late (registered-read) case:

Wrong HRDATA timing: registered read, completion too early

3 cycles
A read to A with a registered read output (+1 cycle) but HREADYOUT completing as if combinational. Cycle 1: HREADY high (completing cycle), master samples, but the registered data Q isn't valid until cycle 2 — so HRDATA holds a stale value X at completion. The data is one cycle too late vs HREADY-high. The fix: HREADYOUT high in cycle 2 (add one wait) to match the read-path depth.HREADY high (completing) → master samples, but Q not valid yet → stale XHREADY high (completin…Q valid one cycle too late; fix: HREADYOUT high HERE (add a wait)Q valid one cycle too …HCLKHREADYHRDATAXX (stale!)Q (too late)registered Q valid?nonoyescheck0FIREFIREt0t1t2
Figure 2 — wrong HRDATA timing: the too-late (registered-read) case. A read to address A. The slave registers its read data (+1 cycle), but its HREADYOUT logic completes as if combinational. Cycle 1: HREADY goes high (the completing cycle) — the master samples HRDATA here. But the registered read data (Q) isn't valid yet — it appears in cycle 2 (one cycle too late). So in cycle 1, HRDATA holds a stale/previous value (X), which the master wrongly samples. The 'HRDATA' row shows X at the completing cycle (cycle 1) and Q only in cycle 2. The 'check' fires at cycle 1: the data is valid one cycle too late vs HREADY-high. The fix: HREADYOUT should go high in cycle 2 (insert one wait), matching the registered read's depth.

The model's lesson: watch the whistle, check the baton is steady right there, and synchronize them if not. In the waveform, the completing cycle (cycle 1, HREADY high) is where the master samples — but the registered read data Q isn't valid until cycle 2, so the master samples stale X. The data is one cycle too late. The fix: make HREADYOUT go high in cycle 2 (add a wait), so completion lines up with the registered data.

4. Real Hardware Perspective

In debug, you find the completing cycle (HREADY high), check HRDATA's value there against the expected, classify early-vs-late, and trace to the read-path-vs-HREADYOUT depth mismatch — then add the matching wait (or hold the data).

The find the completing cycle and check: on the waveform, find the cycle where HREADY is high for the read in question (the completing cycle — the one the master samples). Check HRDATA's value there against the expected (from the scoreboard / the known memory state). A mismatchHRDATA at completion is not the expected value — is the timing bug (assuming the address/HSEL are right — else it's misalignment/HSEL). So in debug, check HRDATA at the HREADY-high cycle. So it's the completing-cycle check. So that's step one.

The buggy registered-read case (completion too early) versus the fix (add one wait to match the register stage).
Figure 3 — the classic cause: a registered read output not accounted for in HREADYOUT. Buggy: the read data is registered (+1 cycle) for timing closure, but HREADYOUT completes as if combinational → HREADYOUT high one cycle early, the registered data not ready → the master samples the previous/undefined value. Fixed: HREADYOUT accounts for the register stage — insert one wait state → HREADYOUT high in the same cycle the registered data becomes valid. Principle: HREADYOUT and HRDATA must come from matching pipeline depths; adding a register to the read path requires adding the matching wait so completion lines up with data validity.

The classify early vs late: classify the timing error. Too late (the data is valid a cycle after completion): look for a register in the read path (a registered read output for timing closure) whose extra cycle the HREADYOUT didn't account for — the #1 cause. Too early (the data was valid before completion and changed): look for a read path that's not held — the data was driven (combinationally) and then changed (by the next address phase, or a stall) before HREADY rose. So in debug, classify and look for the depth mismatch (late) or the not-held (early). So it's classification. So that points to the cause.

The trace and fix the co-timing: with the cause classified, trace: late → the read path has more pipeline depth than the HREADYOUT logic assumesfix by making HREADYOUT account for the register (insert the matching wait — 16.4 — so completion lands when the data is valid); early → the data isn't held until completion → fix by holding the read data (registering/latching it) through the completing cycle. The principle: HREADYOUT and HRDATA must come from matching pipeline depths (16.5's registered-select and 16.4's HREADYOUT must agree). An assertion helps: read_completing |-> (HRDATA == expected) (via the scoreboard) and a check that the data is stable through the completing cycle. So in debug, wrong HRDATA timing is a completing-cycle check (find HREADY high → check HRDATA there → classify early/late → trace to the depth mismatch / not-held → add the matching wait / hold the data). So in debug, co-time the data with completion. So that's the method.

5. System Architecture Perspective

At the system level, wrong HRDATA timing is a read-path / completion-path co-timing bug — a consequence of timing-closure pipelining (adding registers to meet frequency) without matching the completion — making it a common bringup bug when read paths get pipelined; and it's caught by the scoreboard (the data is wrong) but diagnosed by the completing-cycle check.

The timing-closure consequence: read paths often get pipelined (registered) to close timing (meet the clock frequency — a wide mux over many slaves is a long path — 16.5). Each register added shifts the read data later by a cycle. If the completion (HREADYOUT) isn't shifted to match, the co-timing breaks. So wrong HRDATA timing is a consequence of timing-closure pipelining — it appears when read paths are pipelined for frequency without updating the completion. So at the system level, it's a pipelining-for-frequency bug. So it's a closure side effect. So pipelining can mis-time.

The common bringup bug: because it appears when read paths are pipelined (a common late-stage RTL change for timing closure), wrong HRDATA timing is a common bringup bug — the read path was fine combinationally (in early RTL/sim) but broke when registered for the real clock. So at the system level, it's a frequent bringup/integration issue. So it shows up at integration. So watch for it when pipelining.

The caught by data, diagnosed by timing: the scoreboard (17.4) catches it (the read returns the wrong value) — but the diagnosis requires the completing-cycle (timing) view (the value is right, just mis-timed). So the catch (data) and the diagnosis (timing) are different — you catch it with the scoreboard but understand it by checking the completing cycle. So at the system level, wrong HRDATA timing is a read-path/completion co-timing bug (data valid at the wrong cycle), a consequence of timing-closure pipelining (registers added without matching the completion — a common bringup bug when read paths get pipelined), caught by the scoreboard (wrong data) but diagnosed by the completing-cycle check (the value is right, the cycle is off). So wrong HRDATA timing is where timing closure (pipelining for frequency) meets protocol correctness (the data-valid window) — a reminder that adding a register to a data path requires matching the control path. So co-time the data and the completion when you pipeline. So match the depths.

6. Engineering Tradeoffs

Debugging wrong HRDATA timing embodies the completing-cycle-check, classify-early-late, match-the-depth approach.

  • Completing-cycle check vs read values anywhere. Checking HRDATA at the HREADY-high cycle (where the master samples) finds the timing error; reading values anywhere misses when it's valid. Check at completion.
  • Classify early vs late. Too late → a depth mismatch (registered read not in HREADYOUT); too earlynot held. The classification points to the fix (add a wait vs hold the data). Classify first.
  • Match depths vs ad-hoc delay. Matching HREADYOUT to the read-path depth (add the correct wait) is the principled fix; an ad-hoc delay risks over/under-shooting. Match the depth.
  • Hold the data vs let it float. Holding the read data through the completing cycle (register/latch) prevents the too-early case; letting it float (combinational, changing) risks it. Hold the data.

The throughline: wrong HRDATA timing is read data valid a cycle early or late relative to the completing cycle (HREADY high) — the master samples at completion, so the data must be valid exactly then. Too early (driven before HREADY high then changed → not held); too late (valid after HREADY high → classically a registered read +1 cycle not in HREADYOUT). Diagnose by finding the completing cycle and checking HRDATA holds the correct value exactly thenearly/late by one cycle is the bug. It's distinct from misalignment (18.3 — there the value pairs with the wrong address; here the value is right but the cycle is off). It's a consequence of timing-closure pipelining (registers added without matching the completion — a common bringup bug), caught by the scoreboard but diagnosed by the completing-cycle check. The fix: co-time the data and completion — HREADYOUT and HRDATA from matching pipeline depths (add a register to the read path → add the matching wait).

7. Industry Example

Debug a wrong HRDATA timing bug that appeared after the read path was pipelined for timing closure.

A design worked in early RTL but, after the read mux was registered (to close timing at the target frequency), reads return stale data — intermittently.

  • The symptom. Reads occasionally return the previous read's value (a stale value) — the scoreboard flags data mismatches. The address/HSEL are correct (so it's not HSEL or misalignment). No hang.
  • Find the completing cycle. On the waveform, you find the read's completing cycle (HREADY high) and check HRDATA there. The value is stale (the previous read's data) — the correct value appears one cycle later.
  • Classify: too late. The correct data is valid one cycle after completion → too late. You look for a register in the read path → the read mux was registered (the recent timing-closure change), adding +1 cycle — but the HREADYOUT logic still completes as if combinational, one cycle too early.
  • Trace the depth mismatch. The read path now has one more register than the HREADYOUT logic assumes: the data is valid in cycle N+1, but HREADYOUT goes high in cycle N. They're de-co-timed by one cycle.
  • The fix. Make HREADYOUT account for the registered read: insert one wait state so HREADYOUT goes high in cycle N+1 — the same cycle the registered data becomes valid. Now the data is valid exactly when the master samples. (The principle: the register on the read path needs the matching wait on the completion.)
  • Add the check. You add a scoreboard assertion that reads return the expected value (catching the data error) and, knowing the cause, a review that every registered data path has a matching completion — so future timing-closure pipelining doesn't re-introduce the de-co-timing.

The example shows the timing-closure origin and the method: the bug appeared when the read path was pipelined (for frequency), the completing-cycle check found the stale data (too late), the classification pointed to the registered-read depth mismatch, and the fix was the matching wait (not forcing the data early). The principlematch the completion to the data-path depth — is the takeaway. This is how you debug a co-timing bug. This is the data lined up with completion.

8. Common Mistakes

9. Interview Insight

Wrong HRDATA timing is a solid debug interview topic — the completing-cycle rule, the registered-read cause, and the match-the-depth fix are the signals.

A summary card on debugging wrong HRDATA timing: the completing-cycle rule, the two cases, the misalignment distinction, and the match-the-depth fix.
Figure 4 — a strong answer in one card: HRDATA must be valid in the cycle HREADY is high (the master samples then); too early (driven then changed → not held) or too late (registered read +1 not in HREADYOUT); diagnose by finding the completing cycle and checking HRDATA holds the right value exactly then; differs from misalignment (right value, wrong cycle vs wrong address); fix by matching HREADYOUT to the data-path depth. The senior point: HRDATA must be valid exactly when HREADYOUT goes high — match completion timing to the read-path pipeline depth.

The answer that lands gives the completing-cycle rule and the registered-read cause: "HRDATA has to be valid in the cycle the read completes — when HREADY is high — because that's exactly when the master samples it. Wrong HRDATA timing means the data is presented a cycle early or late relative to that point, so the master captures the wrong value. Too early is when the slave drives the data before HREADY goes high and then changes it, so by the completing cycle the bus holds a different value — the data wasn't held. Too late is when valid data appears only after HREADY has gone high, so the master sampled stale or undefined data in the completing cycle. The classic cause of too-late is a registered read output: to close timing, you register the read data, adding a cycle, but if the HREADYOUT logic still completes the transfer as if the read were combinational, it goes high one cycle too early, before the registered data is ready. To debug it, I find the completing cycle — the one where HREADY is high for this read — and check that HRDATA holds the correct value exactly then; if the value is right but one cycle early or late relative to that, that's the bug. It's important to distinguish this from misalignment: in misalignment, the value is paired with the wrong address, a pipeline-pairing error; here, the value is the right one for the right address but in the wrong cycle, a data-valid-window error. So I ask: is the value correct but mis-timed, or is it the wrong address's value? The fix is to align the data validity with HREADY high — HREADYOUT and HRDATA must come from matching pipeline depths. So if I added a register to the read path for timing closure, I add the matching wait state, so HREADYOUT goes high in the same cycle the registered data becomes valid. I would not force the data earlier, because it's registered for timing; I delay the completion to match. This is a common bringup bug — the read path works combinationally but breaks when you pipeline it for frequency without updating the completion." The completing-cycle rule, the registered-read cause, and the match-the-depth fix are the senior signals.

10. Practice Challenge

Build and reason from debugging wrong HRDATA timing.

  1. The rule. State when HRDATA must be valid (the completing cycle, HREADY high) and the two failure modes (too early / too late).
  2. The registered-read cause. Explain why a registered read output causes the too-late case and the matching-wait fix.
  3. Read the waveform. From Figure 2, explain how the registered read makes the data valid one cycle too late vs the completing cycle.
  4. Vs misalignment. Explain how wrong HRDATA timing differs from misalignment (right value/wrong cycle vs wrong address) and the distinguishing question.
  5. The principle. Explain why HREADYOUT and HRDATA must come from matching pipeline depths, and why it's a common bringup bug.

11. Key Takeaways

  • HRDATA must be valid in the completing cycle (HREADY high) — the master samples exactly then. Outside that cycle, HRDATA is don't-care. Check at the completing cycle.
  • Two failure modes: too early (driven before HREADY high then changed → not held) and too late (valid after HREADY high → classically a registered read +1 cycle not in HREADYOUT).
  • The #1 cause is a registered read not reflected in HREADYOUT — completion fires one cycle early, before the registered data is valid → the master samples stale data.
  • The fix is matching depths — make HREADYOUT account for the register (insert the matching wait), so completion lines up with data validity. Not forcing the data early (it's registered for timing).
  • Distinct from misalignment (18.3) — wrong-timing = the right value in the wrong cycle (data-valid-window); misalignment = the value paired with the wrong address (pipeline-pairing). Ask: right value mis-timed, or wrong address's value?
  • A common bringup bug — appears when read paths are pipelined for timing closure without updating the completion; caught by the scoreboard (wrong data) but diagnosed by the completing-cycle (timing) check.

12. What Comes Next

You now can debug a co-timing bug. The next chapters cover the remaining failure modes:

  • Bad HRESP (next) — trace an unexpected ERROR to its cause (and the two-cycle sequence).
  • Burst Wrap Error, Arbitration Bug, Bridge Deadlock, and the Waveform-Based Debug Methodology — the rest of the debugging module.

To revisit the read path and completion, see HRDATA Muxing and HREADYOUT Generation; for the distinct misalignment bug, see Address / Data Misalignment; for what catches it, see AHB Scoreboards.