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.

SignalDriven byMeaning
PCLKClock sourceClock; everything happens on its rising edge
PRESETnSystem resetReset, active low
PADDRRequesterByte address, up to 32 bits
PSELxRequesterSelect, one per completer: this transfer is for you
PENABLERequesterLow in the Setup phase, high in the Access phase
PWRITERequester1 = write, 0 = read
PWDATARequesterWrite data: 8, 16 or 32 bits
PRDATACompleterRead data, same width
PREADYCompleterHigh when the completer finishes the transfer (APB3 and later)
PSLVERRCompleterHigh 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. PSEL is low.
  • SETUP: the requester raises PSEL and puts the address, direction and (for a write) data on the bus. PENABLE stays low. This state always lasts exactly one cycle.
  • ACCESS: the requester raises PENABLE and holds everything else steady. The transfer completes at the rising edge where PREADY is 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);
Output
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 (PSEL high, PENABLE low) and an Access phase (PENABLE high).
  • The transfer completes at the rising edge where PSEL, PENABLE and PREADY are 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 PSEL is low.
Did you find what you were looking for?

Quiz

No quiz questions available for this article.