Skip to content

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 answerwhich 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:

  • PSEL high with PWRITE high → the request. This is a write being launched; the manager is pushing a value out, not reading one.
  • PWDATA (and PADDR) 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.
  • PENABLE rising → the access boundary. The push enters its acknowledge-and-commit phase; PENABLE then 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 first PREADY-high access cycle is the one commit edge — the register changes there.
  • PSLVERR at the commit → applied or faulted. A write can complete with PREADY high and still not apply if PSLVERR is high on that edge.

Read in that order and every write interprets itself — and every broken one fails a specific step.

An annotated APB write timing diagram of a zero-wait write: IDLE then SETUP with PSEL high, PWRITE high, PADDR and PWDATA valid and held, PENABLE low, then one ACCESS cycle with PENABLE and PREADY high where the register captures PWDATA on the dashed commit edge, with PSLVERR low so the write applied, then IDLE.
Figure 1 — a fully annotated fast zero-wait APB write walked IDLE to IDLE against PCLK with the full write signal set. In IDLE, PSEL is low. SETUP raises PSEL and drives PWRITE high — the request, a write, is located — presents PADDR and PWDATA, and holds them while PENABLE stays low. ACCESS raises PENABLE; the fast subordinate drives PREADY high on that same cycle, so PSEL, PENABLE, PWRITE, and PREADY are all high on the single commit edge, marked with a dashed line, where the addressed register captures PWDATA. PADDR and PWDATA are shown as one continuous held band from setup through the commit. PSLVERR is low across the transfer, so the write applied. Every key edge is labelled: the request located by PSEL and PWRITE high, the held PWDATA, the PENABLE rise into access, the single commit edge, and the clean PSLVERR.

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 PSLVERR is high, or PWDATA was 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 PSEL high with PWRITE high (this is a write) and confirm PWDATA/PADDR stay flat across access before searching for the commit, because a held value is what makes the commit meaningful. The first PREADY-high access cycle is the commit; the PREADY-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, PWDATA is merely offered; the register still holds its old value.
  • PSLVERR is the final gate. A write can complete normally — PREADY high, one clean commit edge — and still not apply, with PSLVERR high. 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.

An annotated APB write timing diagram with two wait states: PSEL high through SETUP and ACCESS, PWRITE high, PENABLE held high across three access cycles, PREADY sampled low on the first two and high on the third marking the single commit edge where the register captures PWDATA, PADDR and PWDATA held byte-for-byte across all three cycles, and PSLVERR low so the write applied.
Figure 2 — a fully annotated slow APB write with two wait states, read with the same method against PCLK. The phase bands read IDLE, SETUP, then ACCESS spanning three cycles labelled WAIT, WAIT, COMMIT, then IDLE. PSEL rises into SETUP with PWRITE high, then PENABLE rises and is held high across all three access cycles. PREADY is sampled low on the first two access cycles — the two wait states where the commit is delayed — and high only on the third, the single commit edge marked with a dashed line, where the register captures PWDATA. PADDR and PWDATA are held byte-for-byte across the entire access phase as one continuous band; the value is offered the whole time but stored once. PSLVERR is low, so the write applied. The figure labels the two wait cycles, the held address and data, and the single commit edge — showing the method is unchanged from the fast write, only the wait count differs.

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.

An annotated APB write timing diagram of an error write: PSEL high, PWRITE high, PADDR and PWDATA held, one ACCESS cycle with PENABLE and PREADY high marking the completion edge so the transfer completes, but PSLVERR high on that edge and the register marked not updated, showing the write finishes yet did not apply.
Figure 3 — a fully annotated error APB write against PCLK. The phase bands read IDLE, SETUP, ACCESS COMPLETE ERROR, IDLE. PSEL rises into SETUP with PWRITE high, PADDR and PWDATA held, then PENABLE rises into the single access cycle and the subordinate drives PREADY high — so the transfer completes normally on one completion edge, not retried and not hung. But on that same edge PSLVERR is high, signalling an error response, and the addressed register is not updated — no side effect. The dashed completion marker is drawn in red, and the annotations stress two facts: the transfer still completes on the single edge where PSEL, PENABLE, PWRITE, and PREADY are all high, and the write did not apply because PSLVERR is high — a faulted write, distinct from a normal commit.

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 moveThe shortcut it rejectsWhat it buysWhy 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 writePSEL 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 commitsThe 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 commitPENABLE 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 countThe 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 storedThe 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 effectiveA 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

Two stacked APB write waveforms with one wait state: the top legal write holds PWDATA flat across the wait and commit and captures the intended value; the bottom illegal write, in red, changes PWDATA during access before the commit, so move 2 of the method fails and the wrong value would be captured.
Figure 4 — classifying a write with the seven-move method: a legal write (top, green) versus an illegal data-not-held write (bottom, red), both with one wait state. In the legal write, PADDR and PWDATA are held byte-for-byte across the wait and the commit, so move 2 — confirm PWDATA is presented and held — passes, and the commit captures the intended value. In the illegal write, PWDATA changes during the access phase, before the commit edge, while PREADY is still low, so the manager let go of the data early; the change is drawn in red, move 2 fails, and the commit would capture the wrong value. The figure teaches that an illegal write fails exactly one move, which both names the bug and points to the side that owns it — here the manager, which must hold PWDATA until the commit.

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: PWDATA and PADDR are $stable while PSEL is high and the commit has not happened (covers move 2), the model's register updates only on write_commit = psel & penable & pwrite & pready and never on a PREADY-low wait (covers moves 4 and 5), and the write is recorded as effective only when PSLVERR is 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_commit with PSLVERR low, the reference model updates model_reg[paddr] = pwdata; on a commit with PSLVERR high it records no side effect. A later read-back compared against model_reg catches 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 PSLVERR high, and a write whose PWDATA changes between back-to-back transfers (to catch a stale-data or data-not-held capture). Functional coverage on write_commit && paddr per 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

  1. Run the seven moves. Take the fast write (Figure 1) and write the answers in order: where the request is (PSEL high, PWRITE high), whether PWDATA is held, where access begins, how many PREADY-low waits, which cycle is the commit, that the register changes there, and whether PSLVERR clears it.
  2. 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.
  3. 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.
  4. 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.
  5. Localise the lost write. Given a write waveform where PREADY and PWDATA look 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 PSEL high with PWRITE high, and confirming PWDATA/PADDR stay 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, and PREADY are all high is the single commit edge; the PREADY-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, PWDATA is 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.
  • PSLVERR is the final gate — a write can complete on a clean commit edge and still not apply, with PSLVERR high. Completion and "applied" are separate checks; skip the gate and firmware trusts a register that never took the value.