AMBA APB · Module 7
Write Waveform Analysis
A repeatable method for reading any APB write waveform — locate the request, confirm PWDATA is held, find the access, count the PREADY-low waits, land on the commit edge, confirm the register commits, and check PSLVERR — applied to fast, slow, and error writes.
Module 7 gave you the write rules one piece at a time: the manager pushes PWDATA, the value is held from setup through completion, PREADY paces the acknowledgement, the register commits on one edge, and PSLVERR reports failure. This capstone converts those rules into a skill — a fixed, repeatable method for reading any APB write waveform from left to right and saying exactly what value the register captured, on which cycle, or that it captured nothing at all. The single idea to carry: you read a write waveform by following the push, not by scanning signals — locate the request, confirm the data is held, find the access, count the waits, land on the one commit edge, confirm the register commits there, and check PSLVERR to know whether it applied. The same seven moves read a fast write, a slow write, and a faulted one.
1. Problem statement
The problem is turning a write's waveform rows into one precise answer — which cycle does the register change, what value lands there, and did the write apply or fault — the same way every time, whether the write is instant, stalled, or failed.
A write waveform is a handful of rows (PSEL, PENABLE, PWRITE, PADDR, PWDATA, PREADY, PSLVERR) over a few cycles, and a beginner draws the wrong conclusion by reading them in the wrong order. They see PENABLE high and say "the register changed here" — but PENABLE is high across every wait cycle, while the commit has not happened yet. They assume PWDATA only matters on one cycle and never check that it was held across the access. They see PREADY high, call the write done, and never glance at PSLVERR — and record a value the subordinate never actually stored. The fix is a fixed reading order that maps each waveform feature to a write fact:
PSELhigh withPWRITEhigh → the request. This is a write being launched; the manager is pushing a value out, not reading one.PWDATA(andPADDR) held across access → the data is good for whatever cycle commits. A write engineer must see the data band stay flat from setup through the commit, because the manager owns its stability.PENABLErising → the access boundary. The push enters its acknowledge-and-commit phase;PENABLEthen stays high for the whole access, waits included.PREADY→ the cadence and the commit edge.PREADY-low access cycles are waits where nothing has committed; the firstPREADY-high access cycle is the one commit edge — the register changes there.PSLVERRat the commit → applied or faulted. A write can complete withPREADYhigh and still not apply ifPSLVERRis high on that edge.
Read in that order and every write interprets itself — and every broken one fails a specific step.
2. Why previous knowledge is insufficient
You arrive here with the write flow as a one-way push, PWDATA timing telling you the value must be held from setup through the commit, the PREADY interaction pacing the waits, and write error handling telling you PSLVERR flags a write that did not apply. Each is a rule. None of them, by itself, is a procedure — and an engineer in front of an unfamiliar write waveform, or a broken one, needs a procedure, not a list of facts.
The gap is three-fold:
- The rules are unordered; reading must be ordered. Knowing the write facts does not tell you which to apply first. Look for the commit before you have located the request and confirmed the held data, and you cannot even say which value would land there. The request, the held data, and the access must be located before the commit can be judged.
- The rules describe one write; waveforms vary. A rule says "the register commits on the completion edge." A real write might insert zero, one, or many wait cycles, so "find the commit" is a search, not a fixed cycle. The method has to be wait-count-agnostic.
- The rules assume a good write; debugging starts from a broken one. Every rule above is stated for a write that lands. Debugging means reading a waveform where
PSLVERRis high, orPWDATAwas dropped early, or the commit never happens — and you need the same method to localise which step failed, turning Module 7's write rules into a reading method and a debugging tool for a write that came back wrong.
So the model to add is not another signal rule. It is the discipline of reading a write: a fixed seven-move pass that takes the write rules you already know and makes them a method you can run on any write waveform, fast, slow, or faulted.
3. Mental model
The model: read a write waveform like watching a letter dropped into a mailbox — find where you presented the letter, confirm you held it at the slot, follow it to the click, confirm the slot actually accepted it, and check the slot did not flash "rejected." The request is presenting the letter, the held PWDATA is your hand staying at the slot, the commit edge is the click, and PSLVERR is the rejected light you check before you believe it was filed.
Picture scanning the waveform left to right with seven moves on a card, asked in order. You do not stare at all the rows at once; you locate the request, then confirm the data band is held, then find the access, then walk the access cycles counting waits, then land on the commit edge, then confirm the register commits there, then check PSLVERR. By the time you reach the last move you have already drawn the one cycle the register changes, so deciding whether it applied is trivial — you know exactly where to look and what could disqualify it.
Three refinements make the method precise:
- Request first, held data second, commit by search. Locate
PSELhigh withPWRITEhigh (this is a write) and confirmPWDATA/PADDRstay flat across access before searching for the commit, because a held value is what makes the commit meaningful. The firstPREADY-high access cycle is the commit; thePREADY-low ones before it are waits, and nothing has committed across them. - The register changes once, at the commit. The write-enable pulses on exactly one cycle — the commit edge. On setup and during any wait,
PWDATAis merely offered; the register still holds its old value. PSLVERRis the final gate. A write can complete normally —PREADYhigh, one clean commit edge — and still not apply, withPSLVERRhigh. A write that completes is not the same as a write that landed; the last move separates the two.
4. Real SoC implementation
In practice you run this method on a simulation waveform or a logic-analyser capture during bring-up, and the three writes below are the cases you will read constantly: the fast write (a register that accepts immediately), the slow write (a target across a clock domain or behind a FIFO that inserts backpressure), and the error write (an unmapped, read-only, or access-protected address). Reading all three with the same seven moves is the whole point — the method does not change, only the wait count and the PSLVERR value do.
The slow write. The reading is identical to the fast write up to the wait count, where it diverges: PENABLE is held high across three access cycles, PREADY is sampled low on the first two — those are the wait states, where nothing has committed — and high only on the third. The commit search therefore lands on the third access cycle as the single commit edge, and that is the only cycle the register changes. PADDR and PWDATA are held byte-for-byte across all of access, waits included; the value was offered the whole time but is stored only once. PSLVERR is low, so the write applied.
The error write. The first six moves run exactly as on the fast write: request located, data held, access found, no waits, one commit edge with PREADY high — the write completes, it is not retried and does not hang. The seventh move is where it breaks: on that commit edge PSLVERR is high. The transfer is finished and the bus moves on, but the addressed register was not updated — there is no side effect. This is exactly why the last move exists: a write that completes is not the same as a write that applied.
5. Engineering tradeoffs
The seven-move method is a deliberate reading discipline. Each move trades a tempting shortcut for a reading that stays correct on every write — fast, slow, or faulted.
| Reading move | The shortcut it rejects | What it buys | Why it is correct for an APB write |
|---|---|---|---|
Locate the request by PSEL high + PWRITE high | "Start where the address appears" | A real write, identified as a write | PSEL high is the protocol start; PWRITE high confirms direction |
Confirm PWDATA held across access | "The data only matters on one cycle" | A value guaranteed good on whatever cycle commits | The manager owns PWDATA stability; an early drop captures garbage |
Locate access by PENABLE rise | "PENABLE high means the register changed" | The access boundary, separated from the commit | PENABLE is high across waits, before anything has committed |
Find the commit by first PREADY-high | "The register changes at the first access cycle" | Correct reading at any wait count | The subordinate owns how long the acknowledgement takes |
| Confirm the register commits at that edge | "It completed, so it landed" | A write you can trust actually stored | The commit is a hidden state change, not visible on the bus |
Check PSLVERR at the commit | "PREADY high means it applied" | A write you may treat as effective | A write can complete and still not apply, with PSLVERR high |
The throughline: by reading request and held data first, finding the commit by search, and gating "applied" on PSLVERR, the method is immune to the three things that vary across writes — wait-state count, whether the commit is fast or slow, and whether the write succeeded — so the same seven moves cover the fast write, the slow write, and the error write.
6. Common RTL mistakes
7. Debugging scenario
8. Verification perspective
A write's effect is a hidden state change, so a write monitor cannot watch it on the bus — it must encode the reading method as assertions and predict the commit. The standard structure is a write monitor plus a reference model: the monitor runs the seven moves continuously, and the model captures what the commit should have stored.
- Encode the method, move for move. The monitor asserts the same things you read by eye:
PWDATAandPADDRare$stablewhilePSELis high and the commit has not happened (covers move 2), the model's register updates only onwrite_commit = psel & penable & pwrite & preadyand never on aPREADY-low wait (covers moves 4 and 5), and the write is recorded as effective only whenPSLVERRis low on that edge (covers move 7). Each assertion is one move of the method made executable. - Model the commit, not the access. On each
write_commitwithPSLVERRlow, the reference model updatesmodel_reg[paddr] = pwdata; on a commit withPSLVERRhigh it records no side effect. A later read-back compared againstmodel_regcatches a misgated, mistimed, or faulted commit — the very symptoms the debug scenario classifies, now caught automatically. - Cover the corners that hide write bugs. Coverage should hit: a write to every register, a write-then-immediate-read-back, a write with wait states, a write with
PSLVERRhigh, and a write whosePWDATAchanges between back-to-back transfers (to catch a stale-data or data-not-held capture). Functional coverage onwrite_commit && paddrper register closes the "did we ever write this one" gap.
The point: because the effect is invisible on the bus, the seven-move method encoded as assertions is the test. A write monitor that only checks PREADY rose has verified nothing about whether the data was held, the right value reached the right register, or the write actually applied.
9. Interview discussion
Interviewers test this by sliding a write waveform across the table and asking "what did this write store, on which cycle — and did it actually apply?" The weak candidate points at PENABLE high and says "the register changed there"; the strong one runs a visible, ordered method and narrates each move. Demonstrating the procedure is the answer.
Say it as the seven-move pass: find PSEL high with PWRITE high — that is a write request; confirm PWDATA and PADDR stay flat across access — the data is held; find where PENABLE rises — that is access; walk the access cycles and the PREADY-low ones are waits where nothing has committed; the first PREADY-high access cycle is the single commit edge where the register changes; confirm the register commits on exactly that edge; then check PSLVERR on the same edge to know whether the write applied or faulted. The depth signals that land: state that the method is identical for zero waits and ten — the commit is found by searching for the first PREADY-high cycle, not by a fixed position — that the manager owns PWDATA stability so confirming the held band is a real move, not a formality, and that the final PSLVERR gate separates "the write completed" from "the write applied," which is precisely the bug a sloppy capture misses. An interviewer hears a repeatable engineering method, not memorised trivia.
10. Practice
- Run the seven moves. Take the fast write (Figure 1) and write the answers in order: where the request is (
PSELhigh,PWRITEhigh), whetherPWDATAis held, where access begins, how manyPREADY-low waits, which cycle is the commit, that the register changes there, and whetherPSLVERRclears it. - Re-run on the slow write. Do the same for Figure 2 and confirm only the wait-count answer differs from the fast write — and state what the register holds on each of the two wait cycles.
- Gate on
PSLVERR. For the error write (Figure 3), state which of the seven moves the write passes, which one it fails, and what the manager must conclude about the register. - Classify the illegal write. For Figure 4, name which single move the bottom write fails, the cycle the data was let go, the wrong value that would land, and the side that owns the bug.
- Localise the lost write. Given a write waveform where
PREADYandPWDATAlook normal but a read-back returns the old value, name the move most likely failing and the signal conjunction it checks.
11. Q&A
12. Key takeaways
- Read a write waveform by following the push, not by scanning signals — locate the request, confirm the data is held, find the access, count the waits, land on the one commit edge, confirm the register commits there, then check
PSLVERR, always in that order. - The request is
PSELhigh withPWRITEhigh, and confirmingPWDATA/PADDRstay flat across access is a real move — the manager owns the data, so an early drop captures the wrong value on whatever cycle commits. - Find the commit by searching, not by position — the first access cycle where
PSEL,PENABLE,PWRITE, andPREADYare all high is the single commit edge; thePREADY-low access cycles before it are waits where the register still holds its old value. - The register changes on exactly one cycle — the commit edge. During setup and every wait,
PWDATAis only offered; nothing is stored, and the value lands once. - The method is wait-count-agnostic. Fast write or ten-wait write, the same seven moves apply identically; only the count of
PREADY-low cycles differs. PSLVERRis the final gate — a write can complete on a clean commit edge and still not apply, withPSLVERRhigh. Completion and "applied" are separate checks; skip the gate and firmware trusts a register that never took the value.