Skip to content

AMBA APB · Module 11

Slave Reset Behaviour

The slave's behaviour under PRESETn — async-assert/sync-release of the active-low reset to avoid release metastability, every software-visible register to a defined reset value, the FSM coming up in IDLE with safe bus outputs, and handling the first post-reset access cleanly.

Reset is the one input that defines where the slave begins. Every other chapter in this module has described what the slave does once it is running — how it decodes, when it asserts PREADY, when it raises PSLVERR. This chapter is about the instant before any of that: what the slave looks like while PRESETn is asserted, and how it crosses cleanly into normal operation when reset releases. The single idea to carry: reset is the slave's known-good starting state — PRESETn is active-LOW, applied async-assert / sync-release, and on its release every software-visible register sits at a defined value while the FSM comes up in IDLE driving safe bus outputs, ready to handle the first access cleanly. Get this right and the slave boots into a state firmware can trust; get it wrong and the first transfer after reset hangs, double-completes, or branches firmware on garbage it read at offset zero.

1. Problem statement

The problem is defining a single, deterministic state the slave enters on PRESETn and leaves cleanly on release — a state in which every software-visible register holds a known value, the bus outputs are safe, and the control FSM is parked where the next transfer can start correctly.

PRESETn is the APB reset: a shared, active-LOW signal that travels alongside PCLK to every peripheral on the bus. When it is asserted (driven low), the slave must abandon whatever it was doing and converge to a defined baseline. That baseline is not a vague "cleared" state — it is a precise contract with three audiences:

  • Firmware, which reads the registers at boot. The first thing software does after release is read configuration and status. Every software-visible register must therefore power up at a defined reset value — enables off, status cleared, interrupt masks in their safe (usually masked) state — or boot firmware branches on whatever the flop happened to settle to.
  • The bus, which must not see a spurious transfer. While reset is asserted and across its release, the slave must drive its outputs safe: PREADY low (or at its defined idle), PSLVERR low, PRDATA to a defined value. No half-finished transfer may complete, and no access may be latched as reset releases.
  • The slave's own FSM, which must come up parked. The state machine that sequences SETUP/ACCESS and generates PREADY must reset into IDLE, not into the middle of a transfer — so the first access after release runs the full, correct handshake.

And there is a timing requirement underneath all of it: PRESETn must be applied so that assertion is immediate (even with no clock) but release is clean (re-timed to PCLK), so no flop in the slave goes metastable the moment reset lets go. That combination — async-assert, sync-release — is what turns "set everything to zero" into "leave reset deterministically."

So the job is not "clear the flops." It is to define a complete reset state — register values, bus outputs, FSM position — and a reset release discipline that lands the slave in that state cleanly on a known clock edge.

2. Why previous knowledge is insufficient

