APB协议及APB_Slave设计

一、APB协议

原文:

翻译:

APB协议是一个低成本的接口,经过了优化,降低了功耗和接口复杂性。APB接口是简单同步无流水线的协议。每次传输花费至少两个周期完成。

APB接口设计是为了访问外围设备中的可编程控制寄存器。APB外设通常使用APB桥连接到内存系统。例如,AXI2APB桥可以用来连接一些APB外设到AXI内存系统。

APB传输是由APB桥发起。APB桥可以被认为是请求者。外设接口对于请求者响应。APB外设可以被认为是完成者。协议规范将需要请求者和完成者。

 二、APB接口信号

signalsourcewidthdescription
PCLKclock1PCLK is a clock signal. All APB signals are
timed against the rising edge of PCLK
PRSETnsystem bus reset1

PRESETn is the reset signal and is active-LOW

PRESETn is normally connected directly to the
system bus reset signal

PADDRrequesterADDR_WIDTH

PADDR is the APB address bus.

PADDR can be up to 32 bits wide

PSELxrequester1The Requester generates a PSELx signal for each Completer. PSELx indicates that the Completer is selected and that a data transfer is required
PENABLErequester1PENABLE indicates the second and subsequent
cycles of an APB transfer
PWRITErequester1PWRITE indicates an APB write access when
HIGH and an APB read access when LOW
PWDATArequesterDATA_WIDTHThe PWDATA write data bus is driven by the
APB bridge Requester during write cycles when
PWRITE is HIGH.
PWDATA can be 8, 16, or 32 bits wide
PRDATAcompleterDATA_WIDTHThe PRDATA read data bus is driven by the
selected Completer during read cycles when
PWRITE is LOW.
PRDATA can be 8, 16, or 32 bits wide
PREADYcompleter1PREADY is used to extend an APB transfer by
the Completer
PSLVERRcompleter1PSLVERR is an optional signal that can be
asserted HIGH by the Completer to indicate an
error condition on an APB transfer
PPROTrequester3PPROT indicates the normal, privileged, or
secure protection level of the transaction and
whether the transaction is a data access or an
instruction access
PSTRBrequesterDATA_WIDTH/8

PSTRB indicates which byte lanes to update
during a write transfer. There is one write strobe
for each 8 bits of the write data bus.

PSTRB[n] corresponds to PWDATA[(8n + 7):(8n)].
PSTRB must not be active during a read transfer.

有些文章也将requester,completer说成master,slaver,意思是一样的。

  • APB2 :AMBA 2 APB
  • APB3 :AMBA 3 APB,比APB2多两个信号(PREADY,PSLVERR)
  • APB4 :AMBA 4 APB,比APB3多两个信号(PPROT,PSTRB)

特别说明:

写传输时,如果收到了错误信息,并不意味着外设中的寄存器没有被更新。

读传输时,如果收到了错误信号,数据是无效的。对于读到错误信号,不需要外设驱动数据总线置0。收到错误信号的主机仍然可以使用数据,从机不能依赖错误信号阻止对PRDATA的读取。

PPROT[2:0]保护等级
[0]

1:私有传输

0:一般传输

[1]

1:不安全传输

0:安全传输

[2]

1:指令传输

0:数据传输

PSTRB 就是判断哪个字节有效的信号,手册上很专业的称为“稀疏数据传输” 。

三、传输

1、写传输无等待

2、写传输有等待

3、读传输无等待

4、读传输有等待

5、带有错误信号的写传输

6、带有错误信号的读传输

 平时几乎用到的都是APB3,很少用到PPROT和PSTRB。具体情况具体分析吧

四、apb_slave实现

1、代码如下:

module apb_slave(
    input wire pclk,
    input wire presetn,
    input wire pwrite,
    input wire psel,
    input wire penable,
    input wire [31:0] paddr,
    input wire [31:0] pwdata,

    output reg [31:0] prdata,
    output wire pready
    );

    parameter REG1_ADDR = 8'h00;
    parameter REG2_ADDR = 8'h04;
    parameter REG3_ADDR = 8'h08;

    reg [31:0] reg1;
    reg [31:0] reg2;
    reg [31:0] reg3;
    reg [31:0] invld_reg;

    wire apb_write_vld;
    wire apb_read_vld;

    assign pready = 1'b1;

    assign apb_write_vld = pwrite && psel && penable;
    assign apb_read_vld = (!pwrite) && psel && penable;

    always@(posedge pclk or negedge presetn)begin
        if(!presetn)begin
            reg1 <= 32'd0;
            reg2 <= 32'd0;
            reg3 <= 32'd0;
        end
        else if(apb_write_vld)begin
            case(paddr[7:0])
                REG1_ADDR : reg1 <= pwdata;
                REG2_ADDR : reg2 <= pwdata;
                REG3_ADDR : reg3 <= pwdata;
                default : invld_reg <= pwdata;
            endcase
        end
    end

    always@(*)begin
        if(apb_read_vld)begin
            case(paddr[7:0])
                REG1_ADDR : prdata <= reg1;
                REG2_ADDR : prdata <= reg2;
                REG3_ADDR : prdata <= reg3;
                default : prdata <= invld_reg;
            endcase
        end
        else
            prdata <= 32'd0;
    end
endmodule

2、testbench如下

`timescale 1ns/1ns;
module apb_slave_tb();
    reg pclk;
    reg presetn;
    reg pwrite;
    reg psel;
    reg penable;
    reg [31:0] paddr;
    reg [31:0] pwdata;

    wire pready;
    wire [31:0] prdata;

    reg [31:0] rdata;

    parameter REG1_ADDR = 8'h00;
    parameter REG2_ADDR = 8'h04;
    parameter REG3_ADDR = 8'h08;

    always #10 pclk = ~pclk;

    initial begin
        pclk = 1'b0;
        presetn <= 1'b0;
        pwrite <= 1'b0;
        psel <= 1'b0;
        penable <= 1'b0;
        paddr <= 32'd0;
        pwdata <= 32'd0;
        #123;
        presetn <= 1'b1;
        
        apb_write(REG1_ADDR,32'h33445566);
        apb_read(REG1_ADDR,rdata);
        #66;
        apb_write(REG2_ADDR,32'haabbccdd);
        apb_read(REG2_ADDR,rdata);
        #66;
        apb_write(REG3_ADDR,32'ha1b2c3d4);
        apb_read(REG3_ADDR,rdata);
        #1000;
        $finish;
    end

    task apb_write(input [7:0] addr,input [31:0] wdata);
        begin
            @(posedge pclk);
            
            pwrite <= 1'b1;
            psel <= 1'b1;
            penable <= 1'b0;
            paddr <= {24'd0,addr};
            pwdata <= wdata;

            @(posedge pclk);
            penable <= 1'b1;

            @(posedge pclk);
            pwrite <= 1'b0;
            psel <= 1'b0;
            penable <= 1'b0;
            paddr <= 32'd0;
            pwdata <= 32'd0;

            @(posedge pclk);
        end
    endtask

    task apb_read(input [7:0] addr,output [31:0] rdata);
        begin
            @(posedge pclk);
            pwrite <= 1'b0;
            psel <= 1'b1;
            penable <= 1'b0;
            paddr <= {24'd0,addr};

            @(posedge pclk);
            penable <= 1'b1;

            @(posedge pclk);
            rdata <= prdata;
            psel <= 1'b0;
            paddr <= 32'd0;

            @(posedge pclk);
        end
    endtask

apb_slave apb_slave_inst(
    .pclk           (pclk),
    .presetn        (presetn),
    .pwrite         (pwrite),
    .psel           (psel),
    .penable        (penable),
    .paddr          (paddr),
    .pwdata         (pwdata),

    .prdata         (prdata),
    .pready         (pready)
);

    initial begin
        $fsdbDumpfile("tb.fsdb");
        $fsdbDumpvars;
    end
endmodule

这里需要注意,时钟阻塞赋值,其他信号非阻塞赋值,这样才能保证时钟沿采样到的信号为上一刻的值。与设计思路相符合。

3、仿真结果

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值