Skip to content

A pre-tapeout RTL review is only as good as the checklist it runs against — an APB slave passes or fails silicon on a small, knowable set of structural properties, and this chapter is the categorised list a reviewer walks, item by item, before signing off. You have spent this module learning how to build an APB subordinate — PREADY generation, the write logic, the read-data mux, the address decoder, the register bank. This chapter inverts that knowledge into a review instrument. It is a design-review checklist: eleven categories, each with the concrete items a staff reviewer inspects, and for every item the trio that makes a checklist worth trusting — what to check, why it matters, and the failure it catches. The single idea to carry: a slave is not "correct because it simulated clean"; it is correct because every item on this list was verified present, and an item missing from the list is a class of bug nobody looked for.

1. Problem statement

The problem is converting the diffuse question "is this APB slave ready for tapeout?" into a finite, categorised, structurally-checkable list — so that review is an audit against known items rather than an act of intuition that misses whatever the reviewer happened not to think about.

A design review is the last cheap gate before a bug becomes a mask set. But a review conducted from memory is only as complete as the reviewer's recall on that day, and the bugs that reach silicon are precisely the ones that look fine at a glance: an ungated write-enable that only multi-commits when a wait state appears, a read-data mux with no default that emits X for an unmapped offset, a pready that is combinational off a rippling decode and glitches at gate level. None of these fail a casual read. All of them fail a checklist — because the checklist forces the reviewer to ask the specific structural question that exposes each one. Three properties make such a checklist trustworthy:

  • It must be categorised, not a flat pile. APB-slave bugs cluster into recognisable families — protocol sequencing, PREADY, write path, read path, decode, reset, register kinds, error, latches, multi-driver, CDC. Organising the checklist by category makes it auditable ("did we cover every reset item?") and maps each item onto the part of the datapath it protects.
  • Each item must state what, why, and the failure it catches. "Check the write path" is not a checklist item; "confirm wr_en = psel && penable && pwrite && pready so the register commits exactly once per write, catching the multi-commit that corrupts W1C and accumulator registers under a wait state" is. The why and the failure are what let a reviewer recognise the bug in unfamiliar RTL.
  • The items must be structural, checkable properties — not taste. Every good item can be turned into either an assertion or a lint rule. "One-hot select," "registered PREADY, known-0 out of reset," "every combinational branch assigns every output" are objective. That objectivity is what makes a review reproducible across reviewers.

So the job is not "know how an APB slave works" — you do. It is to render that knowledge as the categorised, what/why/failure checklist that a staff reviewer runs before tapeout, and that a junior can follow to catch the same escapes a veteran would.

2. Why previous knowledge is insufficient

Every prior chapter of this module taught how to build one part of the slave correctly. This chapter is the review of the whole, and building knowledge does not automatically become review knowledge:

  • Knowing how to build each block is not the same as having the list to inspect them all. You learned the write logic and the reset behaviour as separate constructions. A review needs them assembled into one ordered checklist so that nothing is skipped because it lived in a different chapter — the reset item and the register-kinds item and the CDC item all get their turn, in one pass.
  • The bug catalogues taught individual failures; the checklist is the preventive gate. PREADY common design bugs, write corruption, address-decode bugs, and incorrect PRDATA each dissect a failure after it exists. The review checklist is the before: the item you check so that failure never ships. Each catalogue entry has a matching checklist line whose whole purpose is to make that catalogue entry impossible.
  • A rules catalogue tells you what "legal APB" is; the review checklist tells you what to look at in the RTL. The protocol-rules catalogue enumerates the bus-level contract a verification environment encodes. The RTL review checklist is the implementation-side companion — not "what does the spec require on the wires" but "which lines of RTL, and which structural properties, do I inspect to be confident the slave honours it." The two are complementary: one drives assertions, the other drives the human review.

The gap is this: prior chapters gave you the parts and the failures. Neither is the ordered, categorised inspection list that turns a slave into a signed-off slave. Building that list — and teaching the one non-obvious insight that a clean simulation is not a substitute for it — is this chapter.

