Skip to content

AMBA APB · Module 10

APB3 Introduction

The version delta from APB2 to APB3 — the two signals that changed the protocol: PREADY gave the subordinate a voice (wait states) and PSLVERR gave it a verdict (error response), turning a rigid two-cycle bus into one that tolerates slow peripherals and reports failures, with the two-phase core unchanged.

APB3 is the pivotal version of the protocol — and the entire upgrade is two signals. Take the APB2 baseline, add PREADY and add PSLVERR, change nothing else, and you have APB3. The single idea to carry through this chapter: APB3 = APB2 + PREADY + PSLVERR — the two-phase SETUP/ACCESS core is byte-for-byte the same, but two additions transform the bus. PREADY gives the subordinate a voice (it can now say "not yet" and stretch the ACCESS phase into wait states), and PSLVERR gives the subordinate a verdict (it can now say "that failed"). A rigid two-cycle bus that always completed and always "succeeded" becomes a bus that tolerates slow peripherals and reports failures. This chapter is about that delta — what was added, what it enables, and how a mixed-version system stays compatible — not a from-scratch tutorial on the two signals themselves.

1. Problem statement

APB2 solved "attach a simple peripheral cheaply," but it solved it by assuming two things that the real world violates: that every slave can answer in one cycle, and that every access succeeds. As soon as you try to put a slow peripheral or a fallible one behind the bus, the baseline breaks — and it breaks silently, which is worse than breaking loudly.

The concrete problems APB3 was built to fix are exactly two:

  • Some subordinates genuinely cannot respond in a single ACCESS cycle. A peripheral behind a clock-domain crossing, a slow off-chip register, a flash controller, a block that must do a multi-step internal operation — none of these can present read data or commit a write in one cycle, every time. On APB2 they have no way to ask for more time, so they cannot be legal slaves at all. The bus needs a mechanism for the subordinate to insert wait states.
  • Some accesses should fail, and APB2 cannot say so. A read of an unmapped address, a write to a read-only register, a peripheral in a fault state, a parity error on a backing store — on APB2 all of these return whatever the read mux defaults to, and the manager records a clean success. The bus needs a mechanism for the subordinate to return an error verdict so software and hardware can react instead of silently consuming garbage.

APB3's answer is deliberately minimal: it does not redesign the bus. It keeps the cheap two-phase handshake intact and bolts on the two smallest signals that close those two gaps — one for "wait," one for "fail." That restraint is the whole reason APB3 is a drop-in successor rather than a new protocol.

2. Why previous knowledge is insufficient

You arrive here already knowing the pieces, but not the version assembly. You know the APB2 baseline from Chapter 10.1: two-phase, unconditionally two cycles, always completes, always "succeeds," full-word, context-free. You have also studied the two new signals in depth — the mechanics of wait states in Module 8 (PREADY timing) and the mechanics of error reporting in Module 9 (PSLVERR behavior). What you have not done is put those together as a precise version statement: APB3 is APB2 with exactly these two signals added and nothing else changed.

That assembly is the missing piece, and it is what integration and review work actually demands:

  • Knowing PREADY's mechanics is not the same as knowing what it changed. Module 8 taught you how a wait state works cycle-by-cycle. This chapter is about the delta: that before APB3 the ACCESS phase was always one cycle and now it is "held until PREADY high" — a change to the protocol's completion contract, not just a new signal.
  • Knowing PSLVERR's mechanics is not the same as knowing what it changed. Module 9 taught you how an error is signalled. This chapter is about the delta: that before APB3 every transfer had a single outcome ("done"), and now every transfer carries a pass/fail verdict — a change to what "completing" even means.
  • Neither prior module taught you the seam. The hard, real-world part of versioning is what happens when an APB3 master meets an APB2 slave (or vice versa): which signals must be tied off, in which direction, so the mixed system degrades safely. That is a version question, not a single-signal question.

