AHB2APB设计

AHB2APB Bridge位置

  • AHB子系统时钟在200Mhz左右,APB时钟在几十Khz到几十Mhz
  • 所以要进行跨时钟域处理,从AHB高时钟频率转到APB低时钟频率

AHB2APB Bridge规格说明

  • Bridge是APB总线上唯一的主机(也可以通过设计使APB支持多个Master)

AHB2APB Bridge接口

  • Bridge是连接AHB总线和APB总线的桥梁,所以接口有AHB总线和APB总线
  • Bridge是APB总线的Master,是AHA的Slave
  • psel - 有多少个外设就有多少个psel信号
  • penable - 时钟选通信号

AHB2APB Bridge状态机

  • Bridge开始的时候处于IDLE状态,当Bridge收到AHB总线的传输信号之后,进入到setup状态,在setup状态将AHB控制和地址信号进行锁存并将psel置于1,进入到enable状态,可以进行apb的读写操作

AHB2APB Bridge读时序

AHB2APB Bridge 写时序

AHB2APB Bridge设计

设计规格

  • 对于输入输出数据进行寄存或者不寄存,由模块控制,主要是为了时序

接口信号

  • APBACTIVE - APB激活信号

状态机1:输入输出不寄存

状态机2:输入输出数据寄存

状态机:发生传输错误

RTL