3. Mental model

The model: a pre-tapeout review is a pilot's pre-flight checklist, not a conversation. A pilot does not "generally check the plane looks fine" — they run a printed list, item by item, and a single unchecked item can down the aircraft. The checklist exists precisely because the expert's memory is not trusted under time pressure; the discipline is external. An APB-slave review works the same way: you walk eleven categories in order, tick each structural item, and a slave is airworthy only when every item is ticked — not when it "seemed okay."

Three refinements make the model precise:

  • Items cluster into eleven categories, and each category guards a distinct failure family. Protocol (two-phase sequencing), PREADY (registered, reachable, bounded), write path (golden wr_en, one pulse, strobes), read path (stable PRDATA, mux default, no unselected drive), decode (one-hot, no holes/overlaps, word vs byte offset), reset (polarity, known values, no X), register kinds (RW/RO/WO/W1C, reserved), PSLVERR (valid only at completion), latches (no unintended), multi-driver (one driver per net), and CDC (synchronise before gating PREADY). Every APB-slave RTL bug lives in one of these.
  • Every item maps to an assertion or a lint rule — the review is not taste. A checklist item you cannot express as a checkable property is not a review item, it is an opinion. "Registered PREADY, 0 out of reset" is a property; so is "no inferred latches" (a lint) and "one-hot select" (an SVA). This is what makes the review reproducible and lets it feed the verification plan directly.
  • The non-obvious insight: a clean RTL simulation is not proof the checklist passed. Two whole categories — the combinational-glitch variant in PREADY, and X-propagation from a missing reset — are invisible in zero-delay RTL and only surface at gate level or under an X-check. And the highest-frequency write bug, the ungated wr_en, is invisible in any zero-wait test and only appears the moment a wait state is inserted. The checklist forces you to inspect the structure precisely because passing simulation cannot. This is why review is a distinct gate, not a rerun of the regression.
A datapath-centred review map. A central blue APB-slave datapath block with request inputs, an internal register bank, and response outputs is surrounded by ten labelled review cells. Green cells across the top cover two-phase protocol, PREADY generation, and the write path. Amber cells cover address decode, register kinds, read path, reset, and PSLVERR. A red band along the bottom covers no-latch, no-multi-driver, and CDC-before-gating-PREADY. Dashed connectors tie each cell to the datapath region it protects.
Figure 1 — the RTL review checklist as ten review cells arranged around the APB-slave datapath, each cell a category and each mapped onto the part of the datapath it protects. The central blue block is the slave datapath: the request signals enter (psel, penable, pwrite, paddr, pwdata, pstrb), the register bank sits inside, and the response signals leave (prdata, pready, pslverr). Around it, the green top row holds the positive-property categories — two-phase protocol (SETUP then ACCESS, pready sampled on the access edge), PREADY generation (registered, known-0 out of reset, reachable path to 1, bounded), and the write path (golden wr_en, one pulse per write, pstrb byte lanes). The amber middle and bottom rows hold the failure-catching categories — address decode (one-hot, no holes/overlaps, word vs byte offset), register kinds (RW/RO/WO/W1C, reserved fields), read path (stable PRDATA, mux default, unselected slave does not drive), reset (polarity, known values, no X), and PSLVERR (valid only at completion). The red band along the bottom holds the cross-cutting structural gates — no unintended latch, no multi-driver, and CDC synchronised before gating PREADY. The figure is the chapter's spine: each cell is a review gate, a failed cell is a class of silicon escape, and sign-off means every cell is ticked.

4. Real SoC implementation

In a real pre-tapeout review the checklist is a categorised table the reviewer walks against the RTL, ticking each item and recording the assertion or lint that proves it. Here is the checklist itself — eleven categories, and for each item the check, and the why / failure it catches.

Protocol, PREADY, and write path

