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.
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.
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).
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!