APB Slave设计

发布时间 2024-01-09 09:57:18作者: Icer_Newer

APB Slave位置

  • 实现通过CPU对于APB Slave读写模块进行读写操作

规格说明

  • 不支持反压,即它反馈给APB的pready信号始终为1
  • 不支持错误传输,就是说他反馈给APB总线的PSLVERR始终是为0的
  • 支持4个可读写的寄存器
  • 支持12个只读寄存器
  • 支持字节选通信号,根据字节选通信号进行操作数据

接口

寄存器表

  • PID3寄存器的[7:4]位就是输入的版本控制信号

寄存器电路

架构图

  • interface模块就是将APB的信号转变为slave的控制信号(读写使能信号,地址信号,写数据,读数据,写选通信号)

RTL

apb_interface

module apb_slave_if
#(
    parameter ADDRWIDTH=12
)
(
    input       wire                    pclk    ,
    input       wire                    preset  ,
    

    // input apb control signal
    input       wire                    psel    ,
    input       wire    [ADDRWIDTH-1:0] paddr   ,
    input       wire                    penable ,
    input       wire                    pwrite  ,
    input       wire    [31:0]          pwdata  ,
    input       wire    [3:0]           pstrb   ,
            
    input       wire    [31:0]          rdata   ,
    input       wire    [3:0]           ecorevnum,

    // apb outputs
    output      wire    [31:0]          prdata  ,
    output      wire                    pready  ,
    output      wire                    pslverr ,

    // output signals to apb slave
    output      wire    [ADDRWIDTH-1:0] addr    ,
    output      wire                    read_en ,
    output      wire                    write_en,
    output      wire    [31:0]          wdata   ,
    output      wire    [3:0]           byte_strobe,
    output      wire    [3:0]           ecorevnum_pid3
);

    assign pready = 1'b1;
    assign pslverr = 1'b0;

    assign addr = paddr;

    assign read_en = psel && (~pwrite);
    assign write_en = psel && pwrite && (~penable);
    assign byte_strobe = pstrb;
    assign wdata = pwdata;
    assign prdata = rdata;
    assign  ecorevnum_pid3  =ecorevnum;
endmodule

apb_slave