CategoryCheckWhy / failure caught
Two-phase protocolSETUP is psel && !penable; ACCESS is psel && penable the next cycle; pready is sampled only on the ACCESS edgeEnforces the AMBA APB (IHI 0024C) §2.1 SETUP→ACCESS sequence; catches a slave that acts in SETUP or samples completion in the wrong phase
Two-phase protocolpenable is never high without psel; penable is exactly one cycle after psel for each transferCatches a manager/slave that skips SETUP or holds penable across back-to-back transfers, corrupting the phase
PREADY generationpready is a registered output, driven to a known 0 out of resetCatches a combinational glitchy pready and an undriven/X pready that hangs or completes spuriously right after reset
PREADY generationThere is a guaranteed reachable path to pready = 1 from every ACCESS state, and completion is bounded (rises within N cycles)Catches the stuck-low hang (FSM state with no exit / forgotten done path) and the unbounded-wait that hangs the bus
Write pathwr_en = psel && penable && pwrite && pready — the golden termCatches the ungated wr_en that commits on every wait cycle, corrupting W1C and accumulator registers
Write pathThe write is one pulse per write (single-cycle wr_en), and PSTRB byte lanes are honoured per byteCatches the multi-commit under a wait state, and a slave that writes the full word ignoring pstrb, clobbering adjacent bytes

Read path, decode, reset, register kinds

CategoryCheckWhy / failure caught
Read pathPRDATA is stable through ACCESS and only meaningful when this slave is selectedCatches a prdata that changes mid-ACCESS or leads/lags pready, so the manager samples the wrong value
Read pathThe read-data mux has a default branch, and an unselected slave does not drive the shared PRDATA (drives 0 / stays out of the mux)Catches X on an unmapped offset and a bus fight where two slaves drive the shared read line
Address decodeSelect is one-hot with no holes and no overlaps; word vs byte offset is applied consistentlyCatches address aliasing, multi-select (two regions decode the same address), and the off-by-4 word/byte confusion
Resetpresetn is the correct polarity (active-low, async-assert); every register resets to a known value; no X survives resetCatches wrong-polarity reset that never clears, and X-propagation from an unreset flop into the datapath
Register kindsRW / RO / WO / W1C each behave per spec; reserved fields read 0 and ignore writesCatches a RO register that is accidentally writable, a W1C that clears on any write, and reserved bits that latch stray data

PSLVERR, structural gates, CDC

CategoryCheckWhy / failure caught
PSLVERRpslverr is valid only at completion (psel && penable && pready) and deasserted otherwiseCatches a spurious error asserted in SETUP or mid-wait that the manager may latch as a real fault
No unintended latchEvery combinational branch assigns every output (full case/if with defaults)Catches an inferred latch that holds stale state and diverges between simulation and synthesis
No multi-driverEach net has exactly one driver; shared response lines are muxed, not wired-OR of active driversCatches contention that produces X in simulation and a short at gate level
CDC before gating PREADYAny cross-domain term is synchronised (2-flop for a level, handshake/pulse-stretch for an event) before it gates preadyCatches metastable-hang, a missed narrow pulse, and phase-dependent intermittent completion

The single most common review catch is the write-enable — the item that looks correct until a wait state appears. Here is the wrong-versus-right, in real APB signal names:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ============================================================
// REVIEW CATCH — the ungated write-enable (highest-frequency write bug)
// ============================================================
// Inputs (APB slave): pclk, presetn, psel, penable, pwrite, paddr,
//                     pwdata, pstrb;  outputs: prdata, pready, pslverr.
 
// WRONG: wr_en omits the pready qualifier. In a ZERO-wait access it is high
// for one cycle and looks perfect. Add a single wait state and it stays high
// for the WHOLE access, re-committing pwdata on every cycle -> multi-commit.
wire wr_en_bug = psel & penable & pwrite;          // <-- missing pready
always_ff @(posedge pclk or negedge presetn) begin
  if (!presetn)        ctrl_reg <= 8'h00;
  else if (wr_en_bug)  ctrl_reg <= pwdata[7:0];    // fires every wait cycle
  // For a W1C or an accumulator reg, repeated commits corrupt the value.
