AMBA APB · Module 8
PREADY Timing
How a subordinate actually drives PREADY — combinational versus registered, the sample window the manager reads it in, and the glitch and setup hazards that make a logically-correct PREADY still wrong on silicon. The signal-integrity layer beneath the PREADY handshake.
You already know what PREADY means — high completes the transfer, low inserts a wait. This chapter is about something subtler and more dangerous: how a subordinate drives PREADY in time, and why a PREADY that is logically correct can still be electrically wrong. The manager samples PREADY on one clock edge per access cycle, so PREADY must be a clean, settled, glitch-free value at that edge. The single idea to carry: PREADY has two valid implementations — combinational (fast, zero added latency, glitch-prone) and registered (clean, glitch-free, one cycle slower) — and choosing wrong, or building the combinational form carelessly, is how a wait-state design that passes a quick simulation fails timing or glitches in silicon.
1. Problem statement
The problem is presenting a stable, correct PREADY to the manager at the exact instant it samples — the rising clock edge in the access phase — regardless of how the subordinate computes "am I ready?"
A wait-state handshake is only as good as the timing of the one bit that drives it. The manager's transfer FSM samples PREADY on each PCLK rising edge while in access (PENABLE high) and decides, on that edge, whether the access completes or holds. For that decision to be correct, PREADY must satisfy two electrical requirements that "it is logically 1 when ready" does not capture:
- It must be stable in the sample window.
PREADYhas to be settled from setup-time before the rising edge through hold-time after it. A value that is still rippling as the edge arrives is a setup violation or a metastability risk. - It must be glitch-free into that edge. If
PREADYis combinational off a decode that settles in stages, it can momentarily pulse the wrong way mid-cycle; if that transient lands in the sample window, the manager reads a lie.
So the job is not "compute readiness" — it is "deliver readiness as a clean value the manager can trust on its sampling edge," which is a timing and signal-integrity problem, not just a logic one.
2. Why previous knowledge is insufficient
Module 3 named PREADY as the completion-and-backpressure control, and Module 5 drilled the per-cycle sampling cadence — that the manager checks PREADY every access edge. Both treat PREADY as an idealized bit that is simply "1 or 0." Real RTL has to produce that bit, and that is where this chapter goes:
- A logically-correct
PREADYcan be electrically wrong. "DrivePREADYhigh when the data is ready" is a logic statement. Whether that high arrives stable and glitch-free at the sampling edge depends on whether it is combinational or registered and on the depth of the cone behind it. The handshake view never asks howPREADYis built. - Combinational and registered
PREADYare different transfers, not just styles. A combinationalPREADYcan complete a fast access in its first cycle; a registeredPREADYcannot — its earliest high is one cycle later. So the choice changes the minimum latency of every transfer on the bus, which the idealized view hides. - The sample window is the whole game. The manager does not care what
PREADYdoes mid-cycle; it cares whatPREADYis at the rising edge. Understanding wait states at the RTL level means understanding that window and what can corrupt it — glitch, setup violation, or anXpropagating from an undriven path.
So the model to add is the physical one: PREADY as a signal that must be clean in a specific window, built either combinationally (fast, risky) or registered (clean, slower).
3. Mental model
The model: PREADY is a ready light the manager glances at once per beat — and it must be steady at the glance, not flickering. What matters is the light's state at the instant of the glance (the rising edge), not what it did between glances.
A combinational PREADY is a light wired straight through a network of switches: flip the inputs and the light eventually shows the right state — but while the switches settle, it can flicker. If the manager glances during a flicker, it sees the wrong thing. A registered PREADY is a light driven by a latch that only updates on the clock: it is rock-steady between edges and never flickers — but it shows last cycle's decision, so it is always one beat behind. The engineering choice is "fast but must be kept flicker-free" versus "clean but one beat slower."
Three refinements make it precise:
- The glance is the rising edge in access. The manager samples
PREADYon eachPCLKrising edge whilePENABLEis high. Only that instant matters;PREADYmust meet setup and hold around it. - Combinational
PREADYtrades latency for cleanliness. It can complete a ready access in the first access cycle (zero wait states), but the cone that computes it must settle inside the cycle and not glitch into the sample window. The faster the bus clock, the harder that is. - Registered
PREADYtrades a cycle for safety. A flop guarantees a glitch-free, setup-friendly value, at the cost of one extra cycle of minimum latency. On a slow control bus, that cycle is usually free — which is why registeredPREADYis the safe default.
4. Real SoC implementation
In silicon, PREADY is the subordinate's output, and the two implementations are a few lines apart but worlds apart in behaviour. The combinational form drives readiness directly; the registered form clocks it.
// --- Combinational PREADY: fast (zero added latency) but must be glitch-free ---
// data_ready is a combinational term: is the addressed source available NOW?
// A fast subordinate that is always ready ties this high.
assign pready_comb = sel ? data_ready : 1'b1; // unselected -> 1 (do not hold the bus)
// HAZARD: data_ready often depends on the PADDR decode; if that decode ripples,
// pready_comb can glitch. It must settle and be stable in the manager's sample
// window (setup before the PCLK rising edge through hold after it).
// --- Registered PREADY: glitch-free and timing-friendly, +1 cycle latency ---
// pready is now a clean flop output; its earliest high is one cycle after select.
always_ff @(posedge pclk or negedge presetn) begin
if (!presetn) pready_reg <= 1'b0;
else if (sel && penable) pready_reg <= data_ready; // sampled, then presented clean
else pready_reg <= 1'b0;
end
// Trade-off in one line: pready_comb can complete in the first access cycle;
// pready_reg cannot — but pready_reg is rock-steady at the sampling edge.Two facts drive the real decision. First, the sample window is the only timing constraint that matters: whichever form you pick, PREADY must be stable across the PCLK rising edge the manager samples on — a static-timing tool checks this as a normal setup/hold path, and a combinational PREADY with a deep decode cone is exactly where that path fails on a fast clock. Second, the default-ready rule: an unselected subordinate must drive PREADY high (or, more precisely, must not pull the shared/muxed PREADY low), so that the bus does not hang — which is why the combinational form returns 1'b1 when !sel. (How PREADY=0 then extends the access cycle by cycle is the transfer-extension mechanics; this chapter is about getting the PREADY value clean at the edge.)
5. Engineering tradeoffs
The combinational-versus-registered choice is the core PREADY design decision. Each row is a real consequence.
PREADY implementation | What it gives up | What it buys | When to choose it |
|---|---|---|---|
| Combinational | Glitch immunity; easy timing | Zero added latency — completes in the first access cycle | Slow clock, shallow ready cone, latency matters |
| Registered | One cycle of minimum latency | Glitch-free, setup-friendly, trivially timed | Fast clock, deep decode, or when robustness matters most |
| Always-ready (tie high) | Any backpressure | The simplest, fastest path | A register that genuinely answers every cycle |
!sel → 1 default | A subordinate-side "busy when idle" | A bus that never hangs on an unselected slave | Always — an unselected slave must not pull PREADY low |
| Deep combinational cone | Timing closure on a fast clock | (nothing — this is the trap) | Never on a fast bus; register it instead |
The throughline: PREADY is the one bit whose timing — not just logic — decides whether a wait-state design works. On a slow control bus the combinational form is fine and saves a cycle; as the clock rises or the decode deepens, register it. When unsure, register it: a cycle of latency on sparse control traffic is cheap, a metastable manager is not.
6. Common RTL mistakes
7. Debugging scenario
A wait-state design that "works in a quick sim" but misbehaves on a faster clock or in gate-level is almost always a PREADY timing bug, not a logic bug — and it is invisible in a zero-delay RTL run.
- Observed symptom: an access intermittently completes a cycle early (capturing garbage) or the design fails timing closure on the real clock, even though the RTL
PREADYlogic "looks right" and passes a fast zero-delay simulation. It gets worse as the clock frequency rises. - Waveform clue: in a gate-level or annotated-delay waveform (Figure 3),
PREADYis combinational and glitches during the access cycle — it pulses high briefly as thePADDRdecode settles, before the data is actually ready, and that transient lands inside the manager's sample window, so the manager samples a premature1and completes early. - Root cause:
PREADYwas driven combinationally off a multi-level cone that includes thePADDRdecode; as the address bits settle at different times, the decode (and thusPREADY) ripples through intermediate states, one of which is a spurious high that coincides with the sampling edge. - Correct RTL: either register
PREADYso it is a clean flop output —always_ff: if (sel && penable) pready <= data_ready;— or, if the combinational form is required, drive it from a settled, registereddata_readyterm and a registered select so the cone has no rippling decode in it:assign pready = sel_q ? data_ready_q : 1'b1;. - Verification assertion: assert
PREADYis stable across the sampling edge and clean — e.g.assert property (@(posedge pclk) disable iff(!presetn) (psel && penable) |-> !$isunknown(pready));plus a glitch check in gate-level sim thatPREADYdoes not change within a guard window before the clock edge; and a property that the access does not complete beforedata_readyis genuinely asserted. - Debug habit: when a wait-state design works in RTL sim but fails on the real clock or in gate-level, do not re-read the
PREADYlogic — look at thePREADYtiming: is it combinational off a decode? Run a delay-annotated or gate-level sim and watchPREADYacross the sample window for a glitch. The fix is almost always to registerPREADYor its inputs.
8. Verification perspective
PREADY timing bugs are the canonical "passes RTL, fails silicon" class, so verification has to attack them at the right level and with the right checks — a zero-delay RTL run will never catch a glitch.
- Assert the sample-window contract. Bind properties that
PREADYis neverXwhilePSEL && PENABLE(catches undriven paths), and — in gate-level or delay-annotated simulation — thatPREADYdoes not transition within a setup guard-band before eachPCLKrising edge (catches glitches landing in the window). The X-check runs in RTL; the glitch check needs delays. - Check readiness causality, not just value. Beyond "is
PREADYclean," assert that the access does not complete before the data is genuinely available:(complete) |-> (data_was_ready). This catches the asserted-too-early bug, which is a different failure from a glitch and which a stability check alone will miss. - Cover both implementations and the corners. Functional coverage should distinguish a combinational-ready completion (complete in the first access cycle) from a registered-ready completion (complete one cycle later), and hit: zero-wait, one-wait, multi-wait, an unselected slave during another's access (default-ready), and back-to-back transfers. A wait-state suite that never exercises the first-cycle completion path has a hole exactly where the combinational glitch lives. (Wait-state coverage is a chapter of its own.)
The point: PREADY correctness is a timing property, so the verification plan must specify the level (gate-level for glitches) and the causality (ready-before-complete), not just sample the value in RTL.
9. Interview discussion
"Combinational or registered PREADY — which, and why?" is a sharp senior question because it separates people who know the handshake from people who have closed timing on one. A weak answer picks one; a strong answer states the trade and the hazard.
Frame it as latency versus integrity: combinational PREADY adds zero latency and can complete an access in its first cycle, but its cone must settle within the cycle and stay glitch-free across the manager's sample window — risky on a fast clock or a deep PADDR decode. Registered PREADY is glitch-free and trivially timed but adds one cycle of minimum latency to every transfer. Then deliver the depth points: the only instant that matters is the manager's sampling edge (a transient outside the window is harmless; one inside it is sampled as real), and the classic bug — a combinational PREADY glitching off a rippling decode — is invisible in zero-delay RTL and only shows up in gate-level, which is why you either register PREADY or drive it from registered inputs, and verify it with a glitch check plus a ready-before-complete property. Closing with "on a slow control bus I register it by default — a cycle is cheap, a metastable manager is not" signals real silicon experience.
10. Practice
- Place the window. On an access with one wait state, mark each
PCLKedge the manager samplesPREADYand the setup/hold window around it; state whatPREADYbetween edges is allowed to do. - Compare latency. For the same always-ready subordinate, state the earliest completion cycle with a combinational
PREADYversus a registeredPREADY, and why they differ by one. - Spot the glitch. Given a combinational
PREADY = decode(paddr) & data_ready, explain how a ripplingPADDRcan glitchPREADYand what must be true for that glitch to corrupt a transfer. - Write both forms. From memory, write the combinational and the registered
PREADY, and the!sel → 1default, and explain the latency and integrity trade between them. - Pick the level. State which
PREADYbug a zero-delay RTL simulation can catch and which requires gate-level or delay-annotated simulation, and the assertion for each.
11. Q&A
12. Key takeaways
PREADYcorrectness is a timing property, not just a logic one. It must be stable and glitch-free in the manager's sample window — thePCLKrising edge in the access phase — or a logically-rightPREADYis sampled wrong.- Combinational
PREADYis fast but risky: zero added latency (can complete in the first access cycle), but its cone must settle within the cycle and not glitch into the sample window. - Registered
PREADYis clean but a beat slower: glitch-free and trivially timed, at the cost of one cycle of minimum latency on every transfer. It is the safe default on a slow control bus. - An unselected subordinate must drive
PREADYhigh (the!sel → 1default), or it stalls another slave's access or hangs the bus on an unmapped address. - The classic bug — a combinational
PREADYglitch off a rippling decode — is invisible in zero-delay RTL and only appears in gate-level or delay-annotated simulation; the fix is to registerPREADYor its inputs. - Verify
PREADYat the right level: X-checks and ready-before-complete causality in RTL, and a glitch guard-band check in gate-level — and cover both the first-cycle (combinational) and one-later (registered) completion paths.