The earlier chapters in this module built the slave's running behaviour and quietly assumed a clean starting point. This chapter is where that assumption is paid for.

  • Chapter 11.1 — Register-Bank Design introduced that each register has a reset value (if (!presetn) ctrl <= 32'h0;) but treated it as a one-line default. Reset is not a default — it is a specification. Which value each register takes at reset is a design decision firmware depends on (enables off so the peripheral is inert at boot, status cleared so no stale event is reported, masks safe so no spurious interrupt fires). This chapter makes the reset value a first-class part of the register's contract.
  • Chapter 11.5 — PREADY Generation built the FSM and the PREADY logic — but a PREADY FSM is only correct if it starts correct. If the FSM comes out of reset in ACCESS instead of IDLE, the first transfer never runs its SETUP phase and PREADY either hangs low forever or is already high and the access double-completes. The reset position of that FSM is exactly what this chapter pins down.
  • Chapter 11.6 — PSLVERR Generation defined when PSLVERR is raised — and reset is the one time it must be guaranteed low. A slave that comes out of reset with a stale PSLVERR high reports a phantom error on the first access. The reset state of every bus output is this chapter's concern.
  • The protocol knowledge says nothing about release metastability. Nothing earlier explained that de-asserting PRESETn is itself a clock-domain hazard: if reset releases asynchronously, different flops can capture it on different edges, and the FSM can resolve into an illegal state. That is a reset-architecture problem, not a protocol one.

So the model to add is the slave's initial condition and release discipline: defined reset values for every visible register, the FSM parked in IDLE, all bus outputs safe, and PRESETn applied async-assert / sync-release so release lands on a clean edge. With that nailed, Chapter 11.8 — Slave RTL Templates can assemble the whole slave knowing its starting state is sound.

3. Mental model

The model: reset is the slave's "power-on snapshot" — the exact frame the slave freezes into and unfreezes from. Think of a vending machine being switched on: while the power-on relay is held (reset asserted), the machine shows nothing, accepts no coins, and dispenses nothing — it is inert and safe. The instant the relay releases, it must be sitting at its home screen (IDLE), with the price display showing the configured defaults (registers at reset values) and the coin slot ready for the first coin (first access). It must never unfreeze halfway through dispensing a drink nobody ordered.

Three refinements make it precise:

  • PRESETn is active-LOW and asynchronous on assert. "Asserted" means driven to 0. The slave's flops use an asynchronous reset path so that the moment PRESETn goes low — even if PCLK is stopped or gated — every flop is forced to its reset value immediately. You do not wait for a clock edge to become safe.
  • Release is synchronised to PCLK. De-asserting reset is the dangerous part. If PRESETn rises at a random point relative to PCLK, some flops may sample it as 1 and others as 0 on the same edge, and a multi-flop FSM can land in an illegal state — or a single flop can go metastable. The fix is a reset synchroniser: route PRESETn through two flip-flops clocked by PCLK so its release is re-timed to a clean edge, while its assert stays asynchronous. This is the async-assert / sync-release idiom.
  • The reset state is a complete tuple, not just "zero." It is { every register = its defined reset value, FSM = IDLE, PREADY = idle/low, PSLVERR = 0, PRDATA = defined }. Each element serves a different audience — registers serve firmware, the FSM serves the next transfer, the outputs serve the bus — and all of them must hold simultaneously the moment release completes.
A two-part figure: at top, a reset synchroniser with a raw active-low reset asynchronously clearing two PCLK-clocked flip-flops whose output is the slave's internal synchronised reset, labelled async-assert and sync-release; at bottom, a waveform showing PRESETn asserted low with all registers at defined reset values and PREADY, PSLVERR and PRDATA at safe values, then on the synchronised release edge the FSM entering IDLE and a first clean access following.
Figure 1 — async-assert / sync-release PRESETn and the slave coming up in IDLE. Top: a reset synchroniser — the raw active-LOW reset asynchronously clears two cascaded flip-flops clocked by PCLK, and the second flop drives the slave's internal presetn. Because the clear path is asynchronous, reset *assert* reaches the flops immediately with no clock; because release passes through the two flops, reset *de-assert* is re-timed to a clean PCLK edge, so the slave cannot go metastable on release. Bottom: a waveform across the reset window — while PRESETn is low (amber) every software-visible register holds its defined reset value and the bus outputs are safe (PREADY low/idle, PSLVERR low, PRDATA defined); on the synchronised release edge the FSM enters IDLE (green) and the first APB access is handled cleanly. The figure shows reset as the slave's known-good starting state.

4. Real SoC implementation

In RTL, three things must be true: (1) PRESETn reaches the slave through a synchroniser so release is clean; (2) every flop uses the active-LOW asynchronous-reset form with a defined reset value; (3) the FSM and bus outputs reset to IDLE and safe. Here is the standard structure.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ----------------------------------------------------------------------------
// Reset synchroniser: async ASSERT, sync RELEASE.
// The raw reset asserts the two flops asynchronously (no clock needed), but
// its de-assertion ripples through FF1 -> FF2 and so is re-timed to PCLK.
// The slave uses `presetn` (the synchronised output), never `presetn_raw`.
// ----------------------------------------------------------------------------
module apb_reset_sync (
  input  logic pclk,
  input  logic presetn_raw,   // active-LOW, may release asynchronously
  output logic presetn        // active-LOW, release synchronised to pclk
);
  logic rst_ff1, rst_ff2;
  always_ff @(posedge pclk or negedge presetn_raw)
    if (!presetn_raw) begin   // ASYNC assert: forced low immediately
      rst_ff1 <= 1'b0;
      rst_ff2 <= 1'b0;
    end else begin            // SYNC release: walks 0 -> 1 across two edges
      rst_ff1 <= 1'b1;
      rst_ff2 <= rst_ff1;
    end
  assign presetn = rst_ff2;
endmodule
 
// ----------------------------------------------------------------------------
// Slave core, clocked by the SYNCHRONISED presetn.
// Note every always_ff uses (posedge pclk or negedge presetn): async assert.
// ----------------------------------------------------------------------------
module apb_slave_core (
  input  logic        pclk, presetn,        // presetn = synchronised reset
  input  logic        psel, penable, pwrite,
  input  logic [31:0] pwdata,
  output logic        pready, pslverr,
  output logic [31:0] prdata
);
  // --- control/status registers: each with a DEFINED reset value (11.1) ---
  logic [31:0] ctrl;     // RW config  : reset = 0  -> peripheral disabled at boot
  logic        iflag;    // W1C flag   : reset = 0  -> no stale event reported
  logic [31:0] imask;    // RW mask    : reset = 0  -> interrupts masked (safe)
 
  always_ff @(posedge pclk or negedge presetn)
    if (!presetn) begin
      ctrl  <= 32'h0000_0000;   // enables OFF: nothing runs until firmware writes it
      iflag <= 1'b0;            // status CLEARED: handler sees no phantom event
      imask <= 32'h0000_0000;   // masks SAFE: no spurious interrupt out of reset
    end else begin
      if (psel && penable && pwrite && pready) begin
        ctrl  <= pwdata;        // normal write path (decode elided for brevity)
        imask <= pwdata;
      end
    end
 
  // --- PREADY FSM (11.5): MUST come up in IDLE ---
  typedef enum logic [1:0] {IDLE, SETUP, ACCESS} state_t;
  state_t state;
 
  always_ff @(posedge pclk or negedge presetn)
    if (!presetn) state <= IDLE;           // parked in IDLE out of reset
    else unique case (state)
      IDLE   : state <= psel ? SETUP  : IDLE;
      SETUP  : state <= penable ? ACCESS : SETUP;
      ACCESS : state <= IDLE;
      default: state <= IDLE;              // illegal state recovers to IDLE
    endcase
 
  // --- bus outputs: SAFE values in/after reset (11.5 / 11.6) ---
  always_ff @(posedge pclk or negedge presetn)
    if (!presetn) begin
      pready  <= 1'b0;          // not ready -> no transfer completes in reset
      pslverr <= 1'b0;          // no phantom error on the first access
      prdata  <= 32'h0000_0000; // defined, not X
    end else begin
      pready  <= (state == SETUP);              // single-cycle ready (11.5)
      pslverr <= 1'b0;                          // raised by error logic (11.6)
      prdata  <= ctrl;                          // read mux (elided)
    end
endmodule

Two facts make this the right structure. First, PRESETn is asynchronous on assert but synchronous on release: each always_ff triggers on negedge presetn so assertion forces flops to their reset value with no clock, while the synchroniser guarantees the presetn those flops actually see only releases on a clean PCLK edge — so no flop, and no FSM, resolves into a metastable or illegal state when reset lets go. Second, the reset branch of every flop is a deliberate value, not a reflex zero: ctrl/imask reset off so the peripheral is inert and interrupts are masked at boot, iflag resets clear so no stale event is reported, the FSM resets to IDLE so the first transfer runs its full handshake, and pready/pslverr/prdata reset to safe so the bus sees nothing spurious. That tuple is the slave's contract with firmware and the bus — and it is exactly what Chapter 11.8 — Slave RTL Templates drops into the full slave.

5. Engineering tradeoffs

Every signal and register in the slave has a reset state, and choosing it is a deliberate trade between firmware safety, area, and bus correctness. This table is the slave's reset contract.

Signal / registerReset valueWhy this value
PRESETn (the input)active-LOW asserted (0)The bus reset is active-LOW; "in reset" means PRESETn == 0. Applied async-assert / sync-release so release never causes metastability.
FSM stateIDLEThe slave must come up parked so the first access runs the full SETUP/ACCESS handshake; any other start state hangs or double-completes the first transfer.
PREADY0 (idle / not ready)No transfer may complete while in reset or across release; ready must come from the FSM, not survive reset.
PSLVERR0No phantom error on the first access; error is asserted only by the error logic on a real access (11.6).
PRDATAdefined (0), not XA defined read-bus avoids X-propagation into the master and gives a deterministic value if read before configuration.
CTRL / enable bits0 (disabled)The peripheral must be inert at boot — nothing runs until firmware explicitly enables it; a peripheral that auto-starts on reset is a safety and power hazard.
Interrupt mask0 (masked)Interrupts default to masked so a peripheral cannot fire an IRQ before firmware has installed a handler.
IFLAG / status (W1C)0 (cleared)Status comes up clean so the first handler does not service a phantom event; software reads a true "nothing happened" state.
FIFO / data RAM contentsusually not resetLarge arrays are left un-reset to save area and routing; they are not software-visible at boot value and are filled before use. Only the pointers/flags that are visible reset.
Shadow / pipeline regsdefined if observable, else freeReset only what is software-visible or affects bus behaviour; resetting everything costs area and reset-tree fanout for no benefit.

The throughline: reset everything software reads at boot or that drives the bus, to a value chosen for firmware safety (enables off, status cleared, masks safe) — and leave large internal arrays un-reset to save area. The discriminator is visibility: if firmware or the bus can observe it before it is otherwise written, it needs a defined reset value; if not, resetting it is wasted silicon.

6. Common RTL mistakes

7. Debugging scenario

The signature reset bug is a slave whose first transfer after reset hangs or double-completes, caused by an unsynchronised reset release that lets the PREADY/state FSM leave reset in a non-IDLE state — and it only appears occasionally, because it depends on exactly where PRESETn releases relative to PCLK.

  • Observed symptom: the very first APB access after a reset intermittently misbehaves — sometimes the transfer never completes (the master waits on PREADY forever and the bus locks up), and sometimes it completes instantly and a second time (a double-complete). After the second access everything is normal. The failure rate changes with reset timing, supply, and temperature — the hallmark of a metastability/skew bug, not a logic bug.
  • Waveform clue: zoom in on the PRESETn release. In the failing runs PRESETn rises between two PCLK edges, and the FSM's state flops disagree — one captures the released value a cycle later than the others — so on the first post-reset edge the FSM register reads a non-IDLE encoding (or briefly an X). The PREADY line then either stays low through the first access or is already high as the access begins.
  • Root cause: the slave's PRESETn was driven directly from an asynchronous reset source with no reset synchroniser, so reset release was not re-timed to PCLK. The multi-bit FSM state register sampled the release on different edges across its bits, resolving into an illegal/non-IDLE state — the FSM came out of reset already "mid-transfer," so the first access did not run a clean SETUP/ACCESS sequence. The bug is in the reset architecture, not in the FSM logic, which is why the FSM looks correct in isolation.
  • Correct RTL: route PRESETn through a two-flop reset synchroniser (async-assert / sync-release) so the presetn the slave's flops see only releases on a clean PCLK edge, and give the FSM a default: state <= IDLE; so even a momentary illegal encoding recovers — always_ff @(posedge pclk or negedge presetn) if (!presetn) state <= IDLE; else unique case(state) ... default: state <= IDLE; endcase. With release synchronised, every state bit leaves reset on the same edge and the FSM comes up in IDLE.
  • Verification assertion: check that one cycle after reset de-asserts, the FSM is in IDLE and every bus output is safe — assert property (@(posedge pclk) $rose(presetn) |=> (state == IDLE) && (pready == 1'b0) && (pslverr == 1'b0) && !$isunknown(prdata));. Add a companion that no transfer is ever in flight at the moment of reset release: assert property (@(posedge pclk) $rose(presetn) |-> $past(!pready, 1));.
  • Debug habit: when the first access after reset misbehaves intermittently but later accesses are fine, do not debug the FSM logic — go straight to the reset release. Check whether PRESETn is synchronised before it reaches the flops, and whether the FSM comes up in IDLE. Intermittent, timing-sensitive first-transfer failures are almost always an unsynchronised reset release or a missing default state, not a bug in the transfer logic itself.
Two stacked waveforms comparing reset release. The top correct case in green shows PRESETn released on a synchronised PCLK edge, the FSM entering IDLE, and a single clean PREADY pulse on the first access. The bottom buggy case in red shows PRESETn released asynchronously between clock edges, the FSM state resolving into a non-IDLE or X value, and PREADY never asserting so the first access hangs.
Figure 2 — unsynchronised versus synchronised reset release. Top (correct, green): PRESETn passes through a two-flop synchroniser, so release is re-timed to PCLK and all FSM state bits leave reset on the same clean edge; the FSM comes up in IDLE and the first access produces one clean PREADY pulse. Bottom (bug, red): PRESETn is released asynchronously, so it rises between PCLK edges and the FSM's state flops capture it on different edges — one releases a cycle late — and the FSM resolves into a non-IDLE / X state out of reset; the first access then hangs because PREADY never asserts (or double-completes if PREADY is already high). The figure shows the failure lives in the reset *release* path, and the fix is async-assert / sync-release through a reset synchroniser.

8. Verification perspective

Reset behaviour is verified by treating "the slave out of reset" as a checkable contract: a defined value on every visible register, the FSM in IDLE, safe bus outputs, and a clean first access — all on a synchronised release.

  • Reset-value check for every register. After PRESETn de-asserts and before any write, read (or back-door peek) every software-visible register and assert it equals its specified reset value. A register model (UVM RAL or equivalent) automates this across the whole map; the test is only meaningful if the model declares the correct reset value per register — enables off, status cleared, masks safe — which is the design intent from this chapter.
  • FSM-in-IDLE-after-reset. Assert that on the first PCLK edge after release the control FSM is in IDLE and not in any transfer state. Pair it with an illegal-state assertion that the FSM never observes an encoding outside its legal set — assert property (@(posedge pclk) disable iff(!presetn) state inside {IDLE, SETUP, ACCESS}); — to catch a corrupt release.
  • First-post-reset access. The single highest-value functional test: immediately after release, drive a full APB read and a full APB write and check each runs the complete handshake — PREADY asserts exactly once, the write commits, the read returns the reset value, PSLVERR stays low. This is precisely the scenario the unsynchronised-release bug breaks, so it must be an explicit, directed test, not left to random stimulus.
  • Reset-release timing and X-propagation. Run the release at many phases relative to PCLK (and, in gate-level sim, with X-injection / X-pessimism enabled) to confirm no flop the slave exposes resolves to X after release and the FSM never lands non-IDLE. Reset-synchroniser CDC checks (the lint/CDC tool flagging an unsynchronised reset reaching sequential logic) belong here too — they catch the bug structurally before simulation does.
  • Reset assertion mid-transfer. Assert PRESETn in the middle of an in-flight access and check the slave abandons it cleanly: outputs go safe, no partial write commits, and on release the slave is back in the full reset state with the FSM in IDLE. A slave that latches a half-finished transfer through a reset is broken.

The point: reset is a property, not an event. Verify the full reset tuple — every register's value, the FSM in IDLE, safe outputs — directly drive the first post-reset access, and sweep the release timing so the sync-release discipline is actually exercised, not assumed.

9. Interview discussion

"How does an APB slave behave under reset?" is a deceptively deep question: a weak answer says "everything goes to zero," while a strong one shows you think about async-assert / sync-release, defined reset values for firmware, and the FSM coming up in IDLE.

Lead with the reset architecture: PRESETn is active-LOW, applied async-assert / sync-release through a reset synchroniser — assert is asynchronous so flops are forced safe immediately even with no clock, but release is re-timed to PCLK across two flops so no flop and no FSM goes metastable or lands in an illegal state when reset lets go. This single point separates engineers who have built reset trees from those who have only typed if (!rst). Then cover the reset state: every software-visible register resets to a value chosen for boot safety — enables off so the peripheral is inert, status cleared so no phantom event is reported, interrupt masks safe so no IRQ fires before firmware is ready — because firmware reads these registers at boot before it writes anything. Add that the control FSM must reset to IDLE so the first access runs its full SETUP/ACCESS handshake, and that bus outputs reset safePREADY low, PSLVERR low, PRDATA defined — so the bus sees nothing spurious. Close with judgment: you do not reset everything — large data arrays are left un-reset to save area; the discriminator is visibility, and you reset exactly what firmware or the bus can observe before it is otherwise written. Mentioning that the intermittent "first transfer after reset hangs" bug is an unsynchronised release, not an FSM logic error, signals you have actually debugged one.

10. Practice

  1. Classify the reset. State what "async-assert / sync-release" means for PRESETn, why assertion is asynchronous and release is synchronous, and what failure each half prevents.
  2. Write the synchroniser. From memory, write the two-flop reset synchroniser (always_ff @(posedge pclk or negedge presetn_raw)) and explain how it makes release clean while keeping assert immediate.
  3. Fill the reset contract. For a peripheral with a config register, an interrupt-mask register, a W1C status register, and a 16-entry data FIFO, give each a reset value (or "not reset") and one sentence of justification.
  4. Place the FSM. Explain why the PREADY FSM must reset to IDLE, and describe exactly how the first post-reset access fails if it resets to ACCESS instead.
  5. Find the bug. Given a slave whose first transfer after reset intermittently hangs while later transfers are fine, name the most likely root cause and the one-line architectural fix.

11. Q&A

12. Key takeaways

  • PRESETn is active-LOW and is the slave's known-good starting state. "In reset" means PRESETn == 0; on its release the slave must land in a complete, defined state — registers, FSM, and bus outputs all at known values simultaneously.
  • Apply reset async-assert / sync-release. Assertion is asynchronous so flops go safe immediately even with no clock; release is re-timed to PCLK through a two-flop synchroniser so no flop or FSM goes metastable or lands illegal when reset lets go. A sync reset alone does not fix an asynchronous release.
  • Every software-visible register resets to a value chosen for firmware safety — enables off (inert peripheral), status cleared (no phantom event), interrupt masks safe (no IRQ before a handler). Firmware reads these at boot, so an un-reset register is a real bug.
  • The control FSM must reset to IDLE and bus outputs must reset safePREADY low, PSLVERR low, PRDATA defined — so the first access runs the full handshake and the bus sees nothing spurious. A default: state <= IDLE; recovers any illegal encoding.
  • You do not reset everything. Reset exactly what firmware or the bus can observe before it is otherwise written; leave large data arrays (FIFOs, RAMs) un-reset to save area and reset-tree fanout. The discriminator is visibility.
  • The intermittent "first transfer after reset hangs" bug is an unsynchronised reset release, not FSM logic. Verify reset as a property — every register's value, FSM in IDLE, safe outputs, a clean first access — and sweep the release timing so the sync-release discipline is actually exercised.