end
 
// RIGHT: the golden write-enable is qualified by pready, so it is a SINGLE
// pulse on the completing edge, committing exactly the final data, once.
wire wr_en = psel & penable & pwrite & pready;      // golden term
always_ff @(posedge pclk or negedge presetn) begin
  if (!presetn) begin
    ctrl_reg <= 8'h00;                               // known value out of reset
  end else if (wr_en) begin
    // honour PSTRB byte lanes: only write the enabled byte lanes
    if (pstrb[0]) ctrl_reg <= pwdata[7:0];           // one commit, correct lane
  end
end
// pready itself: registered, 0 out of reset, a reachable path to 1, bounded.
always_ff @(posedge pclk or negedge presetn) begin
  if (!presetn)                       pready <= 1'b0;
  else if (psel && penable && !pready) pready <= 1'b1;  // guaranteed rise
  else                                pready <= 1'b0;   // one-cycle complete
end

Two facts make this the archetypal review item. First, the bug is invisible in the test everyone runs first — a zero-wait access. It only manifests once a wait state is present, which is exactly why the checklist forces the reviewer to read the structure of wr_en rather than trust a green zero-wait sim. Second, the fix is the golden term, and the golden term is checkablewr_en = psel && penable && pwrite && pready, one pulse per write, which turns directly into the review SVA in §8. The checklist item is not "the write path looks right"; it is "confirm wr_en carries the pready qualifier and pulses once," and that item catches the single highest-frequency write-corruption escape.

5. Engineering tradeoffs

A checklist is only useful if it is run, and running it involves real judgement calls about scope, automation, and where each item lives.

DecisionOption AOption BWhen to choose which
Item granularityOne atomic structural property per itemCoarse "check the write path" itemsAtomic — each maps to one assertion/lint and is independently tickable; coarse items hide the sub-check that gets skipped
EnforcementAutomate every item as SVA or a lint ruleRely on the human reviewer to rememberAutomate what you can (one-hot, no-latch, registered-pready); reserve human review for intent (register semantics, decode map)
Level of sign-offRequire RTL and gate-level for the level-sensitive itemsRTL-onlyRTL+gate for the glitch and reset-X items — they are invisible in zero-delay RTL, so RTL-only is a false pass
Checklist authorityDerive items from the AMBA spec + local bug historyCopy a generic templateSpec + bug history — the local escapes (the wr_en multi-commit you shipped once) become permanent items
Reserved / optional fieldsInclude gated items for PSTRB/PSLVERR/reserved even if unusedSkip items for signals the slave "doesn't use"Include gated — an unused-but-present signal still has legality rules; skipping is how a reserved-field write escapes

The throughline: a good review checklist is atomic, automated where possible, level-aware, spec-and-history-derived, and complete over present signals. The most important tradeoff is the level one — the single insight that a clean zero-delay RTL run is necessary but not sufficient. The glitchy combinational pready, the reset-X, and the ungated wr_en all pass some simulation; the checklist exists to catch what simulation of the wrong stimulus, at the wrong level, structurally cannot.

6. Common RTL mistakes

7. Debugging scenario

