APB总线协议详解(附APB_SRAM RTL)

1 简介

APB2 :AMBA 2 APB,基本APB协议;
APB3 :AMBA 3 APB,比 APB2 多两个信号(PREADY , PSLVERR);
APB4 :AMBA 4 APB,比 APB3 多两个信号(PPROT , PSTRB );

APB(Advanced Peripheral Bus),高级外设总线。APB总线协议是ARM公司提出的AMBA总线结构之一,是一种片上总线结构。APB主要用于低带宽的周边外设之间的连接,例如UART、IIC等,它的总线架构不像AHB支持多个主模块,在APB里面没有仲裁器,APB 桥是AMBA APB中的唯一总线主机,另外APB桥也是AMBA中的一个从机。其特点:低带宽;高性能;非流水作业,至少需要两个时钟周期传输,且数据均在时钟上升沿变化;无需等待周期和回应信号;控制逻辑简单,只有四个控制信号,且APB上的传输可采用状态机表示

2. APB 协议

2.1 APB2 interface

SignalSource  Description
PCLK Clock sourceClock. The rising edge of PCLK times all transfers on the APB.
PRESETnSystem bus equivalentReset. The APB reset signal is active LOW. This signal is normally connected directly to the system bus reset signal.
PADDR APB bridgeAddress. This is the APB address bus. It can be up to 32 bits wide and is driven by the peripheral bus bridge unit.
PSELx APB bridgeSelect. The APB bridge unit generates this signal to each peripheral bus slave.It indicates that the slave device is selected and that a data transfer is required.There is a PSELx signal for each slave.
PENABLE APB bridgeEnable. This signal indicates the second and subsequent cycles of an APB transfer.
PWRITEAPB bridgeDirection. This signal indicates an APB write access when HIGH and an APB read access when LOW.
PWDATAAPB bridgeWrite data. This bus is driven by the peripheral bus bridge unit during write cycles when PWRITE is HIGH. This bus can be up to 32 bits wide.
PRDATA  lave interfaceRead Data. The selected slave drives this bus during read cycles when

2.2 APB2 Timing

2.1.1 APB2 写传输

  1. 在T1~T2阶段,所有总线处于IDLE状态。
  2. 在T2~T3阶段,第一个时钟周期,处在Setup phase状态。T2时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
  3. 在T3~T4阶段,第二个时钟周期,处在Access phase状态。此时PENABLE有效,地址、数据和控制信号在整个ENABLE周期保持有效。T3时刻,这个时候对应的Slave接收到Master发送过来的地址和写控制命令,此时Slave得知Master要准备发数据过来了,做好准备。
  4. T4时刻,采到PENABLE为低电平(除非当前传输之后紧接着下一次传输),表示Master在这一时刻之前一次写操作已经完成,Master回到IDLE状态,而Slave把数据取走。

注意:为了降低功耗地址信号和写信号将在传输后保持不变,直到下一个传输发生才改变。

2.1.2 APB2 读传输

  1. 在T1~T2阶段,所有总线处于IDLE状态。
  2. 在T2~T3阶段,第一个时钟周期,处在Setup phase状态。T2时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
  3. 在T3~T4阶段,第二个时钟周期,处在Access phase状态。T3时刻,此时PENABLE有效,这个时候对应的Slave接收到Master发送过来的地址和读控制命令,此时Slave得知自己要将这个地址反馈给Master了。
  4. T4时刻,采到PENABLE为低电平,表示Master在这一时刻之前一次读操作已经完成,Master回到IDLE状态。

2.3 APB3 interface

        在APB2的基础上增加:

Signal  Source Description
PREADYSlave interfaceReady. The slave uses this signal to extend an APB transfer.
PSLVERR Slave interface This signal indicates a transfer failure. APB peripherals are not required to support the PSLVERR pin. This is true for both existing and new APB peripheral designs. Where a peripheral does not include this pin then the appropriate input to the APB bridge is tied LOW.

2.4 APB3 Timing

2.4.1 APB3 无等待的写传输

     0. T1之前处于IDLE状态; 

  1. T1时刻上升沿:APB把PADDR,PWDATA准备好;拉高PSEL,拉高PWRITE(写),拉低PENABLE进入SETUP状态。
  2. T2时刻上升沿:拉高PENABLE,开始进入ACCESSS状态。
  3. T3时刻上升沿:PREADY=0,传输未完成,保持ACCESS状态;PREADY=1,slave已经接收到数据,master可拉低PENABLE,PSEL,进入IDLE状态。

