axi lite slave操作寄存器的接口转换代码分享(verilog实现)

  • 代码实现的功能是将axi lite从机接口转换为可以操作寄存器的接口,代码不复杂,便不进行过多说明了,有兴趣的同学可以参考。
module axilite_to_regs #
(
    parameter   integer     C_S_AXI_DATA_WIDTH  =   32                          ,
    parameter   integer     C_S_AXI_ADDR_WIDTH  =   5                           ,
    /* 依据地址线的宽度计算寄存器的总数 */
    localparam  integer     REG_COUNT           =   power(2, C_S_AXI_ADDR_WIDTH)/ 
                                                    (C_S_AXI_DATA_WIDTH / 8) 
)(
    /* 时钟 复位 */
    input       wire                                        S_AXI_ACLK          ,
    input       wire                                        S_AXI_ARESETN       ,

    /* 源接口(axi lite 接口) */
    input       wire    [C_S_AXI_ADDR_WIDTH-1       : 0]    S_AXI_AWADDR        ,
    input       wire    [2                          : 0]    S_AXI_AWPROT        ,
    input       wire                                        S_AXI_AWVALID       ,
    output      wire                                        S_AXI_AWREADY       ,
    input       wire    [C_S_AXI_DATA_WIDTH-1       : 0]    S_AXI_WDATA         ,
    input       wire    [(C_S_AXI_DATA_WIDTH/8)-1   : 0]    S_AXI_WSTRB         ,
    input       wire                                        S_AXI_WVALID        ,
    output      wire                                        S_AXI_WREADY        ,
    output      wire    [1                          : 0]    S_AXI_BRESP         ,
    output      wire                                        S_AXI_BVALID        ,
    input       wire                                        S_AXI_BREADY        ,
    input       wire    [C_S_AXI_ADDR_WIDTH-1       : 0]    S_AXI_ARADDR        ,
    input       wire    [2                          : 0]    S_AXI_ARPROT        ,
    input       wire                                        S_AXI_ARVALID       ,
    output      wire                                        S_AXI_ARREADY       ,
    output      wire    [C_S_AXI_DATA_WIDTH-1       : 0]    S_AXI_RDATA         ,
    output      wire    [1                          : 0]    S_AXI_RRESP         ,
    output      wire                                        S_AXI_RVALID        ,
    input       wire                                        S_AXI_RREADY        ,

    /* 目标接口(寄存器接口) */
    output      wire    [C_S_AXI_DATA_WIDTH-1       : 0]    data_write          ,
    input       wire    [C_S_AXI_DATA_WIDTH-1       : 0]    data_read           ,
    output      wire    [REG_COUNT-1                : 0]    reg_write_valid     ,
    input       wire    [REG_COUNT-1                : 0]    reg_write_ready     ,
    output      wire    [REG_COUNT-1                : 0]    reg_read_valid      ,
    input       wire    [REG_COUNT-1                : 0]    reg_read_ready
);

/* 指数计算函数 */
function integer power (input integer base, input integer exponent);
        integer result, i;
        begin
            result = 1;
            for (i = 0; i < exponent; i = i + 1) begin
                result = result * base;
            end
            power = result;
        end
endfunction

    
/* 计算数据的位宽 */
function integer clogb2 (input integer bit_depth);
    begin
        for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
            bit_depth = bit_depth >> 1;
    end
endfunction

localparam  integer ADDR_LSB            =   (C_S_AXI_DATA_WIDTH/32) + 1         ;
localparam  integer OPT_MEM_ADDR_BITS   =   C_S_AXI_ADDR_WIDTH - ADDR_LSB - 1   ;


/* axi lite 输出信号的寄存器定义 */
reg                                                 axi_awready         ;
reg                                                 axi_wready          ;
reg                 [1                    : 0]      axi_bresp           ;
reg                                                 axi_bvalid          ;
reg                                                 axi_arready         ;
reg                 [C_S_AXI_DATA_WIDTH-1 : 0]      axi_rdata           ;
reg                 [1                    : 0]      axi_rresp           ;
reg                                                 axi_rvalid          ;
/* 寄存器接口 输出信号的寄存器定义 */
reg                 [C_S_AXI_DATA_WIDTH-1 : 0]      r_data_write        ;
reg                 [REG_COUNT-1          : 0]      r_reg_write_valid   ;
reg                 [REG_COUNT-1          : 0]      r_reg_read_valid    ;

integer                                             index               ;



/* 将输出信号连接到对应的寄存器上 */
assign  S_AXI_AWREADY       =                       axi_awready         ;
assign  S_AXI_WREADY        =                       axi_wready          ;
assign  S_AXI_BRESP         =                       axi_bresp           ;
assign  S_AXI_BVALID        =                       axi_bvalid          ;
assign  S_AXI_ARREADY       =                       axi_arready         ;
assign  S_AXI_RDATA         =                       axi_rdata           ;
assign  S_AXI_RRESP         =                       axi_rresp           ;
assign  S_AXI_RVALID        =                       axi_rvalid          ;

assign  data_write          =                       r_data_write        ;
assign  reg_write_valid     =                       r_reg_write_valid   ;
assign  reg_read_valid      =                       r_reg_read_valid    ;


/* axi主机写状态位 1:从机正在处理 axi主机的写请求  0:从机处于空闲状态 */
reg                                                 master_write_state  ;
/* axi主机的写请求标志 */
wire                                                master_wire_request ;

/* axi主机的地址和数据都准备好了则认为主机有写请求 */
assign  master_wire_request =                       S_AXI_AWVALID       && 
                                                    S_AXI_WVALID        ;
    
