The three-state APB FSM — IDLE, SETUP, and ACCESS — the exact conditions for every transition, what signals must hold in each state, back-to-back transfers without returning to IDLE, and a complete annotated state diagram from the spec.
The APB interface operates as a simple three-state finite state machine. The state machine runs entirely in the Requester (APB bridge) — the Completer (peripheral) does not have a state machine; it only responds to the signals driven by the Requester.
PSELx = 0PENABLE = 0PSELx = 1PENABLE = 0PSELx = 1PENABLE = 1The state machine starts in IDLE after reset. It enters SETUP when the bridge needs to start a transfer, spends exactly one clock cycle there, then moves unconditionally to ACCESS. It remains in ACCESS until the Completer asserts PREADY, at which point it either returns to IDLE (no further transfers) or jumps directly to SETUP (back-to-back transfer to the same or a different peripheral).
IDLE is the default state of the APB interface. The system enters IDLE after reset and returns to IDLE between transfers (unless back-to-back transfers occur — see ACCESS). In IDLE:
PSELx = 0 — no Completer is selectedPENABLE = 0 — no transfer in progressThe Requester exits IDLE when it has a transfer to perform. It asserts PSELx for the target Completer and presents PADDR, PWRITE, PWDATA (if write) and control signals. On the next rising clock edge the system is in SETUP.
The SETUP state is entered when the bridge asserts PSELx to start a transfer. In SETUP:
PSELx = 1 — target Completer is selectedPENABLE = 0 — distinguishes Setup from Access phasePADDR must be valid and stablePWRITE must be valid (1=write, 0=read)PWDATA must be valid for write transfersPPROT, PSTRB, PAUSER, PWUSER must be valid and stableThe Completer uses the SETUP cycle to decode the address and prepare for the transfer. It should use this cycle to determine which register is being accessed and whether the access is permitted. By the time ACCESS begins (PENABLE asserted), the Completer should be ready to complete the transfer — if it is not, it deasserts PREADY to add wait states.
The ACCESS state is entered unconditionally from SETUP on the clock cycle after PSELx was asserted. In ACCESS:
PSELx = 1 — Completer remains selectedPENABLE = 1 — marks this as the Access phaseThe Completer controls exit from ACCESS via PREADY:
On exit from ACCESS (PREADY=1), the bridge chooses one of two paths:
| From | To | Condition | What happens |
|---|---|---|---|
| IDLE | SETUP | Transfer required | Bridge asserts PSELx for target Completer. Presents PADDR, PWRITE, PWDATA, PPROT, PSTRB. PENABLE stays LOW. |
| IDLE | IDLE | No transfer pending | Interface stays idle. PSELx and PENABLE remain deasserted. No signal changes required. |
| SETUP | ACCESS | Always — next rising edge | Bridge asserts PENABLE. All other signals hold their values from SETUP. The Completer may now assert PREADY to complete in this cycle, or deassert PREADY to insert wait states. |
| ACCESS | ACCESS | PREADY = 0 | Wait state. All bus signals (PADDR, PWRITE, PWDATA, PSELx, PENABLE, PPROT, PSTRB, PAUSER, PWUSER) must remain completely unchanged. |
| ACCESS | IDLE | PREADY = 1 AND no transfer pending | Transfer completes. Bridge deasserts PSELx and PENABLE. Interface returns to default idle state. |
| ACCESS | SETUP | PREADY = 1 AND next transfer pending | Transfer completes AND next transfer begins simultaneously. Bridge deasserts PENABLE, updates address/control signals for next transfer, keeps or switches PSELx. No idle cycle between the two transfers. |
This timing diagram shows all three state paths in one waveform: a write with wait state → completion → back-to-back read → idle.
| Signal | IDLE | SETUP | ACCESS (wait) | ACCESS (complete) |
|---|---|---|---|---|
PSELx | 0 | 1 | 1 | 1 (then 0) |
PENABLE | 0 | 0 | 1 | 1 (then 0) |
PADDR | Don’t care | Valid & stable | Must not change | Stable (then can change) |
PWRITE | Don’t care | Valid & stable | Must not change | Stable (then can change) |
PWDATA | Don’t care | Valid (write only) | Must not change | Stable (then can change) |
PPROT | Don’t care | Valid & stable | Must not change | Stable (then can change) |
PSTRB | Don’t care | Valid & stable | Must not change | Stable (then can change) |
PREADY | Don’t care | Don’t care | 0 (Completer not ready) | 1 (Completer ready) |
PRDATA | Don’t care | Don’t care | Undefined (Completer preparing) | Valid (Completer drives) |
PSLVERR | Rec: 0 | Rec: 0 | Rec: 0 | Valid (error indicator) |
The APB state machine in a bridge is straightforward. Here is a synthesisable SystemVerilog implementation:
typedef enum logic [1:0] {IDLE=2'b00, SETUP=2'b01, ACCESS=2'b10} apb_state_t;
apb_state_t state;
always_ff @(posedge PCLK or negedge PRESETn) begin
if (!PRESETn) begin
state <= IDLE;
PSELx <= 1'b0;
PENABLE <= 1'b0;
end else begin
case (state)
IDLE: begin
if (transfer_req) begin
state <= SETUP;
PSELx <= 1'b1;
PENABLE <= 1'b0;
PADDR <= req_addr;
PWRITE <= req_write;
PWDATA <= req_wdata;
end
end
SETUP: begin
state <= ACCESS; // always
PENABLE <= 1'b1;
end
ACCESS: begin
if (PREADY) begin
PENABLE <= 1'b0;
if (transfer_req) begin
state <= SETUP; // back-to-back
PADDR <= req_addr;
PWRITE <= req_write;
PWDATA <= req_wdata;
end else begin
state <= IDLE;
PSELx <= 1'b0;
end
end // else stay in ACCESS (wait state)
end
endcase
end
end
The SETUP→ACCESS transition has no condition — state <= ACCESS is unconditional in the SETUP case. This directly encodes the spec rule that SETUP always lasts exactly one cycle.
| Item | Rule |
|---|---|
| Number of states | 3 — IDLE, SETUP, ACCESS |
| State machine owner | Requester (APB bridge) — the Completer has no state machine |
| IDLE: PSELx | 0 — no Completer selected |
| IDLE: PENABLE | 0 |
| SETUP: PSELx | 1 |
| SETUP: PENABLE | 0 — distinguishes Setup from Access |
| SETUP duration | Always exactly 1 clock cycle — no exceptions, no conditions |
| SETUP→ACCESS | Unconditional — always on the next rising clock edge after SETUP |
| ACCESS: PSELx | 1 |
| ACCESS: PENABLE | 1 |
| ACCESS wait state condition | PREADY=0 → stay in ACCESS, all bus signals must hold |
| ACCESS completion condition | PREADY=1 → transfer completes on this rising edge |
| ACCESS→IDLE condition | PREADY=1 AND no next transfer pending |
| ACCESS→SETUP condition | PREADY=1 AND next transfer pending (back-to-back) |
| Back-to-back benefit | Eliminates one idle cycle between transfers to the same or different peripheral |
| PREADY in SETUP | Don’t care — Completer may drive anything, Requester ignores it |
| Signals stable during wait | PADDR, PWRITE, PWDATA, PSELx, PENABLE, PPROT, PSTRB, PAUSER, PWUSER |
| PRDATA valid when | Only at ACCESS completion (PSEL+PENABLE+PREADY=1, PWRITE=0) |
| PSLVERR valid when | Only at ACCESS completion (PSEL+PENABLE+PREADY=1) |