module ahb_to_apb_bridge
#(
    parameter ADDRWIDTH = 16    ,
    parameter REGISTER_RDATA = 1,
    parameter REGISTER_WDATA = 0
)
(
    input   wire                    hclk,
    input   wire                    hresetn,
    input   wire                    pclken,

    input   wire                    hsel,
    input   wire    [ADDRWIDTH-1:0] haddr,
    input   wire    [1:0]           htrans,
    input   wire    [2:0]           hsize,
    input   wire    [4:0]           hprot,
    input   wire                    hwrite,
    input   wire                    hready,
    input   wire    [31:0]          hwdata,

    output  reg                     hreadyout,
    output  wire    [31:0]          hrdata,
    output  wire                    hresp,

    output  wire    [ADDRWIDTH-1:0] paddr,
    output  wire                    penable,
    output  wire                    pwrite,
    output  wire    [3:0]           pstrb,
    output  wire    [2:0]           pprot,
    output  wire    [31:0]          pwdata,
    output  wire                    psel,

    output wire                     apbactive,

    input   wire    [31:0]          prdata,
    input   wire                    pready,
    input   wire                    pslverr   
);

    // 寄存写信号和写地址
    reg [ADDRWIDTH-1:0] addr_reg;
    reg [2:0]           wr_reg;
    reg [31:0]          rwdata_reg;

    // 定义当前状态变量和下一状态变量
    reg [2:0]           state_reg;
    reg [2:0]           next_state;

    reg [3:0]           pstrb_reg;
    wire [3:0]          pstrb_nxt;
    
    reg [1:0]           pprot_reg;
    wire [1:0]           pprot_nxt;

    // apb bridge选择信号
    wire                apb_select;
    
    // 传输完成信号
    wire                apb_tran_end;

    // 判断数据是否寄存的变量
    wire                reg_rdata_cfg;
    wire                reg_wdata_cfg;

    // 定义写控制信号寄存的寄存器
    reg                 sample_wdata_reg;

    localparam ST_BITS=3;

    localparam  [ST_BITS-1:0]   ST_IDLE             =3'b000;
    localparam  [ST_BITS-1:0]   ST_APB_WAIT         =3'b001;
    localparam  [ST_BITS-1:0]   ST_APB_TRNF         =3'b010;     
    localparam  [ST_BITS-1:0]   ST_APB_TRNF2        =3'b011;     
    localparam  [ST_BITS-1:0]   ST_APB_NODOK        =3'b100;
    localparam  [ST_BITS-1:0]   ST_APB_ERR1         =3'b101;
    localparam  [ST_BITS-1:0]   ST_APB_ERR2         =3'b110;
    localparam  [ST_BITS-1:0]   ST_APB_ILLEGAL      =3'b111;
    

    // main code

    // 产生读写数据是否寄存的信号
    assign reg_rdata_cfg = REGISTER_RDATA == 0? 1'b0  : 1'b1;
    assign reg_rdata_cfg = REGISTER_WDATA == 0? 1'b0  : 1'b1;
    
    // 产生bridge被选中的信号
    assign apb_select = hsel && htrans[1] && hready;

    // apb传输完成信号
    assign apb_tran_end = (state_reg == 3'b011) & pready;

    //pprot信号产生
    assign pprot_nxt[0] = hprot[1];
    assign pprot_nxt[1] = ~hprot[0];

    // pstrb信号产生
    assign pstrb_nxt[0] = hwrite & ((hsize[1]) |(hsize[0] & (~haddr[1])) | (haddr[1:0]==2'b00));
    assign pstrb_nxt[1] = hwrite & ((hsize[1]) |(hsize[0] & (~haddr[1])) | (haddr[1:0]==2'b01));
    assign pstrb_nxt[2] = hwrite & ((hsize[1]) |(hsize[0] & haddr[1]) | (haddr[1:0]==2'b10));
    assign pstrb_nxt[3] = hwrite & ((hsize[1]) |(hsize[0] & haddr[1]) | (haddr[1:0]==2'b11));


    // sample control signals 打拍信号
    // data和addr对齐
    always @(posedge hclk or negedge hresetn) begin
        if(!hresetn) begin
            addr_reg <= {ADDRWIDTH-2{1'b0}};
            wr_reg  <=  1'b0;
            pprot_reg <= 2'b0;
            pstrb_reg <= 4'b0;
        end 
        else if(apb_select) begin
            addr_reg <= haddr[ADDRWIDTH-1:2];
            wr_reg  <=  hwrite;
            pprot_reg <= pprot_nxt;
            pstrb_reg <= pstrb_nxt;
        end
    end

    // 采样写数据的控制信号
    wire sample_wdata_set = apb_select & hwrite & reg_wdata_cfg;
    wire sample_wdata_clt = sample_wdata_set & pclken;

    always @ (posedge hclk or negedge hresetn) begin
        if(!hresetn) begin
            sample_wdata_reg <= 1'b0;
        end
        else if(sample_wdata_set | sample_wdata_clt) begin
            sample_wdata_reg <= sample_wdata_set;
        end
    end

    // 第一段状态机
    always @ (posedge hclk or negedge hresetn) begin
        if(!hresetn) begin
            state_reg <= 3'b000;
        end
        else
            state_reg <= next_state;
    end

    // 第二段状态机描述状态转移
    always @ (*) begin
        case(state_reg)
            ST_IDLE:
            begin
                if(apb_select & pclken & ~(reg_wdata_cfg&hwrite)) begin
                    next_state = ST_APB_TRNF;
                end
                else if(apb_select)
                    next_state = ST_APB_WAIT;
                else
                    next_state = ST_IDLE;
            end
            ST_APB_WAIT:
            begin
                if(pclken) 
                    next_state = ST_APB_TRNF;
                else    
                    next_state = ST_IDLE;
            end
            ST_APB_TRNF:
            begin
                if(pclken)
                    next_state = ST_APB_TRNF2;
                else 
                    next_state = ST_APB_TRNF;
            end
            ST_APB_TRNF2:
            begin
                if(pready & pslverr & pclken) 
                    next_state = ST_APB_ERR1;
                else if(pready & (~pslverr)&pclken)
                begin
                    if(reg_rdata_cfg)
                        next_state = ST_APB_NODOK;
                    else
                        next_state = ST_APB_TRNF2;                
                end
            end
            ST_APB_NODOK:
            begin
                if(apb_select & pclken & ~(reg_wdata_cfg&hwrite)) begin
                    next_state = ST_APB_TRNF;
                end
                else if(apb_select)
                    next_state = ST_APB_WAIT;
                else
                    next_state = ST_IDLE;
            end
            ST_APB_ERR1:
                next_state = ST_APB_ERR2;
            ST_APB_ERR2:
                if(apb_select & pclken & ~(reg_wdata_cfg&hwrite)) begin
                    next_state = ST_APB_TRNF;
                end
                else if(apb_select)
                    next_state = ST_APB_WAIT;
                else
                    next_state = ST_IDLE; 
            default : next_state = 3'bxxx;
        endcase
    end


    // 采样数据
    always @ (posedge hclk or negedge hresetn) begin
        if(!hresetn)
            rwdata_reg = 32'b0;
        else if(sample_wdata_reg & reg_wdata_cfg & pclken)
            rwdata_reg <= hwdata;
        else if(apb_tran_end & reg_rdata_cfg & pclken)
            rwdata_reg <= prdata;
    end

    // 产生输出信号
    assign paddr = {addr_reg,2'b00};
    assign  pwrite = wr_reg;
    assign pwdata = reg_wdata_cfg ? rwdata_reg : hwdata;
    assign psel = (state_reg == ST_APB_TRNF | state_reg == ST_APB_TRNF2);
    assign penable = (state_reg == ST_APB_TRNF2);
    assign pprot = {pprot_reg[1],1'b0,pprot_reg[0]};
    assign pstrb = pstrb_reg[3:0];

    //产生hready_out
    always @(*) begin
        case(state_reg)
            ST_IDLE:hreadyout = 1'b1;
            ST_APB_WAIT:hreadyout=1'b0;
            ST_APB_TRNF:hreadyout=1'b0;
            ST_APB_TRNF2:hreadyout=(~reg_rdata_cfg) & pready & (~pslverr)&pclken;
            ST_APB_NODOK:hreadyout = 1'b0;
            ST_APB_ERR1:hreadyout = 1'b0;
            ST_APB_ERR1:hreadyout = 1'b1;
            default:hreadyout=1'bx;
        endcase   
    end

    assign hrdata = reg_rdata_cfg ? rwdata_reg : prdata;
    assign hresp = (state_reg == ST_APB_ERR1) |(state_reg == ST_APB_ERR2);
    assign apbactive = (hsel & htrans[1]) | state_reg;

endmodule
posted @ 2024-01-10 09:41  Icer_Newer  阅读(397)  评论(0编辑  收藏  举报