2.4.2 APB3 有等待的写传输

  1. 在T0~T1阶段,所有总线处于IDLE状态。
  2. 在T1~T2阶段,第一个时钟周期,处在Setup phase状态。T1时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
  3. 在T2~T3阶段,第二个时钟周期,处在Access phase状态。T2时刻,这个时候对应的Slave接收到Master发送过来的地址和写控制命令,此时Slave得知Master要准备发数据过来了,做好准备。
  4. T3时刻,采到 PENABLE 为高电平,但是 PREADY 为低电平,表示Master数据还没准备好。
  5. T5时刻,采到 PENABLE & PREADY 为高电平,表示Master在这一时刻之前一次写操作已经完成,Master回到IDLE状态,而Slave把数据取走。
     

2.4.3 无等待的读传输

  1. 在T0~T1阶段,所有总线处于IDLE状态。
  2. 在T1~T2阶段,第一个时钟周期,处在Setup phase状态。T1时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
  3. 在T2~T3阶段,第二个时钟周期,处在Access phase状态。T2时刻,这个时候对应的Slave接收到Master发送过来的地址和读控制命令,此时Slave得知自己要将这个地址反馈给Master了。
  4. T3时刻,采到PENABLE & PREADY 为高电平,表示Master这一时刻之前一次读操作已经完成,Master回到IDLE状态。

2.4.4 有等待的读传输

  1. 在T0~T1阶段,所有总线处于IDLE状态。
  2. 在T1~T2阶段,第一个时钟周期,处在Setup phase状态。T1时刻,PADDR、PWRITE、PWDATA变化,PSEL拉高,即Master把这些数据发送到总线上。
  3.  在T2~T3阶段,第二个时钟周期,处在Access phase状态。T2时刻,这个时候对应的Slave接收到Master发送过来的地址和读控制命令,此时Slave得知自己要将这个地址反馈给Master了。
  4. T3时刻,采到 PENABLE 为高电平,但是 PREADY 为低电平,表示Slave数据还没准备好。
  5. T5时刻,采到 PENABLE & PREADY 为高电平,表示Master这一时刻之前一次读操作已经完成,Master回到IDLE状态。
     

2.4.5 有错误的写传输

 2.4.6 有错误的读传输

2.5 状态转化

从MASTER角度理解:

 从SLAVE角度理解:

 3. APB_SRAM RTL实现

首先进行模块划分:apb_sram.v;sram.v;tb.v。

3.1 sram.v 模块RTL实现

SignalSource  Description
clkinput系统时钟
rst_ninput 复位信号,低电平复位
en input 使能SRAM信号
we input 读写使能;1:写;0:读
addrinput 输入地址
dininput 输入写数据
doutoutput 读数据
//thise module define a ram ,depth = 32,width = 32bit
module sram
#(
    parameter DEPTH = 32,
    parameter WIDTH = 32,
    parameter ADDR_WIDTH  = $clog2(32*32)
)
(
    input   wire                    clk     ,//clock 
    input   wire                    rst_n   ,//reset
    input   wire                    en      ,//enable sram
    input   wire                    we      ,//1:write;0:read
    input   wire    [ADDR_WIDTH-1:0]addr    ,//address
    input   wire    [WIDTH-1:0]     din     ,//write data

    output  reg     [WIDTH-1:0]     dout     //read data
);

integer i;

reg [WIDTH-1:0] mem [0:DEPTH-1];

always@(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin             //initialize sram
        for(i=0;i<(DEPTH-1);i=i+1)begin 
            mem[i] <= 'd0;
        end 
    end else if(en)begin        //enable sram
        if(we)
            mem[addr] <= din;   //write data
        else 
            dout <= mem[addr];  //read data 
    end 
end 

endmodule 

3.2 apb_sram.v 模块RTL实现 

SignalSource  Description
pclkinput系统时钟
prstninput复位信号,低电平复位
pselinput片选信号
penableinput使能信号
pwriteinput1:写;0:读
paddrinput地址
pwdatainput写数据
preadyoutput响应
prdataoutput读数据
//spb_sram slave module;a control module between bridge and sram
module apb_sram
(
    //from bridge
    input   wire            pclk    ,
    input   wire            prstn   ,
    input   wire            psel    ,
    input   wire            penable ,
    input   wire            pwrite  ,
    input   wire    [9:0]   paddr   ,
    input   wire    [31:0]  pwdata  ,
    //to bridge 
    output  wire            pready  ,
    output  wire    [31:0]  prdata
);
//state define
parameter   IDLE    =   3'b001;
parameter   SETUP   =   3'b010;
parameter   ACCESS  =   3'b100;

reg [2:0]   curr_state;
reg [2:0]   next_state;

//---- FSM_1:state transfer ----/
always@(posedge pclk or negedge prstn)begin 
    if(!prstn)begin 
        curr_state <= IDLE ;
    end else begin 
        curr_state <= next_state;
    end 
end 
//---- FSM_2:state transfer condition ----//
always@(*)begin 
    if(!prstn)begin 
        next_state <= IDLE;
    end else begin 
        case(curr_state)
            IDLE:begin 
                if(psel && !penable)begin 
                    next_state = SETUP;
                end else begin 
                    next_state = IDLE;
                end 
            end 
            SETUP:begin 
                next_state = ACCESS;
            end 
            ACCESS:begin 
                if(!psel && !penable)begin 
                    next_state = IDLE;
                end else if(psel && !penable)begin
                    next_state = SETUP;
                end else begin 
                    next_state = ACCESS;
                end 
            end 
            default:next_state = IDLE;
        endcase
    end 
end 

//---- FSM3:output logic 
wire            mem_en  ;
wire            mem_we  ;
wire    [9:0]   apb_addr;
wire    [31:0]  apb_wdata;

assign mem_en   =   psel && !penable;
assign mem_we   =   psel ? pwrite:mem_we;
assign apb_addr =   (next_state == SETUP) ? paddr[9:2] : apb_addr;
assign apb_wdata=   (next_state == SETUP) ? pwdata : apb_wdata;
assign pready   =   penable;


sram
#(
    .depth (32),
    .width (32)
)
U0_sram
(
   .clk     (pclk       ),//clock 
   .rst_n   (prstn      ),//reset
   .en      (mem_en     ),//enable sram
   .we      (mem_we     ),//1:write;0:read
   .addr    (apb_addr   ),//address
   .din     (apb_wdata  ),//write data

   .dout    (prdata     )//read data
);