Pick the ungated write-enable, because it is the review catch that most cleanly demonstrates why the checklist beats the regression: it ships from a project that had a green, coverage-closed sign-off.

  • Observed symptom: a peripheral's interrupt-clear register — a W1C — behaves erratically in the lab. Firmware writes a 1 to clear one pending bit, but other pending bits clear too, or the clear "sticks" across a status update. In directed simulation every write to the register passed. The bug only appears in the lab, under real bus latency.
  • Waveform clue: in a capture with a wait state (Figure 2, top), wr_en is high for the entire ACCESS phase, not one cycle. The W1C register sees the clear term asserted on every wait cycle, so it applies the write-1-clear multiple times against a status vector that is changing underneath it — clearing bits the firmware never targeted.
  • Root cause: wr_en was coded as psel && penable && pwrite, missing the pready qualifier. In the directed tests the slave completed with zero wait states, so wr_en happened to be a single cycle and the bug was invisible. The lab's real slave inserts wait states; the moment it does, wr_en spans multiple cycles and the register multi-commits.
  • Correct RTL: qualify the write-enable with pready so it is a single pulse on the completing edge, committing exactly once:
    Azvya Education Pvt. Ltd.VLSI Mentor
    Snippet
    wire wr_en = psel & penable & pwrite & pready;    // golden term, one pulse
    always_ff @(posedge pclk or negedge presetn)
      if (!presetn)      irq_clr <= '0;
      else if (wr_en)    irq_clr <= irq_clr & ~pwdata; // W1C, applied once
  • Verification assertion: prove the write-enable pulses once per access and only on the completing edge (see §8).
  • Debug habit: when a write-side register misbehaves only with wait states or only in the lab, do not chase the register logic first — chase the wr_en term. If it is missing the pready qualifier, it is firing on every ACCESS cycle. The "passes directed sim, fails with real latency" signature is the ungated write-enable until proven otherwise. And the deeper lesson: the review item that would have caught it — "confirm wr_en carries pready" — is a five-second structural read that no amount of zero-wait simulation performs for you.
Two stacked APB write timing diagrams over a 2-wait-state access. The top red panel shows wr_en high across the whole ACCESS phase with three marked redundant commits of pwdata. The bottom green panel shows wr_en high for exactly one cycle on the completing edge where pready is high, committing the final data once. Both share pclk, psel, penable, pready, and pwdata rows.
Figure 2 — the write-enable review catch, wrong versus right, on the same APB write with two wait states. Top (bug, red): wr_en is computed as psel and penable and pwrite only, so it stays high across the whole ACCESS phase and re-commits pwdata on every wait cycle — three commits for one write, which corrupts a W1C or accumulator register and lets stray or drifting bus data land more than once. The three red dots mark the redundant commits. Bottom (golden, green): wr_en is the full term psel and penable and pwrite and pready, so it is high for exactly one cycle — the completing edge where pready is high — and the register is written once with the final data. The figure shows why the bug is invisible in a zero-wait test (where wr_en would be one cycle either way) and only appears once a wait state stretches the ACCESS phase, which is exactly the corner the checklist forces the reviewer to inspect.

8. Verification perspective

Because every checklist item is a structural property, the review feeds the verification plan directly: each item becomes an assertion (or a lint rule for the structural ones), and the plan's completeness is measured by which checklist items have owning assertions. A reviewer would demand at least the write-enable and completion properties.

  • The write-enable property is the one a reviewer will not sign off without. Prove that the write-enable pulses exactly once per access and only on the completing edge — this catches the multi-commit directly:
    Azvya Education Pvt. Ltd.VLSI Mentor
    Snippet
    // wr_en must carry the pready qualifier and pulse once on the completing edge
    a_wr_en_golden: assert property (@(posedge pclk) disable iff (!presetn)
      $rose(wr_en) |-> (psel && penable && pwrite && pready)
    );
    // and it must not stay high for a second consecutive cycle within an access
    a_wr_en_single_pulse: assert property (@(posedge pclk) disable iff (!presetn)
      wr_en |=> !wr_en || $fell(penable)
    );
  • Bounded completion catches the PREADY hang family; a never-X check catches the reset family. One liveness property — (psel && penable) |-> ##[1:N] pready — proves the reachable, bounded pready items in one stroke, and (psel && penable) |-> !$isunknown(pready) catches the reset/undriven case. Pair these with a one-hot select assertion ($onehot0(sel_vec)) for the decode item and a pslverr-only-at-completion property for the error item.
  • Two categories need the level dimension, and one needs lint. The combinational-glitch variant of pready and the reset-X only surface at gate level or delay-annotated simulation, so a clean RTL pass is necessary but not sufficient — the checklist explicitly marks these as gate-level items. And the no-latch and no-multi-driver items are best enforced by lint (full-case/parallel-case and driver-count checks), not SVA — the review routes each item to the tool that can actually see its failure.

