APB(Advanced Peripheral Bus)是AMBA总线体系的一部分。相较于AMBA总线体系中的其他总线,APB总线具有低功耗,低复杂度的特征。APB总线主要应用于对性能要求不太高的低带宽外设接口。
本文所讲述的是AMBA4中的APB协议。其信号如下:

其中,PCLK和PRESETn分别为时钟信号和复位信号,PADDR为地址(至多32位),PPROT为保护类型,PSELx为选中信号,当它为1时,表明选中该从设备,因此每个从设备都会有一个对应的PSELx信号,PENABLE为使能信号,下面会详细阐述,PWRITE表示本次传输的方向,1表示写,0表示读,PWDATA为要写的数据,至多32bit,PSTRB为字节选中信号,第i位为1,表示第i*8到第i*8+7位是有效的,PRDATA为读出的数据,同样至多32位,PSLVERR为传输失败指示信号,为1且PENABLE、PSELx、PREADY均为高时,表明传输错误,否则表示传输正确。
下图是PPROT信号各个位的含义

Write transfers
With no wait states
无等待的写传输,如下图所示,写传输分为两个阶段:Setup Phase和Access Phase,第一个周期,PADDR给出要写的地址、PWRITE为1表示写传输,同时PSELx拉高选中设备,PWDATA给出要写的数据,此时PENABLE为0,这个阶段叫做Setup Phase。第二个周期,上述信号保持不变,主机和从机分别拉高PENABLE和PREADY,写入数据完成,下一个周期,PSELx、PENABLE以及PREADY均拉低。(若紧接着下一次传输,则PSELx无需拉低)

With wait states
有等待的写传输,如下图所示,第一个阶段和上面相同,第二阶段,PENABLE拉高,直到检测到从机的PREADY信号也为高时,Access阶段才完成。而在等待PREADY信号为高期间,PADDR,PWRITE,PSELx,PWDATA,PSTRB,PPROT信号均应该保持不变。

从有等待写传输和无等待写传输的时序中,我们可以看出,Access Phase只有在PSEL、PENABLE和PREADY信号同时为高时,才会发生,否则需要等待。
Read transfers
With no wait states
与无等待的写传输唯一不同的地方,就是在下图中,PWRITE信号是0,表示读数据。

With wait states

APB总线的状态机
下图为APB总线协议的状态机,需要注意的是,当ACCESS完成后,如果还有一次传输,则直接跳转到SETUP阶段,否则跳回IDLE阶段。