module apb_slave
#(
    parameter ADDRWIDTH = 12
)
(
    input   wire                        pclk        ,
    input   wire                        preset      ,
    input   wire    [ADDRWIDTH-1:0]     addr        ,
    input   wire    [31:0]              wdata       ,
    input   wire                        read_en     ,
    input   wire                        write_en    ,
    input   wire    [3:0]               byte_strobe ,
    input   wire    [3:0]               ecorevnum_pid3   ,

    // output signals
    output  reg    [31:0]              rdata       
);

    // 定义只读寄存器内容
    localparam ARM_CHSDK_APB4_EG_SLAVE_PID4 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_PID5 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_PID6 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_PID7 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_PID0 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_PID1 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_PID2 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_PID3 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_CID0 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_CID1 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_CID2 = 32'h0000_0004;
    localparam ARM_CHSDK_APB4_EG_SLAVE_CID3 = 32'h0000_0004;


    // 定义读写寄存器
    reg [31:0]  data0;
    reg [31:0]  data1;
    reg [31:0]  data2;
    reg [31:0]  data3;

    wire [3:0] wr_sel;

    // 通过addr[2:3]bit选择data寄存器
    assign wr_sel[0] = ((addr[ADDRWIDTH-1:2]==10'b0000_0000_00 &&(write_en)) ? 1'b1 : 1'b0);
    assign wr_sel[1] = ((addr[ADDRWIDTH-1:2]==10'b0000_0000_01 &&(write_en)) ? 1'b1 : 1'b0);
    assign wr_sel[2] = ((addr[ADDRWIDTH-1:2]==10'b0000_0000_10 &&(write_en)) ? 1'b1 : 1'b0);
    assign wr_sel[3] = ((addr[ADDRWIDTH-1:2]==10'b0000_0000_11 &&(write_en)) ? 1'b1 : 1'b0);

    // register wirte
    always @(posedge pclk or negedge preset) begin
        if(~preset)
            data0 <= 32'b0;
        else if(wr_sel[0]) begin
            // according to byte_strobe write the data0 register
            if(byte_strobe[0])
                data0[7:0] <= wdata[7:0];
            else if(byte_strobe[1])
                data0[15:8] <= wdata[15:8];
            else if(byte_strobe[2])
                data0[23:16] <= wdata[23:16];
            else if(byte_strobe[3])
                data0[31:24] <= wdata[31:24];
            else   
                data0 <= 32'b0; 
        end
    end


    always @(posedge pclk or negedge preset) begin
        if(~preset)
            data1 <= 32'b0;
        else if(wr_sel[0]) begin
            // according to byte_strobe write the data0 register
            if(byte_strobe[0])
                data1[7:0] <= wdata[7:0];
            else if(byte_strobe[1])
                data1[15:8] <= wdata[15:8];
            else if(byte_strobe[2])
                data1[23:16] <= wdata[23:16];
            else if(byte_strobe[3])
                data1[31:24] <= wdata[31:24];
            else   
                data1 <= 32'b0; 
        end
    end


    always @(posedge pclk or negedge preset) begin
        if(~preset)
            data2 <= 32'b0;
        else if(wr_sel[0]) begin
            // according to byte_strobe write the data0 register
            if(byte_strobe[0])
                data2[7:0] <= wdata[7:0];
            else if(byte_strobe[1])
                data2[15:8] <= wdata[15:8];
            else if(byte_strobe[2])
                data2[23:16] <= wdata[23:16];
            else if(byte_strobe[3])
                data2[31:24] <= wdata[31:24];
            else   
                data2 <= 32'b0; 
        end
    end


    always @(posedge pclk or negedge preset) begin
        if(~preset)
            data3 <= 32'b0;
        else if(wr_sel[0]) begin
            // according to byte_strobe write the data0 register
            if(byte_strobe[0])
                data3[7:0] <= wdata[7:0];
            else if(byte_strobe[1])
                data3[15:8] <= wdata[15:8];
            else if(byte_strobe[2])
                data3[23:16] <= wdata[23:16];
            else if(byte_strobe[3])
                data3[31:24] <= wdata[31:24];
            else   
                data3 <= 32'b0; 
        end
    end


    // register read
    always @(*) begin
      case (read_en)
      1'b1:
            begin
                // 读取RW寄存器的值,通过高addr[2:3]进行寻址,高位都为0
                if(addr[11:4]==8'b0) begin
                    case (addr[3:2])
                        2'b00 : rdata = data0;
                        2'b01 : rdata = data1;
                        2'b10 : rdata = data2;
                        2'b11 : rdata = data3;
                        default:rdata = 32'b0;
                    endcase
                end
                else if(addr[11:6] == 6'h3f) begin
                    case(addr[5:2])
                        4'b0100:rdata = ARM_CHSDK_APB4_EG_SLAVE_PID4;
                        4'b0101:rdata = ARM_CHSDK_APB4_EG_SLAVE_PID5;
                        4'b0110:rdata = ARM_CHSDK_APB4_EG_SLAVE_PID6;
                        4'b0111:rdata = ARM_CHSDK_APB4_EG_SLAVE_PID7;
                        4'b1000:rdata = ARM_CHSDK_APB4_EG_SLAVE_PID0;
                        4'b1001:rdata = ARM_CHSDK_APB4_EG_SLAVE_PID1;
                        4'b1010:rdata = ARM_CHSDK_APB4_EG_SLAVE_PID2;
                        4'b1011:rdata = {ARM_CHSDK_APB4_EG_SLAVE_PID3[31:8],
                                                ecorevnum_pid3[3:0],4'h0};
                        4'b1100:rdata = ARM_CHSDK_APB4_EG_SLAVE_CID0;
                        4'b1101:rdata = ARM_CHSDK_APB4_EG_SLAVE_CID1;
                        4'b1110:rdata = ARM_CHSDK_APB4_EG_SLAVE_CID2;
                        4'b1111:rdata = ARM_CHSDK_APB4_EG_SLAVE_CID3;
                        default:rdata = 32'bx;
                    endcase 
                end
                else    
                    rdata = 32'b0;
            end 
      1'b0:
        begin
          rdata = 32'b0;
        end
      default:rdata=32'bx;
      endcase
    end


endmodule