The APB protocol (Advanced Peripheral Bus) is the simplest member of the AMBA family. It connects low-bandwidth peripherals such as timers, UARTs and GPIO to the rest of a chip. Every APB transfer has two phases, Setup and Access, and the signals hardly change between transfers, which keeps both the logic and the power small. This article walks through an APB transfer signal by signal, then builds and simulates a four-register APB completer.
9 min read | Beginner to Intermediate
What You'll Learn
- Name the APB signals and who drives each one
- Trace the IDLE, SETUP and ACCESS states of a transfer
- Write an APB completer with registers in Verilog
- Drive APB writes and reads from a testbench
Where APB Sits
A processor never talks to APB directly. It reaches the APB through a bridge on AXI or AHB, and that bridge is the only requester on the APB bus. The bridge decodes the address into one select line per peripheral, and drives the address, direction and write data that all peripherals share. Only the selected peripheral answers.
Because there is a single requester, APB needs no arbitration. Because a peripheral answers one transfer at a time, it needs no pipelining either. That is why an APB interface takes only a few dozen gates.
The APB Signals
All APB signals start with P and are sampled on the rising edge of PCLK. The specification calls the bridge side the Requester and the peripheral side the Completer.
| Signal | Driven by | Meaning |
|---|---|---|
| PCLK | Clock source | Clock; everything happens on its rising edge |
| PRESETn | System reset | Reset, active low |
| PADDR | Requester | Byte address, up to 32 bits |
| PSELx | Requester | Select, one per completer: this transfer is for you |
| PENABLE | Requester | Low in the Setup phase, high in the Access phase |
| PWRITE | Requester | 1 = write, 0 = read |
| PWDATA | Requester | Write data: 8, 16 or 32 bits |
| PRDATA | Completer | Read data, same width |
| PREADY | Completer | High when the completer finishes the transfer (APB3 and later) |
| PSLVERR | Completer | High to report an error, optional (APB3 and later) |
APB4 and APB5 add a few more signals, such as byte strobes and protection bits. They are covered in APB4 and APB5.
Setup and Access
An APB interface is always in one of three states:
- IDLE: no transfer.
PSELis low. - SETUP: the requester raises
PSELand puts the address, direction and (for a write) data on the bus.PENABLEstays low. This state always lasts exactly one cycle. - ACCESS: the requester raises
PENABLEand holds everything else steady. The transfer completes at the rising edge wherePREADYis high. Until then the interface stays in ACCESS.
After ACCESS, the interface goes back to SETUP if another transfer is waiting, or to IDLE. Either way PENABLE drops, so every transfer takes at least two cycles. APB gives up speed here on purpose: the completer gets a whole cycle to decode the address before the transfer counts.
Quick Check
Q: How does a completer know that it is in the Access phase rather than the Setup phase?
Show Answer
By PENABLE. Both phases have PSEL high; PENABLE is low in Setup and high in Access.
A Four-Register Completer
Here is a complete APB completer with four 32-bit registers at byte addresses 0x0, 0x4, 0x8 and 0xC. Bits 3:2 of the address pick the register. It never needs extra time, so PREADY is tied high, and it never reports an error.
module apb_regs (
input PCLK,
input PRESETn,
input PSEL,
input PENABLE,
input PWRITE,
input [11:0] PADDR,
input [31:0] PWDATA,
output reg [31:0] PRDATA,
output PREADY,
output PSLVERR
);
reg [31:0] r [0:3];
integer i;
wire [1:0] idx = PADDR[3:2]; // word index: byte address bits 3:2
// A write takes effect in the Access phase: PSEL and PENABLE both high
always @(posedge PCLK) begin
if (!PRESETn) begin
for (i = 0; i < 4; i = i + 1)
r[i] <= 32'h0;
end
else if (PSEL && PENABLE && PWRITE) begin
r[idx] <= PWDATA;
end
end
// Read data is driven during the transfer
always @(*) begin
if (PSEL && !PWRITE)
PRDATA = r[idx];
else
PRDATA = 32'h0;
end
assign PREADY = 1'b1;
assign PSLVERR = 1'b0;
endmodule
Two details are worth noticing. The write happens on the clock edge at the end of the Access phase, when PSEL, PENABLE and PREADY are all high; a completer with PREADY tied high can leave PREADY out of the condition. And PRDATA is combinational, so the data is ready during the Access cycle when the requester samples it.
The Requester Side
In a testbench, the requester is two tasks. Each one runs the Setup phase for one cycle, then the Access phase until PREADY is high:
task apb_write(input [11:0] addr, input [31:0] data);
begin
@(posedge PCLK); // Setup phase
PSEL <= 1;
PENABLE <= 0;
PWRITE <= 1;
PADDR <= addr;
PWDATA <= data;
@(posedge PCLK); // Access phase
PENABLE <= 1;
@(posedge PCLK);
while (!PREADY)
@(posedge PCLK);
PSEL <= 0; // transfer complete
PENABLE <= 0;
end
endtask
task apb_read(input [11:0] addr, output [31:0] data);
begin
@(posedge PCLK);
PSEL <= 1;
PENABLE <= 0;
PWRITE <= 0;
PADDR <= addr;
@(posedge PCLK);
PENABLE <= 1;
@(posedge PCLK);
while (!PREADY)
@(posedge PCLK);
data = PRDATA; // sampled at the completing edge
PSEL <= 0;
PENABLE <= 0;
end
endtask
The testbench writes two registers and reads them back:
apb_write(12'h004, 32'hCAFE_0001);
apb_write(12'h008, 32'h1234_5678);
apb_read (12'h004, rdata);
apb_read (12'h008, rdata);
45 write 0x004 = 0xcafe0001 75 write 0x008 = 0x12345678 105 read 0x004 = 0xcafe0001 135 read 0x008 = 0x12345678
Each transfer is a Setup cycle followed by an Access cycle. The tasks also leave one idle cycle between transfers, so a transfer starts every three cycles. A bridge that has another transfer waiting can go straight from ACCESS to SETUP and start one every two cycles.
Why APB Holds Its Signals
Look at PADDR and PWRITE in the waveform: they do not return to zero between transfers. A requester is free to leave them at their last value, and a low-power bridge does exactly that. Signals that do not toggle do not burn power, and the next transfer often goes to the same peripheral anyway. This works because a completer looks only at PSEL and PENABLE to decide whether a transfer is happening, and ignores every other APB signal while its PSEL is low.
Quick Check
Q: A completer writes its register when PSEL && PWRITE is true, without checking PENABLE. What goes wrong?
Show Answer
The register is written at the end of the Setup cycle and again at the end of the Access cycle. For a plain register that is harmless, but for a register with side effects, such as a FIFO write port or a write-1-to-clear status bit, the action happens twice.
Running It in ChipVerify Lab
The example contains the four-register completer and the testbench with the write and read tasks. Run it, open the waveform, and find the Setup and Access cycle of each transfer.
Common Mistakes
Mistake #1: Acting in the Setup phase
Writes and other side effects belong in the Access phase, qualified with PSEL && PENABLE (and PREADY when the completer can stall). Acting on PSEL alone triggers the action twice.
Mistake #2: Decoding the address with the wrong bits
PADDR is a byte address. Registers at 0x0, 0x4, 0x8 and 0xC are picked by bits 3:2, not 1:0. Using the low bits makes every register alias onto the same storage.
Mistake #3: Changing PADDR or PWDATA during Access
The requester must hold the address, direction and write data from Setup until the transfer completes. A requester that updates them early writes the wrong value or reads the wrong register.
Practice Exercise
Challenge: Back-to-Back Transfers
Change the testbench so that the second write starts with its Setup phase right after the first write's Access phase, with no idle cycle in between. How many cycles do the four transfers take now?
Hint
The tasks wait for a rising edge before the Setup phase. If the next task starts its Setup at the same edge where the previous transfer completes, the idle cycle disappears.
Solution
task apb_write(input [11:0] addr, input [31:0] data);
begin
PSEL <= 1; // Setup starts at the current edge
PENABLE <= 0;
PWRITE <= 1;
PADDR <= addr;
PWDATA <= data;
@(posedge PCLK);
PENABLE <= 1;
@(posedge PCLK);
while (!PREADY)
@(posedge PCLK);
end
endtask
Call the tasks after one @(posedge PCLK), make apb_read match, and drop PSEL and PENABLE after the last transfer. Each transfer now takes two cycles, so the four transfers take 8 cycles instead of 12.
Open the ready-made example in the lab and run the simulation.
Summary
- APB connects peripherals to the chip through a bridge, which is the only requester on the bus.
- Every transfer has a one-cycle Setup phase (
PSELhigh,PENABLElow) and an Access phase (PENABLEhigh). - The transfer completes at the rising edge where
PSEL,PENABLEandPREADYare all high. - The requester holds the address, direction and write data steady through the transfer.
- A completer acts in the Access phase only and ignores the bus while its
PSELis low.