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 && preadyso 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 (goldenwr_en, one pulse, strobes), read path (stablePRDATA, 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 gatingPREADY). 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 ungatedwr_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.
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
| Category | Check | Why / failure caught |
|---|---|---|
| Two-phase protocol | SETUP is psel && !penable; ACCESS is psel && penable the next cycle; pready is sampled only on the ACCESS edge | Enforces 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 protocol | penable is never high without psel; penable is exactly one cycle after psel for each transfer | Catches a manager/slave that skips SETUP or holds penable across back-to-back transfers, corrupting the phase |
| PREADY generation | pready is a registered output, driven to a known 0 out of reset | Catches a combinational glitchy pready and an undriven/X pready that hangs or completes spuriously right after reset |
| PREADY generation | There 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 path | wr_en = psel && penable && pwrite && pready — the golden term | Catches the ungated wr_en that commits on every wait cycle, corrupting W1C and accumulator registers |
| Write path | The write is one pulse per write (single-cycle wr_en), and PSTRB byte lanes are honoured per byte | Catches 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
| Category | Check | Why / failure caught |
|---|---|---|
| Read path | PRDATA is stable through ACCESS and only meaningful when this slave is selected | Catches a prdata that changes mid-ACCESS or leads/lags pready, so the manager samples the wrong value |
| Read path | The 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 decode | Select is one-hot with no holes and no overlaps; word vs byte offset is applied consistently | Catches address aliasing, multi-select (two regions decode the same address), and the off-by-4 word/byte confusion |
| Reset | presetn is the correct polarity (active-low, async-assert); every register resets to a known value; no X survives reset | Catches wrong-polarity reset that never clears, and X-propagation from an unreset flop into the datapath |
| Register kinds | RW / RO / WO / W1C each behave per spec; reserved fields read 0 and ignore writes | Catches 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
| Category | Check | Why / failure caught |
|---|---|---|
| PSLVERR | pslverr is valid only at completion (psel && penable && pready) and deasserted otherwise | Catches a spurious error asserted in SETUP or mid-wait that the manager may latch as a real fault |
| No unintended latch | Every 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-driver | Each net has exactly one driver; shared response lines are muxed, not wired-OR of active drivers | Catches contention that produces X in simulation and a short at gate level |
| CDC before gating PREADY | Any cross-domain term is synchronised (2-flop for a level, handshake/pulse-stretch for an event) before it gates pready | Catches 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:
// ============================================================
// 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
endTwo 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 checkable — wr_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.
| Decision | Option A | Option B | When to choose which |
|---|---|---|---|
| Item granularity | One atomic structural property per item | Coarse "check the write path" items | Atomic — each maps to one assertion/lint and is independently tickable; coarse items hide the sub-check that gets skipped |
| Enforcement | Automate every item as SVA or a lint rule | Rely on the human reviewer to remember | Automate what you can (one-hot, no-latch, registered-pready); reserve human review for intent (register semantics, decode map) |
| Level of sign-off | Require RTL and gate-level for the level-sensitive items | RTL-only | RTL+gate for the glitch and reset-X items — they are invisible in zero-delay RTL, so RTL-only is a false pass |
| Checklist authority | Derive items from the AMBA spec + local bug history | Copy a generic template | Spec + bug history — the local escapes (the wr_en multi-commit you shipped once) become permanent items |
| Reserved / optional fields | Include gated items for PSTRB/PSLVERR/reserved even if unused | Skip 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_enis 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_enwas coded aspsel && penable && pwrite, missing thepreadyqualifier. In the directed tests the slave completed with zero wait states, sowr_enhappened to be a single cycle and the bug was invisible. The lab's real slave inserts wait states; the moment it does,wr_enspans multiple cycles and the register multi-commits. - Correct RTL: qualify the write-enable with
preadyso it is a single pulse on the completing edge, committing exactly once:Azvya Education Pvt. Ltd.VLSI MentorSnippetwire 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_enterm. If it is missing thepreadyqualifier, 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 — "confirmwr_encarriespready" — is a five-second structural read that no amount of zero-wait simulation performs for you.
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 MentorSnippet
// 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, boundedpreadyitems 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 apslverr-only-at-completion property for the error item. - Two categories need the level dimension, and one needs lint. The combinational-glitch variant of
preadyand 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
- 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.
- 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
preadyterm is dropped and a wait state is inserted. - Pick the level. For the ungated
wr_en, the combinational-glitchpready, 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. - 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. - 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 thepreadyterm 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
preadyand the reset-X are invisible in zero-delay RTL (gate-level / X-check items), and the ungatedwr_enis 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_engolden), 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.