- 代码实现的功能是将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