reg reg_write_success;
always @(*) begin
    reg_write_success = 1'b0;
    for (index = 0; index < REG_COUNT; index = index + 1) begin
        if ((r_reg_write_valid[index] && reg_write_ready[index])) begin
            reg_write_success = 1'b1;
        end
    end
end


/* 写处理 */
/* 将axi写数据端口直连到 reg端口 */
always @( posedge S_AXI_ACLK ) begin
    if ( S_AXI_ARESETN == 1'b0 )begin
        r_data_write <= 0;
    end else begin
        for ( index = 0; index <= (C_S_AXI_DATA_WIDTH/8)-1; index = index+1 ) begin 
            if ( S_AXI_WSTRB[index] == 1 ) begin 
                r_data_write[(index*8) +: 8] <= S_AXI_WDATA[(index*8) +: 8];
            end
        end
    end
end


always @( posedge S_AXI_ACLK ) begin
    axi_bresp   <= 2'b0;
end



always @( posedge S_AXI_ACLK )begin
    if ( S_AXI_ARESETN == 1'b0 )begin
        master_write_state <= 1'b0;                        
    end else if (master_wire_request && ~master_write_state) begin
    /* axi主机有写请求 且 从机还没有响应 则开始响应 */
        master_write_state <= 1'b1;
    end else if (S_AXI_BREADY && axi_bvalid) begin
    /* axi从机向主机发送axi_bvalid 并得到响应,则认为主机的写过程结束 */
        master_write_state <= 1'b0;
    end
end



always @( posedge S_AXI_ACLK ) begin
    if ( S_AXI_ARESETN == 1'b0 ) begin
        for (index = 0; index < REG_COUNT; index = index + 1) begin
            r_reg_write_valid[index] <= 0;
        end
    end else begin
        if (master_wire_request && ~master_write_state) begin
            for (index = 0; index < REG_COUNT; index = index + 1) begin
                if (S_AXI_AWADDR[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == index) begin
                    r_reg_write_valid[index] <= 1;
                end
            end
        end else begin
            for (index = 0; index < REG_COUNT; index = index + 1) begin
                if (r_reg_write_valid[index] && reg_write_ready[index]) begin
                    r_reg_write_valid[index] <= 0;
                end
            end
        end
    end
end


    /* 往寄存器写成功后 */
always @( posedge S_AXI_ACLK )begin
    if ( S_AXI_ARESETN == 1'b0 )begin
        axi_awready <= 1'b0;
        axi_wready  <= 1'b0;
    end else if(reg_write_success) begin
        axi_awready<= 1'b1;
        axi_wready <= 1'b1;
    end else  begin
        axi_awready <= 1'b0;
        axi_wready  <= 1'b0;
    end
end

always @( posedge S_AXI_ACLK )begin
    if ( S_AXI_ARESETN == 1'b0 )begin
        axi_bvalid  <= 0;
    end else if(reg_write_success) begin
        axi_bvalid <= 1'b1;
    end else if(S_AXI_BREADY && axi_bvalid) begin
        axi_bvalid  <= 0;
    end
end


/* 读数据 */
/* axi主机读状态位 1:从机正在处理 axi主机的读请求  0:从机处于空闲状态 */
reg                                     master_read_state                           ;
/* axi主机的读请求标志 */
wire                                    master_read_request                         ;

/* axi主机的地址和数据都准备好了则认为主机有写请求 */
assign  master_read_request =           S_AXI_ARVALID                               ;


reg reg_read_success;
always @(*) begin
    reg_read_success = 1'b0;
    for (index = 0; index < REG_COUNT; index = index + 1) begin
        if ((r_reg_read_valid[index] && reg_read_ready[index])) begin
            reg_read_success = 1'b1;
        end
    end
end


/* reg端口直连到 axi_rdata */
always @( * ) begin
    axi_rdata <= data_read;
end
always @( posedge S_AXI_ACLK ) begin
    axi_rresp <= 0;
end

always @( posedge S_AXI_ACLK )begin
    if ( S_AXI_ARESETN == 1'b0 )begin
        master_read_state <= 1'b0;
    end else if (master_read_request && ~master_read_state) begin
        master_read_state <= 1'b1;
    end else if (axi_rvalid && S_AXI_RREADY) begin
        master_read_state <= 1'b0;
    end
end


always @( posedge S_AXI_ACLK ) begin
    if ( S_AXI_ARESETN == 1'b0 ) begin
        for (index = 0; index < REG_COUNT; index = index + 1) begin
            r_reg_read_valid[index] <= 0;
        end
    end else begin
        if (master_read_request && ~master_read_state) begin
            for (index = 0; index < REG_COUNT; index = index + 1) begin
                if (S_AXI_ARADDR[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == index) begin
                    r_reg_read_valid[index] <= 1;
                end
            end
        end else begin
            for (index = 0; index < REG_COUNT; index = index + 1) begin
                if (r_reg_read_valid[index] && reg_read_ready[index]) begin
                    r_reg_read_valid[index] <= 0;
                end
            end
        end
    end
end


always @( posedge S_AXI_ACLK )begin
    if ( S_AXI_ARESETN == 1'b0 )begin
        axi_arready <= 0;
    end else if (reg_read_success) begin
        axi_arready <= 1'b1;
    end else begin
        axi_arready <= 1'b0;
    end
end


always @( posedge S_AXI_ACLK )begin
    if ( S_AXI_ARESETN == 1'b0 )begin
        axi_rvalid <= 0;
    end else if (reg_read_success) begin
        axi_rvalid <= 1'b1;
    end else if(axi_rvalid && S_AXI_RREADY) begin
        axi_rvalid <= 1'b0;
    end
end


endmodule

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值