So treat this chapter as additive composition, not re-teaching. We will state the delta precisely, show the same access on both versions, write the RTL diff, and handle the boundary. For the deeper "why these two signals, why now" rationale, forward-link to 10.4 — PREADY rationale and 10.5 — PSLVERR rationale; for the next layer (APB4's PSTRB/PPROT), see 10.3 — APB4 Introduction.

3. Mental model

The model: APB3 took the APB2 vending machine and added a "please wait" light and a "transaction failed" receipt — and changed nothing else about how you make a selection. You still make your selection the same way (SETUP), the machine still dispenses on the same access step (ACCESS), but now the machine can flash "please wait" until it is actually ready (PREADY), and when it finishes it hands you a receipt that says OKAY or ERROR (PSLVERR). The selection mechanism is identical; two new lights changed what the machine can tell you.

Three refinements make it precise:

  • The core is unchanged — SETUP then ACCESS. Every APB3 transfer still begins with one SETUP cycle (PSEL high, PENABLE low) and enters ACCESS (PENABLE high) on the next cycle. That sequencing is byte-for-byte identical to APB2. APB3 did not touch the phase structure; this is why it is "APB2 plus signals" and not a redesign.
  • PREADY changes ACCESS from "always one cycle" to "held until PREADY high." This is the completion-contract delta. On APB2, the transfer completes at the first ACCESS edge, full stop. On APB3, the transfer completes only on the cycle where PSEL && PENABLE && PREADY are all high — the subordinate can hold PREADY low to stretch ACCESS into any number of wait states. A fast slave that drives PREADY high immediately behaves exactly like APB2; a slow one buys the cycles it needs. The subordinate now has a voice in when the transfer ends.
  • PSLVERR adds a pass/fail verdict to a transfer that previously always "succeeded." This is the outcome delta. On APB2 the only outcome was "completed." On APB3, at the completion edge (sampled together with PREADY high), PSLVERR reports OKAY (low) or ERROR (high). A transfer that completes can now be a failed transfer. The subordinate now has a verdict on whether the transfer was valid.
A side-by-side waveform comparison. The top APB2 panel shows a fixed two-cycle transfer with no PREADY and no PSLVERR, PRDATA sampled unconditionally. The bottom APB3 panel shows the same access with an added PREADY signal held low for one wait cycle (amber) so the ACCESS phase stretches, completion only when PREADY is high, and an added PSLVERR signal reporting OKAY at completion.
Figure 1 — the same read access on APB2 (top) and APB3 (bottom), with the version delta highlighted. On APB2 there is no PREADY and no PSLVERR: the ACCESS phase is exactly one cycle and the manager samples PRDATA at the next edge unconditionally, the transfer always completes in two cycles, and there is no channel to report failure. On APB3 two signals are added: PREADY lets the subordinate hold the ACCESS phase low to insert wait states, so the transfer completes only on the cycle where PSEL, PENABLE and PREADY are all high; PSLVERR, sampled at that completion edge, reports OKAY or ERROR. The SETUP and ACCESS phases are identical on both panels — APB3 = APB2 + PREADY (a voice) + PSLVERR (a verdict).

4. Real SoC implementation

In silicon, upgrading an APB2 slave to APB3 is a small, surgical RTL diff: add a pready output and a pslverr output, and the logic that drives them. The address decode, register array, and read mux from the APB2 baseline are reused verbatim. The block below is the APB2 slave from Chapter 10.1 with the APB3 delta layered on — every change is commented with what was added.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// APB3 slave = the APB2 slave + PREADY + PSLVERR. Two-phase core unchanged.
// Compare against the apb2_slave in Chapter 10.1: only the marked lines are new.
module apb3_slave #(parameter AW = 8) (
  input              pclk, presetn,
  input              psel, penable, pwrite,
  input  [AW-1:0]    paddr,
  input  [31:0]      pwdata,
  output reg [31:0]  prdata,
  output             pready,    // <== NEW in APB3: the subordinate's VOICE (wait states)
  output             pslverr    // <== NEW in APB3: the subordinate's VERDICT (error response)
);
  reg [31:0] ctrl, status;      // same tiny CSR bank as the APB2 baseline
 
  // --- Decode helpers (reused from APB2) ---
  wire access      = psel && penable;                 // ACCESS phase active
  wire addr_valid  = (paddr == 8'h00) || (paddr == 8'h04);
 
  // --- PREADY: this slave can answer in one cycle, so it ties ready high. ---
  // A SLOW slave would instead drive a wait FSM here (PREADY low until data is
  // settled) — that mechanism is Module 8; this chapter shows the delta, not the
  // full wait machine. Driving pready=1 makes this slave behave like APB2 timing.
  assign pready = 1'b1;                                // <== NEW: always-ready (1-cycle)
 
  // --- PSLVERR: error verdict, valid at the completion edge (access & pready). ---
  // Here: flag a write to a read-only register, and any unmapped address.
  wire write_ro = pwrite && (paddr == 8'h04);          // status is read-only
  assign pslverr = access && (!addr_valid || write_ro);// <== NEW: pass/fail verdict
 
  // WRITE commits in the ACCESS cycle — but now only on a *successful* transfer.
  // The error case is suppressed so a flagged write does not also mutate state.
  always_ff @(posedge pclk or negedge presetn) begin
    if (!presetn) ctrl <= 32'b0;
    else if (access && pready && pwrite && !pslverr && (paddr == 8'h00))
      ctrl <= pwdata;                                  // full word, on success only
  end
 
  // READ mux — unchanged from APB2 (combinational, valid in ACCESS).
  always_comb begin
    case (paddr)
      8'h00:   prdata = ctrl;
      8'h04:   prdata = status;
      default: prdata = 32'h0;     // now ALSO flagged via PSLVERR, not silent
    endcase
  end
endmodule

Two facts define the delta. First, PREADY is a real output now — even an always-ready slave must drive it (here 1'b1), because the APB3 master waits for it; a slow slave replaces that constant with a wait FSM (Module 8). Second, PSLVERR turns the old silent default case into a reported error — the unmapped-address read that APB2 quietly returned 0 for is now accompanied by pslverr=1, and a write that fails is suppressed rather than silently committed. Notice what did not change: the phase decode, the CSR array, and the read mux are identical to the APB2 baseline. That is the point of APB3 — minimal additive surface.

5. Engineering tradeoffs

The cleanest way to hold the delta is a direct dimension-by-dimension comparison of the two versions.

DimensionAPB2APB3
Transfer lengthUnconditionally 2 cycles (SETUP + 1 ACCESS)2+ cycles — ACCESS held until PREADY high (1 ACCESS if ready immediately)
Flow controlNone — subordinate has no voice; manager never waitsPREADY — subordinate inserts wait states; manager stalls until ready
Error reportingNone — every transfer "succeeds"; failures are silentPSLVERR — pass/fail verdict sampled at completion
Slow-peripheral supportImpossible — a slave that needs >1 cycle is not legalNative — slow memory, CDC, flash, multi-step ops are all legal
Completion contractCompletes at the single ACCESS edgeCompletes only when PSEL && PENABLE && PREADY
New signals vs APB2— (this is the baseline)PREADY, PSLVERR (only these two added)
Byte strobes / protectionNoneStill none — PSTRB/PPROT are APB4, not APB3
Backward compatAn always-ready, never-error APB3 slave behaves exactly like APB2
Cost of the upgradeOne ready output + one error output + (for slow slaves) a small wait FSM

The throughline: APB3 is the minimum upgrade that fixes APB2's two structural limitations without disturbing anything else. It does not add throughput (no bursts, no pipelining), and it does not add byte-granular writes or protection — those are deliberately left for APB4. Reading "APB3-compliant" on a datasheet should immediately tell you: it supports wait states and error responses, but it may still write full words only and carry no protection context. That precise expectation is the version-aware judgment integration work rewards.

6. Common RTL mistakes

7. Debugging scenario

The signature APB3-era bug lives at the version seam — an APB3 master wired to an APB2 slave, where the two signals the slave does not drive are mishandled at the boundary. The most common form is a floating PREADY input that hangs the bus forever.

  • Observed symptom: the very first access to one peripheral never returns — the CPU's APB transaction hangs and the whole bus locks up during bring-up. Every other (native-APB3) peripheral works; only the one APB2-IP block deadlocks, and it deadlocks 100% of the time, on the first transfer, not intermittently.
  • Waveform clue: the transfer reaches the ACCESS phase normally — PSEL high, PENABLE high — and then stays there forever. PENABLE never deasserts. Looking at the master's PREADY input, it is X (undriven) the entire time: there is no driver on the net. The manager is waiting for PREADY to go high to complete, and it never will, because nothing is connected to drive it.
  • Root cause: the APB2 slave has no PREADY output (it's APB2 — that signal doesn't exist), but the APB3 master has a PREADY input it waits on. At the integration seam the master's PREADY input was left floating — connected to nothing — instead of being tied off. The master's completion condition PSEL && PENABLE && PREADY can never be true with PREADY stuck at X/0, so it stalls in ACCESS indefinitely. (A sibling bug: the PSLVERR input left floating, which is read as a spurious error on otherwise-good transfers.)
  • Correct RTL: at the boundary, tie the absent subordinate outputs to their backward-compatible constants — PREADY high (always-ready, matching APB2's unconditional single-cycle completion) and PSLVERR low (OKAY). Then the APB3 master sees a fast, never-failing subordinate and degrades to APB2 behavior:
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// At an APB3-master <-> APB2-slave seam, define the signals the slave lacks.
// NEVER leave these master inputs floating.
assign m_pready  = 1'b1;   // APB2 slave is always ready -> complete in 1 ACCESS cycle
assign m_pslverr = 1'b0;   // APB2 slave never errors    -> always OKAY
  • Verification assertion: at any APB2/APB3 boundary, prove the master's version-specific inputs are never unknown, and prove every transfer eventually completes (no infinite ACCESS stall):
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 1) The master's PREADY/PSLVERR inputs must be driven (never X) during ACCESS.
assert property (@(posedge pclk) disable iff(!presetn)
  (psel && penable) |-> (!$isunknown(m_pready) && !$isunknown(m_pslverr)))
  else $error("Floating PREADY/PSLVERR at APB2/APB3 seam");
 
// 2) Liveness: once in ACCESS, the transfer must complete within a bound.
assert property (@(posedge pclk) disable iff(!presetn)
  (psel && penable) |-> ##[0:MAXWAIT] (psel && penable && m_pready))
  else $error("Transfer never completed -- PREADY hung");
  • Debug habit: when an integrated APB peripheral hangs (as opposed to returning wrong data), suspect a version seam first — check whether the master's PREADY/PSLVERR inputs are actually driven by something. A floating ready is the single most common APB3 integration failure. Before tracing internal timing, confirm the protocol versions on each side of the seam match, and that every signal the higher version expects but the lower version lacks is explicitly tied off. Check the connectivity of the version signals, not just their values.
Two stacked block diagrams of an APB3 master connected to an APB2 slave. The top buggy case shows the master's PREADY and PSLVERR inputs as floating dashed red lines with no driver, causing a deadlock in the ACCESS phase. The bottom correct case shows PREADY tied high and PSLVERR tied low at the boundary in green, so the master degrades to APB2 behavior and the transfer completes.
Figure 2 — the version-mismatch tie-off bug at an APB3-master / APB2-slave seam. Top (bug, red): the APB2 slave drives no PREADY and no PSLVERR, and the master's PREADY input is left floating (reads X). Because the APB3 master completes only when PREADY is high, it waits forever and the bus deadlocks in the ACCESS phase; the floating PSLVERR may additionally read as a spurious error. Bottom (correct, green): at the boundary the absent PREADY is tied high (always-ready) and the absent PSLVERR is tied low (OKAY), so the APB3 master sees a fast, never-failing subordinate and degrades cleanly to APB2 behavior. The lesson: a version down-conversion must define every signal the lower version lacks — never leave one floating.

8. Verification perspective

Verifying APB3 is mostly verifying the delta and the seam: that the two new signals honour their contracts, that the old two-phase core is untouched, and that a mixed-version system is checked with the testbench told which version it is on.

  • Configure the agent for the version, then verify the new contracts. A modern UVM APB agent is version-parameterized — it must be told whether the segment is APB2 or APB3, or it will check for signals that are not present (false failures) or fail to check the ones that are (false passes). In APB3 mode, the agent enforces the two new contracts: PREADY qualifies completion (the transfer ends only on PSEL && PENABLE && PREADY), and PSLVERR is sampled only at that completion edge and is OKAY/ERROR. The defining APB3 assertion is the completion rule itself — not the APB2 "always two cycles" rule, which is now wrong for any slave that waits.
  • Cover backward compatibility explicitly. The headline APB3 property is that an always-ready, never-error slave is indistinguishable from APB2. Functional coverage must include the boundary cases: zero-wait transfers (PREADY high in the first ACCESS cycle — the APB2-equivalent path), N-wait transfers (PREADY held low for 1, 2, … cycles), and PSLVERR both ways (OKAY and ERROR) on reads and writes. Crossing {read, write} × {0-wait, N-wait} × {okay, error} is the minimal APB3 coverage grid, and it directly exercises "is APB3 still compatible with APB2 timing when the slave doesn't use the new features?"
  • Pin the two signals' contracts at the APB2/APB3 seam. Where an APB3 master meets an APB2 slave (or a bridge down-converts), the verification job is to prove the tie-offs are correct and never floating: assert the master's PREADY input is driven and effectively high (so transfers complete), assert PSLVERR is driven and low (so no spurious errors), and cover that a transfer crossing the seam completes in APB2 timing. This is where the real bugs live, so the coverage model must name the seam — a floating PREADY (hang) and a floating PSLVERR (spurious error) are the two failure modes to close.

The point: APB3 verification is APB2 verification plus the two new contracts plus the seam — and the discipline of configuring the testbench to the correct version so it neither demands nor ignores PREADY/PSLVERR.

9. Interview discussion

"What did APB3 add over APB2?" is a precise version-knowledge filter, and the model answer is one sentence followed by the consequence of each addition: APB3 is APB2 plus PREADY and PSLVERR — nothing else changed.

Lead with the equation, then unpack: PREADY (flow control) gave the subordinate a voice — it changed the ACCESS phase from "always one cycle" to "held until PREADY high," so a slow peripheral can now insert wait states and be a legal slave, which it could never be on APB2. PSLVERR (error response) gave the subordinate a verdict — it added a pass/fail outcome to a transfer that on APB2 always "succeeded," so an unmapped address or a fault is now reported instead of silently returning garbage. Stress the two things that make you sound senior: first, that the two-phase SETUP/ACCESS core is unchanged — APB3 is strictly additive, which is why it is a drop-in successor and why an always-ready/never-error APB3 slave is bit-for-bit APB2 behavior. Second, the backward-compatibility seam: when an APB3 master meets an APB2 slave, you tie the absent PREADY high and the absent PSLVERR low at the boundary — leave them floating and the bus either hangs (floating ready) or sees spurious errors (floating error). Close by drawing the version line cleanly: APB3 added wait and error; byte strobes (PSTRB) and protection (PPROT) are APB4, not APB3 — conflating them is the classic slip.

10. Practice

  1. State the equation. Write APB3 = APB2 + ?, name the two added signals, and for each one name the single APB2 limitation it fixes.
  2. Draw the delta. Sketch the same read on APB2 and APB3. Mark where the ACCESS phase length differs and the exact cycle each transfer completes; show one wait state on the APB3 version and where PSLVERR is sampled.
  3. Write the RTL diff. Starting from the APB2 slave, add exactly the lines needed to make it an always-ready APB3 slave that flags writes to a read-only register. Identify which APB2 lines you did not touch.
  4. Make it backward-compatible. Given an APB3 master and an APB2 slave, write the two assign statements at the seam that make the master degrade to APB2 behavior, and state what breaks if you omit each one.
  5. Diagnose the hang. Given an integrated peripheral that deadlocks in the ACCESS phase with PSEL/PENABLE stuck high, walk the steps to identify a floating PREADY at a version seam — and contrast it with the stale-data symptom of a floating PSLVERR.

11. Q&A

12. Key takeaways

  • APB3 = APB2 + PREADY + PSLVERR. The upgrade is exactly two signals; the two-phase SETUP/ACCESS core is byte-for-byte unchanged. APB3 is strictly additive, which is why it is a drop-in successor.
  • PREADY gave the subordinate a voice. It changed the ACCESS phase from "always one cycle" to "held until PREADY high," so slow peripherals (CDC, slow memory, flash, multi-step ops) can insert wait states and finally be legal slaves.
  • PSLVERR gave the subordinate a verdict. It added a pass/fail outcome to a transfer that on APB2 always "succeeded," turning silent failures (unmapped address, faults) into reported errors — sampled at the completion edge, alongside PREADY high.
  • Backward compatibility is built in. An always-ready, never-error APB3 slave is indistinguishable from APB2. Driving PREADY=1 constantly is the legal way to express a single-cycle slave.
  • The seam is where bugs live. Connecting an APB3 master to an APB2 slave means tying the absent PREADY high and the absent PSLVERR low at the boundary — leave them floating and the bus hangs (floating ready) or sees spurious errors (floating error). Never leave a version signal floating.
  • APB3 is not APB4. APB3 added wait and error only; byte strobes (PSTRB) and protection (PPROT) are APB4. Reading "APB3-compliant" means wait-state and error support, full-word writes, and no protection context.