This is a walkthrough of the APB specification AMBA 3 APB Protocol. The spec is short, but I thought to document my notes anyway.

Introduction Link to heading

APB is AMBA’s low-speed bus that provides basic write/read transfer. No pipelines with a minimum access time of 2 cycles.

Transfers Link to heading

Chapter 2 explains write and read transfers with 2 variants:

  • No wait (exactly 2 cycles)
  • Wait (more than 2 cycles)

I will go through the write transfer and how that relates to the FSM in chapter 2. The read transfer should be the same.

For no-wait write transfer, the spec provides the following timing diagram.

Example image

The order of events in the diagram:

  • At T1, the master asserts PSEL, PADDR, PWRITE
  • At T2, the master asserts PENABLE, and the slave asserts PREADY
  • At T3, data is latched, and the transfer is done.

A quick and dirty model of the master would look something like this:

    @(posedge PRESETn);
    @(posedge PCLK);
    PSELx = 1;
    PADDR  = 0;
    PWRITE = 1;
    PWDATA = 2;
    @(posedge PCLK);
    PENABLE = 1;
    @(posedge PCLK);
    PSELx = 0;
    PENABLE = 0;

In the case of a wait transfer, the slave can introduce wait states with PREADY, and the master has to keep all signals stable until PREADY is asserted.

Example image

APB master FSM Link to heading

Chapter 3 shows the following FSM for APB transfer. It shows the 3 transitions on master signals during 2 cycles (T1, T2, T3).

Example image

So, what about the slave FSM? The slave has to be one clock cycle behind the master. So, for no-wait, the PREADY is asserted in the setup state or stays de-asserted until the slave is ready for transfer.

The slave should be simpler than the master. Basically, the slave needs to do 2 things:

  • Wait for PSEL and assert PREADY if ready.
  • Do the transfer (read or write) whenever both PENABLE and PREADY.

I wrote a small (again quick and dirty) slave model. I assume the slave will have an internal flag to indicate it’s ready to do the transfer. In this example, ready.

If both ready and PSEL are asserted, PREADY will be asserted.

If the master starts a new transfer, it will have to go back to setup/idle which means PENABLE will be de-asserted anyway.

// internal ready flag
logic ready=0;
logic pready;

assign PREADY = pready;

always @(posedge PCLK) begin
    if (PRESETn == 0 ) begin
        pready <= #1 1'b1;
    end
    else begin
        if (PSELx == 1)  begin
            if(ready == 1) begin
                pready <= #1 1;
            end
            else begin
                pready <= #1 0;
            end
        end
    end
end

always @(posedge PCLK) begin
    if (pready && PENABLE) begin
    $display($time,, "DATA ADDR=%x, DATA=%x", PADDR, PWDATA);
    end
end

I used iverilog and gtkwave to test the master and slave above which works. Kinda!

Example image