System Verilog代码
slave
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/03/29 21:22:43
// Design Name:
// Module Name: apb_slave
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module apb_slave(
input logic PCLK,
input logic PRESETn,
input logic [31:0] PADDR,
input logic [2:0] PPROT,
input logic PSELx,
input logic PENABLE,
input logic PWRITE,
input logic [31:0] PWDATA,
input logic [3:0] PSTRB,
output logic PREADY,
output logic [31:0] PRDATA,
output logic PSLVERR
);
localparam N = 32;
logic [31:0] REG [0:N-1];
logic [31:0] ADDR;
logic [3:0] STRB;
logic WRITE;
//ADDR锁存
always_ff@(posedge PCLK)
if(PSELx&&~PENABLE)
ADDR<=PADDR;
//STRB锁存
always_ff@(posedge PCLK)
if(PSELx&&~PENABLE)
STRB<=PSTRB;
//WRITE
always_ff@(posedge PCLK)
if(PSELx&&~PENABLE) //SETUP阶段
WRITE<=PWRITE;
//PREADY
always_ff@(posedge PCLK,negedge PRESETn)
if(~PRESETn)
PREADY<=1;
else if(PSELx&&~PENABLE) //SETUP阶段结束
PREADY<=1;
else if(PSELx&&PENABLE&&PREADY) //ACCESS阶段结束
PREADY<=0;
//PRDATA
assign PRDATA=REG[ADDR];
//WRITE
always_ff@(posedge PCLK,negedge PRESETn)
if(~PRESETn)
begin
for(int i=0;i<N;i++)
REG[i]=0;
end
else if(PENABLE&&PSELx&&PREADY&&WRITE) //将数据写入寄存器
begin
for(int i=0;i<4;i++)
begin
if(STRB[i])
REG[ADDR][(i*8)+:8]<=PWDATA[(i*8)+:8];
end
end
//PSLVERR
assign PSLVERR=0;
endmodulemaster
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/03/29 21:42:49
// Design Name:
// Module Name: apb_master
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module apb_master(
input logic start,
//
input logic PCLK,
input logic PRESETn,
output logic PWRITE,
output logic PENABLE,
output logic PSELx,
output logic [31:0] PADDR,
output logic [2:0] PPROT,
output logic [3:0] PSTRB,
input logic [31:0] PRDATA,
output logic [31:0] PWDATA,
input logic PREADY,
input logic PSLVERR
);
localparam WRITE = 0;
localparam READ = 1;
localparam IDLE = 2;
localparam END= 3;
logic [1:0] cur_state;
logic [1:0] next_state;
always_ff@(posedge PCLK,negedge PRESETn)
if(~PRESETn)
cur_state<=IDLE;
else
cur_state<=next_state;
//
always_comb
begin
case(cur_state)
IDLE:if(start)
next_state=WRITE;
else
next_state=IDLE;
WRITE:if(PENABLE&&PSELx&&PREADY&&PWRITE)
next_state=READ;
else
next_state=WRITE;
READ:if(PENABLE&&PSELx&&PREADY&&~PWRITE)
next_state=END;
else
next_state=READ;
END:next_state=END;
endcase
end
//PWRITE
always_comb
begin
if(cur_state==WRITE)
PWRITE=1;
else
PWRITE=0;
end
//PADDR
assign PADDR=32'd4;
//PSTRB
assign PSTRB=4'b0101;
//PWDATA
assign PWDATA={8'h3,8'h4,8'h5,8'h6};
//PSELx
always_ff@(posedge PCLK,negedge PRESETn)
if(~PRESETn)
PSELx<=0;
else if(next_state==WRITE&&cur_state!=WRITE) //
PSELx<=1;
else if(next_state==READ&&cur_state!=READ)
PSELx<=1;
else if(PENABLE&&PSELx&&PREADY) //一次ACCESS完成
PSELx<=0;
//PENABLE
always_ff@(posedge PCLK,negedge PRESETn)
if(~PRESETn)
PENABLE<=0;
else if(PSELx&&~PENABLE) //SETUP结束
PENABLE<=1;
else if(PENABLE&&PSELx&&PREADY) //ACCESS结束
PENABLE<=0;
endmodule测试平台
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/03/29 21:56:45
// Design Name:
// Module Name: apb_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module apb_tb;
logic PCLK;
logic PRESETn;
logic [31:0] PADDR;
logic [2:0] PPROT;
logic PSELx;
logic PENABLE;
logic PWRITE;
logic [31:0] PWDATA;
logic [3:0] PSTRB;
logic PREADY;
logic [31:0] PRDATA;
logic PSLVERR;
logic start;
//PCLK
initial begin
PCLK=0;
forever begin
#5 PCLK=~PCLK;
end
end
//PRESETn
initial
begin
PRESETn=0;
#50
PRESETn=1;
end
//start
initial
begin
start=0;
#102
start=1;
#10
start=0;
end
apb_slave U1(.*
// logic PCLK,
// logic PRESETn,
// logic [31:0] PADDR,
// logic [2:0] PPROT,
// logic PSELx,
// logic PENABLE,
// logic PWRITE,
// logic [31:0] PWDATA,
// logic [3:0] PSTRB,
// logic PREADY,
// logic [31:0] PRDATA,
// logic PSLVERR
);
//
apb_master U2(.*
// start,
// //
// logic PCLK,
// logic PRESETn,
// logic PWRITE,
// logic PENABLE,
// logic PSELx,
// logic [31:0] PADDR,
// logic [2:0] PPROT,
// logic [3:0] PSTRB,
// logic [31:0] PRDATA,
// logic [31:0] PWDATA,
// logic PREADY,
// logic PSLVERR
);
endmodule仿真波形

















