AMBA APB · Module 4
Anatomy of a Write Transfer
A full APB write walked from IDLE to IDLE — setup, access, the completion cycle where PWDATA is captured into the register, and the return to IDLE, shown in timing.
You now know each APB signal and the rule that completion is PSEL & PENABLE & PREADY all high. This chapter assembles those pieces into the thing you will actually read off a waveform or drive in RTL: one complete write transfer, walked cycle by cycle from IDLE back to IDLE. A write is the canonical APB transaction — PWRITE high, the manager driving PWDATA, PRDATA unused — and watching it move through IDLE → SETUP → ACCESS → COMPLETE → IDLE is how every other transfer (reads, waited transfers, back-to-back bursts) is understood. The single idea to carry: the manager presents the write data from the setup cycle and holds it steady, but the subordinate captures it on exactly one edge — completion — so "the data is on the bus" and "the write has landed" are different cycles, and a correct design never confuses them.
1. What problem is being solved?
The problem is performing a complete write — value in, register updated — over a shared bus, as one bounded, unambiguous sequence both ends agree on.
A write is not a single event. The manager has to announce who is being written (PADDR, PSEL), declare that it is a write (PWRITE high), present the value (PWDATA), give the subordinate a settle cycle, perform the access, and learn when the subordinate has actually taken the data (PREADY). If any of those steps were fuzzy about timing, the value could land in the wrong register, land early, or land twice. APB pins the whole thing to a fixed skeleton:
- IDLE — nothing selected (
PSELlow); the bus is quiet. - SETUP —
PSELhigh,PENABLElow;PADDR,PWRITEhigh, andPWDATAare all presented. One settle cycle for the subordinate to decode. - ACCESS —
PENABLEhigh; the access is performed and the subordinate signals readiness withPREADY. - COMPLETE — the access cycle where
PREADYis high; the write is captured here and nowhere else.
Every legal write is exactly this shape. The value travels from manager to subordinate, the subordinate's register updates, and both ends know precisely which cycle that happened on.
2. Why the previous model is not enough
Up to now you have the parts in isolation: the access phase mechanics, PWDATA and its capture-at-completion rule, the PREADY handshake, the completion contract. Each is correct, but a list of signal contracts is not a transaction. To drive a write or debug one on a scope, you have to see all the signals move together, in order, and know which cycle does what.
The gaps a part-by-part view leaves open are exactly the ones that produce bugs:
- It does not show presentation and capture as different cycles.
PWDATAis on the bus from SETUP, but the register clocks it only at COMPLETE. Looking at one signal at a time, it is easy to assume the write happens when the data appears. Watching the whole transfer makes the gap between "presented" and "captured" visible. - It does not show what stays still while the access stretches. When the subordinate is slow, ACCESS spans extra cycles.
PADDR,PWRITE,PWDATA, andPSELmust hold unchanged across all of them. That stability rule only makes sense seen against the movingPREADY. - It does not show the return to IDLE. A transfer is bounded — it ends. After completion the bus either flows to the next SETUP or drops to IDLE. The lifecycle's shape (where it starts, where it ends) is the thing that lets you count transfers on a busy bus.
So the model to add is not another signal; it is the assembled transaction — every signal in motion, in order, with one capture edge and a defined beginning and end.
3. Mental model
The model: a write is handing a filled-in form across a counter — you lay it down (SETUP), the clerk reads and works it (ACCESS), and they file it in one motion when ready (COMPLETE).
You place the form on the counter complete: the destination written on it (PADDR), a mark saying "this is a deposit, not a withdrawal" (PWRITE high), and the amount filled in (PWDATA). That is SETUP — everything is presented, but nothing is filed yet; the clerk is still reading. Then the clerk starts working it (PENABLE high, ACCESS). You do not snatch the form back or change the amount while they work — you leave it exactly as laid down, however long they take. When the clerk is ready they file it in a single motion and say "done" (PREADY high) — that is COMPLETE, and the filing happens on that one moment, not while they were still reading. Then the counter clears for the next customer (IDLE or the next SETUP).
Three refinements make the model precise:
- Presented complete, from SETUP.
PADDR,PWRITE, andPWDATAare all valid from the setup cycle — the subordinate has a full, settled picture one cycle before the access is performed. - Held still through ACCESS. Through every access cycle, including any wait states, the manager holds the address, direction, and data unchanged. The form on the counter does not move while the clerk works.
- Filed on one edge. The subordinate captures
PWDATAonly on the completion cycle —PSEL & PENABLE & PWRITE & PREADYall high — never onPENABLEalone and never on a wait cycle. Presence on the bus is not permission to file.
4. Real SoC / hardware context
In a real SoC the write you just walked is how the control plane configures everything: a CPU or DMA engine writes a configuration register, the access reaches an APB bridge, and the bridge drives this exact sequence onto the peripheral bus. PWRITE high tells the addressed peripheral "store this"; the bridge drives PWDATA from whatever the originating transaction supplied and holds it steady; PRDATA is left unused because nothing is being read back. The peripheral's job is one gated capture — decode the address in SETUP, but commit the register only at completion.
// APB subordinate write capture (teaching sketch — not a full slave).
// PWDATA is presented from SETUP, but the write COMMITS on exactly one
// cycle: the completion cycle of a write. Nothing commits before completion.
wire write_commit = psel & penable & pwrite & pready; // the one capture edge
always_ff @(posedge pclk or negedge presetn) begin
if (!presetn)
ctrl_reg <= '0;
else if (write_commit && (paddr == CTRL_ADDR))
ctrl_reg <= pwdata; // sample PWDATA here, at completion — never earlier
endTwo facts make this the correct write path. First, write_commit is low for the SETUP cycle (PENABLE low) and for every wait cycle (PREADY low), so the register clocks PWDATA exactly once — on the completion edge — even though the data has sat on the bus since setup. Second, the PWRITE term keeps this logic dormant on reads, so the same block ignores PWDATA whenever a read is in flight. The bus can carry the data for several cycles; the flip-flop captures it on one.
5. Engineering tradeoff table
Walking the write as a fixed IDLE-to-IDLE skeleton is a deliberate design. Each property of the sequence trades a capability APB does not need for the simplicity and certainty it does.
| Write-transfer property | What it gives up | What it buys | Why it is correct for APB |
|---|---|---|---|
| Dedicated SETUP cycle before ACCESS | One cycle of latency per write | A settle cycle to decode address and data | The subordinate acts on a stable, fully-presented transfer |
PWDATA presented from SETUP, held through ACCESS | Late, just-in-time data | A value guaranteed valid on whatever cycle completes | One capture rule works for any subordinate speed |
Capture only on completion (PSEL & PENABLE & PWRITE & PREADY) | Committing the instant data appears | A single, agreed commit edge | Manager and subordinate never disagree about when the write landed |
PRDATA unused on a write | A shared bidirectional data bus | Separate, single-driver write and read paths | PWRITE cleanly splits the two directions |
| Bounded IDLE → … → IDLE shape | Overlapping/pipelined transfers | Countable, non-overlapping transactions | Sparse control traffic does not need pipelining |
The throughline: APB spends one settle cycle and a little held-stable discipline, and in return every write is a bounded, single-commit transaction that both ends read the same way — which is exactly why an APB write is trivial to drive and trivial to debug.
6. Common RTL / waveform mistakes
7. Interview framing
"Walk me through an APB write" is one of the most common protocol questions, and it rewards a structured, cycle-by-cycle answer over a vague signal list. It tells the interviewer whether you can actually drive or debug the bus.
Walk the skeleton in order: IDLE (nothing selected) → SETUP (PSEL high, PENABLE low, with PADDR, PWRITE high, and PWDATA all presented) → ACCESS (PENABLE high) → COMPLETE (the access cycle where PREADY is high) → IDLE. Then deliver the two depth points that prove you understand timing, not just sequence: PWDATA is presented from setup but captured only at completion — never on PENABLE alone — and the address, direction, and data are held stable through ACCESS until completion, including across any wait states. Volunteering that "presented" and "captured" are different cycles, and that PRDATA is simply unused on a write, signals you have built or debugged a real interface rather than memorised a diagram.
8. Q&A
9. Practice
- Draw the clean write. Draw
PSEL,PENABLE,PWRITE,PADDR,PWDATA, andPREADYfor a write with no wait state, label the IDLE/SETUP/ACCESS/COMPLETE bands, and mark the single capture cycle. - Add a wait. Redraw the same write with one wait state. Show what holds stable across the wait and where the capture edge moves to.
- Write the wire. From memory, write the
write_commitexpression and thealways_ffthat capturespwdatainto the addressed register, and explain why each term is needed. - Find the bug. A subordinate captures
PWDATAon the first cyclePENABLEis high. On a one-wait write, mark the cycle it wrongly writes and state what could go wrong even when the captured value happens to be correct. - Account for
PRDATA. In one sentence, say whatPRDATAcarries during this write and why the manager ignores it.
10. Key takeaways
- A write is a bounded sequence: IDLE → SETUP → ACCESS → COMPLETE → IDLE. Every legal write has this shape, with one completion edge and a defined start and end.
PWRITEhigh selects the write. The manager drivesPWDATAand the read busPRDATAis unused for the whole transfer.PWDATAis presented from SETUP and held stable through ACCESS, wait states included, so it is settled early and still valid whenever the subordinate completes.- The subordinate captures
PWDATAon exactly one edge — completion, wherePSEL & PENABLE & PWRITE & PREADYare all high, never onPENABLEalone and never during a wait. - Presentation and capture are different cycles. "The data is on the bus" (from setup) and "the write has landed" (at completion) are not the same moment — confusing them is the canonical write bug.
- The skeleton is what you read off any waveform. Find SETUP, find the completion edge, and the whole write — and by extension reads and waited transfers — interprets itself.