APB(Advanced Peripheral Bus)是AMBA总线体系的一部分。相较于AMBA总线体系中的其他总线,APB总线具有低功耗,低复杂度的特征。APB总线主要应用于对性能要求不太高的低带宽外设接口。

本文所讲述的是AMBA4中的APB协议。其信号如下:

amba总线什么时候返回error response_数据


其中,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信号各个位的含义

amba总线什么时候返回error response_sed_02

Write transfers

With no wait states

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

amba总线什么时候返回error response_数字IC设计_03

With wait states

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

amba总线什么时候返回error response_数字IC设计_04


从有等待写传输和无等待写传输的时序中,我们可以看出,Access Phase只有在PSEL、PENABLE和PREADY信号同时为高时,才会发生,否则需要等待。

Read transfers

With no wait states

与无等待的写传输唯一不同的地方,就是在下图中,PWRITE信号是0,表示读数据。

amba总线什么时候返回error response_sed_05

With wait states

amba总线什么时候返回error response_hdl_06

APB总线的状态机

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

amba总线什么时候返回error response_数字IC设计_07

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;
endmodule

master

`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

仿真波形

amba总线什么时候返回error response_sed_08