endmodule 

3.3 Testbench

`timescale 1ns/1ps

module tb();

reg         pclk    ;
reg         prstn   ;
reg         psel    ;
reg         penable ;
reg         pwrite  ;
reg [9:0]   paddr   ;
reg [31:0]  pwdata  ;

wire        pready  ;
wire[31:0]  prdata  ;

//---- apb_write_task ----//
task apb_write;
input   [31:0]  addr;
input   [31:0]  data;
begin 
    @(posedge pclk);
    paddr   <=  #1 addr;
    psel    <=  #1 1'b1;
    pwrite  <=  #1 1'b1;
    pwdata  <=  #1 data;
    @(posedge pclk);
    penable <= #1 1'b1;
    @(posedge pclk);
    psel    <=  #1 1'b0;
    penable <=  #1 1'b0;
end 
endtask
//---- apb_read_task ----//
task apb_read;
input   [31:0]  addr;
begin 
    @(posedge pclk);
    paddr   <=  #1 addr;
    psel    <=  #1 1'b1;
    pwrite  <=  #1 1'b0;
    @(posedge pclk);
    penable <=  #1 1'b1;
    @(posedge pclk);
    psel    <=  #1 1'b0;
    penable <=  #1 1'b0;
end 
endtask

//---- initial signle ----//
integer i,j,k;
reg [31:0]  wdata_random;

initial begin 
    pclk    = 1'b0;
    prstn   = 1'b1;
    psel    = 1'b0;
    penable = 1'b0;
    pwrite  = 1'b0;
    paddr   = 32'b0;
    pwdata  = 32'b0;
    repeat(3) @(posedge pclk);
    prstn   = 1'b0;
    repeat(5) @(posedge pclk);
    prstn   = 1'b1;
    
    $display("------------------------------------");
    $display("-------------- write ---------------");
    for(i=0;i<=31;i=i+1)begin
        wdata_random = $random;
        apb_write(i*4,wdata_random);
        $display("addr = %h,    wdata = %h",i*4,wdata_random);
    end 
    $display("------------------------------------\n");

    $display("------------------------------------");
    $display("--------------- read ---------------");
    for(j=0;j<=31;j=j+1)begin 
        apb_read(j*4);
        $display("addr = %h,    rdata = %h",j*4,prdata);
    end 
    $display("-------------------------------------\n");

    $display("-------------------------------------");
    $display("-------- writing and reading --------");
    for(k=0;k<=31;k=k+1)begin 
        wdata_random = $random;
        apb_write(k*4,wdata_random);
        apb_read(k*4);
        $display("write data is %h, read data is %h",wdata_random,prdata);
    end 
    $display("-------------------------------------");

    repeat(10)@(posedge pclk);
    $finish();

end 

//---- define clock -----//
always begin 
    #10 pclk = ~pclk; //pclk cycle is 20ns 
end 

//---- generate wave -----//
initial begin 
    $fsdbDumpfile("tb.fsdb");
    $fsdbDumpvars(0);
    $fsdbDumpMDA();//add to see memory
end 

apb_sram    U0_apb_sram
(  
   .pclk    (pclk   ),
   .prstn   (prstn  ),
   .psel    (psel   ),
   .penable (penable),
   .pwrite  (pwrite ),
   .paddr   (paddr  ),
   .pwdata  (pwdata ),
   
   .pready  (pready ),
   .prdata  (prdata )
);

endmodule 

3.4 Makefile

Makefile脚本例程

4. 仿真结果

写sram部分:

读sram部分:

边写边读:

 

 

 

  • 2
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值