The point: the checklist is not a parallel artefact to verification — it is the source list the verification plan derives from. Every ticked item is either an owning assertion, a lint rule, or a required gate-level pass, and a checklist item with no owner is a hole the sign-off must not close over.

9. Interview discussion

"How do you review an APB slave before tapeout?" is a staff-level question because the weak answer describes running the regression again, while the strong answer reveals an organised, categorised checklist and — critically — an understanding of why the review catches what the regression misses.

Lead with the structure: a slave passes silicon on a small, knowable set of structural properties, so I review against a categorised checklist — protocol, PREADY, write path, read path, decode, reset, register kinds, PSLVERR, latches, multi-driver, and CDC — and for every item I state what I check, why, and the failure it catches. Then land the depth point that separates experience from recitation: a clean simulation is not proof the checklist passed. Give the concrete example — the ungated wr_en = psel && penable && pwrite passes every zero-wait directed test and only multi-commits once a wait state appears, so it ships from green regressions and corrupts W1C registers in the lab; the review item, "confirm wr_en carries the pready qualifier and pulses once," is a five-second structural read that no zero-wait sim performs. Add the two level-sensitive families — the combinational-glitch pready and the reset-X, both invisible in zero-delay RTL and requiring gate-level or an X-check — to show you know which items simulation structurally cannot catch. Closing with "and each checklist item is a property, so the review feeds the verification plan directly — a checklist item with no owning assertion or lint is a hole" signals that you treat review as an engineering artefact, not a vibe check.

10. Practice

  1. Categorise the catch. For each of these three symptoms — "W1C clears extra bits only in the lab," "reads of an unmapped offset return X," and "the slave hangs only at certain clock ratios" — name the checklist category and the specific item that catches it.
  2. Write the golden term. State the golden write-enable expression, explain why each of its four terms is required, and describe the exact failure that appears if the pready term is dropped and a wait state is inserted.
  3. Pick the level. For the ungated wr_en, the combinational-glitch pready, the reset-X, and the one-hot decode, state for each whether a zero-delay RTL simulation can catch it, or whether it needs a wait-state stimulus, a gate-level pass, an X-check, or a lint rule.
  4. Turn an item into an assertion. Take the "registered pready, reachable path to 1, bounded" item and write the bounded-completion SVA, then state which reset-family bug it does not catch and what does.
  5. Audit a partial checklist. Given a review that covered protocol, PREADY, and the write path but skipped the read path, reset, and CDC categories, name one real escape that each skipped category would have caught.

11. Q&A

12. Key takeaways

  • A slave is tapeout-ready when every checklist item is verified present — not when it simulated clean. Review is a distinct gate: a categorised, item-by-item audit of structural properties, run against the RTL like a pilot's pre-flight, because expert memory under time pressure is not trusted.
  • The eleven categories are protocol, PREADY, write path, read path, decode, reset, register kinds, PSLVERR, latches, multi-driver, and CDC — each guarding a distinct failure family, and each item stating what to check, why, and the failure it catches, per AMBA APB (IHI 0024C) §2.1 for the two-phase sequence.
  • The golden write-enable is wr_en = psel && penable && pwrite && pready, one pulse per write. Drop the pready term and the register multi-commits on every wait cycle — the highest-frequency write bug, invisible in a zero-wait sim and caught only by structural review or a $rose(wr_en) assertion.
  • A clean RTL simulation is not proof the checklist passed. The combinational-glitch pready and the reset-X are invisible in zero-delay RTL (gate-level / X-check items), and the ungated wr_en is invisible without a wait-state stimulus — which is exactly why the review inspects structure that simulation cannot.
  • Every checklist item is a property, so the review feeds the verification plan. Each item is an owning assertion (bounded-completion, one-hot select, wr_en golden), a lint rule (no latch, no multi-driver), or a required gate-level pass — and a checklist item with no owner is a hole the sign-off must not close over.