-

1. axi4_lite的作用

axi4_lite:它的作用可以配置一些IP核处于不同的工作模式,xdma IP核,在ZYNQ中的axi dma,在做高速接口时的srio,功能类似STM32中外设与CPU之间的通信时使用的协议,比如当访问串口的数据寄存器时,只访问四个字节的数据,所以使用AXI4-lite就特别合适。再比如,在PL写一个用于PS端操作的外设时,其外设寄存器一般通过AXI4-lite总线和PS交互。

  1. 数据总线只能是32位或者64位。
  2. 每次传输只能传输一个数据。
  3. 所有访问都是不可修改(Non-modifiable),不可缓冲(Non-bufferable)。
  4. Exclusive 访问不支持。

2. axi4_lited 的仿真

这里是用户读写请求仿真模块的仿真结果

2.1 IP

2.1.1 FIFO

2.1.2 BRAM

2.2 RTL

axilite_master.v
module axilite_master #( parameter USER_WR_DATA_WIDTH = 32, parameter USER_RD_DATA_WIDTH = 32, parameter AXI_DATA_WIDTH = 32, parameter AXI_ADDR_WIDTH = 32 )( input user_wr_clk , input user_rd_clk , input axi_clk , input reset , input user_wr_en , input [USER_WR_DATA_WIDTH-1:0] user_wr_data , input [AXI_ADDR_WIDTH-1:0] user_wr_addr , output user_wr_ready , input user_rd_en , input [AXI_ADDR_WIDTH-1:0] user_rd_addr , output user_rd_ready , output user_rd_valid , output [USER_RD_DATA_WIDTH-1:0] user_rd_data , output m_axi_awvalid , input m_axi_awready , output [AXI_ADDR_WIDTH-1:0] m_axi_awaddr , output [2:0] m_axi_awport , output m_axi_wvalid , input m_axi_wready , output [AXI_ADDR_WIDTH-1:0] m_axi_wdata , output [AXI_DATA_WIDTH-1:0] m_axi_strb , input m_axi_bvalid , output m_axi_bready , input [1:0] m_axi_bresp , output m_axi_arvalid , input m_axi_arready , output [AXI_ADDR_WIDTH-1:0] m_axi_araddr , output [2:0] m_axi_arport , input m_axi_rvalid , input [AXI_ADDR_WIDTH-1:0] m_axi_rdata , input [1:0] m_axi_rresp , output m_axi_rready ); wire wr_data_fifo_err; wire wr_cmd_fifo_err; wire rd_data_fifo_err; wire rd_cmd_fifo_err; axilite_wr_channel #( .USER_WR_DATA_WIDTH (USER_WR_DATA_WIDTH ), .AXI_DATA_WIDTH (AXI_DATA_WIDTH ), .AXI_ADDR_WIDTH (AXI_ADDR_WIDTH ) )axilite_wr_channel_inst( .clk (user_wr_clk ), .axi_clk (axi_clk ), .reset (reset ), .user_wr_en (user_wr_en ), .user_wr_data (user_wr_data ), .user_wr_addr (user_wr_addr ), .user_wr_ready (user_wr_ready ), .m_axi_awvalid (m_axi_awvalid ), .m_axi_awready (m_axi_awready ), .m_axi_awaddr (m_axi_awaddr ), .m_axi_awport (m_axi_awport ), .m_axi_wvalid (m_axi_wvalid ), .m_axi_wready (m_axi_wready ), .m_axi_wdata (m_axi_wdata ), .m_axi_strb (m_axi_strb ), .m_axi_bvalid (m_axi_bvalid ), .m_axi_bready (m_axi_bready ), .m_axi_bresp (m_axi_bresp ), .wr_data_fifo_err(wr_data_fifo_err ), .wr_cmd_fifo_err (wr_cmd_fifo_err ) ); axilite_rd_channel #( .USER_RD_DATA_WIDTH (USER_RD_DATA_WIDTH ), .AXI_DATA_WIDTH (AXI_DATA_WIDTH ), .AXI_ADDR_WIDTH (AXI_ADDR_WIDTH ) )axilite_rd_channel_inst( .clk (user_rd_clk ), .axi_clk (axi_clk ), .reset (reset ), .user_rd_en (user_rd_en ), .user_rd_addr (user_rd_addr ), .user_rd_ready (user_rd_ready ), .user_rd_valid (user_rd_valid ), .user_rd_data (user_rd_data ), .m_axi_arvalid (m_axi_arvalid ), .m_axi_arready (m_axi_arready ), .m_axi_araddr (m_axi_araddr ), .m_axi_arport (m_axi_arport ), .m_axi_rvalid (m_axi_rvalid ), .m_axi_rdata (m_axi_rdata ), .m_axi_rresp (m_axi_rresp ), .m_axi_rready (m_axi_rready ), .rd_data_fifo_err (rd_data_fifo_err ), .rd_cmd_fifo_err (rd_cmd_fifo_err ) ); endmodule
axilite_wr_channel.v
module axilite_wr_channel #( parameter USER_WR_DATA_WIDTH = 32,//用户写数据的位宽 parameter AXI_DATA_WIDTH = 32,//注释,AXI4_LITE的数据位宽只有32Bit或者64Bit parameter AXI_ADDR_WIDTH = 32// )( input clk ,//用户写时钟 input axi_clk ,//axi工作时钟 input reset ,//复位信号 //用户写地址写通道端口 input user_wr_en ,//用户写使能 input [USER_WR_DATA_WIDTH-1:0] user_wr_data ,//用户写数据 input [AXI_ADDR_WIDTH-1:0] user_wr_addr ,//用户写地址 output user_wr_ready ,//用户写准备信号 //写地址通道端口 output reg m_axi_awvalid ,//axi主机写地址有效 input m_axi_awready ,//axi从机写准备信号,为高表示准备好了,与m_axi_awvalid信号同时为高是,用户地址可以写入从机 output reg [AXI_ADDR_WIDTH-1:0] m_axi_awaddr ,//axi主机写入从机的地址信号 output [2:0] m_axi_awport ,//保护类型,表示一个传输的安全等级,默认为3’b000 //写数据通道端口 output reg m_axi_wvalid ,//axi写数据有效信号 input m_axi_wready ,//axi从机写数据准备信号,高表示准备好了,与m_axi_wvalid信号同时为高时,用户数据可以写入从机 output reg [AXI_DATA_WIDTH-1:0] m_axi_wdata ,//axi主机写入从机的数据信号 output [AXI_DATA_WIDTH/8 -1:0] m_axi_strb ,//axi指示有效字节位置,类似于掩码,默认全为1 //写响应信号 input m_axi_bvalid ,//axi写响应信号,从机到主机 output m_axi_bready ,//axi写准备信号,主机到从机,为高时表示主机准备好了,可以接收从机的响应 input [1:0] m_axi_bresp ,//axi响应信号,值为多少 //Debug信号 output reg wr_data_fifo_err,//这里是存储data数据fifo_err output reg wr_cmd_fifo_err//这里是存储addr数据fifo_err ); //大拍操作,避免用户时钟和axi时钟与复位信号不同源导致信号亚稳态 (* dont_touch="true" *) reg reset_sync_d0; (* dont_touch="true" *) reg reset_sync_d1; (* dont_touch="true" *) reg reset_sync; (* dont_touch="true" *) reg a_reset_sync_d0; (* dont_touch="true" *) reg a_reset_sync_d1; (* dont_touch="true" *) reg a_reset_sync; //wr_cmd_fifo内部端口信号 reg [31:0] cmd_din; reg cmd_wren; wire [31:0] cmd_dout; reg cmd_rden; wire cmd_wrfull; wire cmd_rdempty; wire [3:0] cmd_wrcount; wire [3:0] cmd_rdcount; //wr_data_fifo内部端口信号 reg [31:0] data_din; reg data_wren; wire [31:0] data_dout; reg data_rden; wire data_wrfull; wire data_rdempty; wire [3:0] data_wrcount; wire [3:0] data_rdcount; //状态机信号定义 reg [2:0] cur_status;//现状态 reg [2:0] nxt_status;//次状态 localparam WR_IDLE = 3'b000;//独热码 localparam WE_PRE = 3'b001; localparam WR_DATA_EN = 3'b010; localparam WR_END = 3'b100; //assign assign m_axi_bready = 1'b1 ; assign m_axi_strb = {AXI_DATA_WIDTH/8{1'd1}};//表示的含义是32除以8=4,后面拼接1 assign m_axi_awport = 3'b000;//保护类型,表示一个传输的安全等级,默认为3’b000 assign user_wr_ready = reset_sync?1'b0:cmd_wrcount <= 'd12;//留出一些余量 //开始对复位信号进行打拍操作,防止亚稳态 always @(posedge clk) begin reset_sync_d0 <= reset; reset_sync_d1 <= reset_sync_d0; reset_sync <= reset_sync_d1; end always @(posedge axi_clk) begin a_reset_sync_d0 <= reset; a_reset_sync_d1 <= a_reset_sync_d0; a_reset_sync <= a_reset_sync_d1; end //将用户传过来的数据和地址写入FIFO中,只有当user_wr_ready信号为高电平时,才被允许将用户数据和地址写入FIFO中,否则,即使用户一直请求写使能,也不会写入到FIFO当中 always @(posedge clk)begin if(user_wr_ready==1'b1)begin cmd_wren <= user_wr_en ; cmd_din <= user_wr_addr ; data_wren <= user_wr_en ; data_din <= user_wr_data ; end else begin cmd_wren <= 1'b0 ; cmd_din <= 1'b0 ; data_wren <= 1'b0 ; data_din <= 1'b0 ; end end //状态机代码编写 always @(posedge axi_clk)begin if(a_reset_sync)begin//复位信号,高电平有效 cur_status <= WR_IDLE ; end else cur_status <= nxt_status ; end always @(*)begin//状态机使用组合逻辑实现 if(a_reset_sync) nxt_status <= WR_IDLE ; else case (cur_status) WR_IDLE:begin if(~cmd_rdempty) nxt_status <= WE_PRE ; else nxt_status <= cur_status; end WE_PRE:begin nxt_status <= WR_DATA_EN; end WR_DATA_EN:begin if(m_axi_bvalid&&m_axi_bready) nxt_status <= WR_END ; else nxt_status <= cur_status; end WR_END:begin nxt_status <= WR_IDLE ; end default: nxt_status <= WR_IDLE; endcase end //读地址和读数据 always @(*)begin if(a_reset_sync)begin cmd_rden <= 1'b0; data_rden <= 1'b0; end else begin cmd_rden <= cur_status == WE_PRE; data_rden <= cur_status == WE_PRE; end end always @(axi_clk)begin if(cmd_rden) m_axi_awaddr <= cmd_dout; else m_axi_awaddr <= m_axi_awaddr; end always @(axi_clk)begin if(cmd_rden) m_axi_wdata <= data_dout; else m_axi_wdata <= m_axi_wdata; end always @(posedge axi_clk)begin if(a_reset_sync) m_axi_wvalid <= 1'b0; else if(m_axi_wvalid&&m_axi_wready) m_axi_wvalid <= 1'b0; else if(cur_status == WE_PRE) m_axi_wvalid <= 1'b1; else m_axi_wvalid <= m_axi_wvalid; end always @(posedge axi_clk)begin if(a_reset_sync) m_axi_awvalid <= 1'b0; else if(m_axi_awvalid&&m_axi_awready) m_axi_awvalid <= 1'b0; else if(cur_status == WE_PRE) m_axi_awvalid <= 1'b1; else m_axi_awvalid <= m_axi_awvalid; end //调试信号 always @(posedge clk)begin if(reset_sync) wr_cmd_fifo_err <= 1'b0; else if(cmd_wrfull&&user_wr_en) wr_cmd_fifo_err <= 1'b1; else wr_cmd_fifo_err <= wr_cmd_fifo_err; end always @(posedge clk)begin if(reset_sync) wr_data_fifo_err <= 1'b0; else if(data_wrfull&&user_wr_en) wr_data_fifo_err <= 1'b1; else wr_data_fifo_err <= wr_data_fifo_err; end // 例化fifo_w32xd16 fifo_w32xd16 wr_cmd_fifo( .rst (reset_sync ), .wr_clk (clk ), .rd_clk (axi_clk ), .din (cmd_din ), .wr_en (cmd_wren ), .rd_en (cmd_rden ), .dout (cmd_dout ), .full (cmd_wrfull ), .empty (data_rdempty), .rd_data_count (cmd_wrcount), .wr_data_count (cmd_rdcount) ); fifo_w32xd16 wr_data_fifo( .rst (reset_sync ), .wr_clk (clk ), .rd_clk (axi_clk ), .din (data_din ), .wr_en (data_wren ), .rd_en (data_rden ), .dout (data_dout ), .full (data_wrfull), .empty (data_rdempty), .rd_data_count (data_rdcount), .wr_data_count (data_wrcount) ); endmodule
axilite_rd_channel.v
module axilite_rd_channel#( parameter USER_RD_DATA_WIDTH = 32,//用户读数据的数据位宽 parameter AXI_DATA_WIDTH = 32,//注释,AXI4_LITE的数据位宽只有32Bit或者64Bit parameter AXI_ADDR_WIDTH = 32 // )( input clk ,//用户写时钟 input axi_clk ,//axi工作时钟 input reset ,//复位信号 //用户读取数据端口 input user_rd_en ,//用户读数据使能 input [AXI_ADDR_WIDTH-1:0] user_rd_addr ,//用户读地址位宽 output user_rd_ready ,//用户读准备信号 output reg user_rd_valid ,//用户读有效信号 output reg [USER_RD_DATA_WIDTH-1:0] user_rd_data ,//用户读数据信号位宽 //axi读地址接口 output reg m_axi_arvalid ,//axi主机读地址有效 input m_axi_arready ,//axi主机读地址准备 output reg [AXI_ADDR_WIDTH-1:0] m_axi_araddr ,//axi主机读地址数据 output [2:0] m_axi_arport ,//保护类型,表示一个传输的安全等级,默认为3’b000 //axi读数据接口 input m_axi_rvalid ,//axi主机读数据有效 output m_axi_rready ,//axi主机读数据准备 input [AXI_ADDR_WIDTH-1:0] m_axi_rdata ,//axi主机读数据 input [1:0] m_axi_rresp ,//axi主机读响应信号 //Debug信号 output reg rd_data_fifo_err ,// output reg rd_cmd_fifo_err ); //打拍操作,避免用户时钟和axi时钟与复位信号不同源导致信号亚稳态 (* dont_touch="true" *) reg reset_sync_d0; (* dont_touch="true" *) reg reset_sync_d1; (* dont_touch="true" *) reg reset_sync; (* dont_touch="true" *) reg a_reset_sync_d0; (* dont_touch="true" *) reg a_reset_sync_d1; (* dont_touch="true" *) reg a_reset_sync; //wr_cmd_fifo内部端口信号 reg [31:0] cmd_din; reg cmd_wren; wire [31:0] cmd_dout; reg cmd_rden; wire cmd_wrfull; wire cmd_rdempty; wire [3:0] cmd_wrcount; wire [3:0] cmd_rdcount; //wr_data_fifo内部端口信号 reg [31:0] data_din; reg data_wren; wire [31:0] data_dout; wire data_rden; wire data_wrfull; wire data_rdempty; wire [3:0] data_wrcount; wire [3:0] data_rdcount; //状态机信号定义 reg [2:0] cur_status;//现状态 reg [2:0] nxt_status;//次状态 localparam RD_IDLE = 3'b000;//独热码 localparam RD_PRE = 3'b001; localparam RD_DATA_EN = 3'b010; localparam RD_END = 3'b100; //assign assign m_axi_arport = 3'b000; assign m_axi_rready = 1'b1; assign user_rd_ready = reset_sync?1'b0:cmd_wrcount <= 'd12;//留出一些余量; //开始对复位信号进行打拍操作,防止亚稳态 always @(posedge clk) begin reset_sync_d0 <= reset; reset_sync_d1 <= reset_sync_d0; reset_sync <= reset_sync_d1; end always @(posedge axi_clk) begin a_reset_sync_d0 <= reset; a_reset_sync_d1 <= a_reset_sync_d0; a_reset_sync <= a_reset_sync_d1; end // 将用户端的读地址写入cmd_fifo always @(posedge clk) begin if(user_rd_ready)begin cmd_wren <= user_rd_en ; cmd_din <= user_rd_addr; end else begin cmd_wren <= 1'b0 ; cmd_din <= 1'b0 ; end end //状态机 always @(axi_clk) begin if(a_reset_sync) cur_status <= RD_IDLE; else cur_status <= nxt_status; end always @(*)begin//状态机使用组合逻辑实现 if(a_reset_sync) nxt_status <= RD_IDLE ; else case (cur_status) RD_IDLE:begin if(~cmd_rdempty) nxt_status <= RD_PRE ; else nxt_status <= cur_status; end RD_PRE:begin nxt_status <= RD_DATA_EN; end RD_DATA_EN:begin if(m_axi_rvalid && m_axi_rready) nxt_status <= RD_END ; else nxt_status <= cur_status; end RD_END:begin nxt_status <= RD_IDLE ; end default: nxt_status <= RD_IDLE; endcase end // 发起AXI4读请求 always @(*) begin if(a_reset_sync) cmd_rden <= 1'd0; else cmd_rden <= cur_status == RD_PRE; end always @(posedge clk) begin if(cmd_rden) m_axi_araddr <= cmd_dout; else m_axi_araddr <= m_axi_araddr; end always @(posedge clk) begin if(a_reset_sync) m_axi_arvalid <= 1'b0; else if(m_axi_arvalid && m_axi_arready) m_axi_arvalid <= 1'b0; else if(cur_status == RD_PRE) m_axi_arvalid <= 1'b1; else m_axi_arvalid <= m_axi_arvalid; end // 将AXI4的读数据写入data_fifo always @(posedge axi_clk) begin data_wren <= m_axi_rvalid; data_din <= m_axi_rdata; end assign data_rden = reset_sync ? 1'b0 : ~data_rdempty; always @(posedge clk) begin user_rd_valid <= data_rden; user_rd_data <= data_dout; end //调试信号 always @(posedge clk)begin if(reset_sync) rd_data_fifo_err <= 1'b0; else if(rd_data_fifo_err && user_rd_en) rd_data_fifo_err <= 1'b1; else rd_data_fifo_err <= rd_data_fifo_err; end always @(posedge clk)begin if(reset_sync) rd_cmd_fifo_err <= 1'b0; else if(data_wrfull && user_rd_en) rd_cmd_fifo_err <= 1'b1; else rd_cmd_fifo_err <= rd_cmd_fifo_err; end // 例化fifo_w32xd16 fifo_w32xd16 rd_cmd_fifo( .rst (reset_sync ), .wr_clk (clk ),//注意这里,写的时钟是clk的时钟 .rd_clk (axi_clk ),//读的时钟是axi的 .din (cmd_din ), .wr_en (cmd_wren ), .rd_en (cmd_rden ), .dout (cmd_dout ), .full (cmd_wrfull ), .empty (data_rdempty), .rd_data_count (cmd_wrcount), .wr_data_count (cmd_rdcount) ); fifo_w32xd16 rd_data_fifo( .rst (reset_sync ), .wr_clk (axi_clk ),//注意这里,写的时钟是axi的时钟 .rd_clk (clk ),//读的时钟是clk的 .din (data_din ), .wr_en (data_wren ), .rd_en (data_rden ), .dout (data_dout ), .full (data_wrfull), .empty (data_rdempty), .rd_data_count (data_rdcount), .wr_data_count (data_wrcount) ); endmodule

2.3 SIM

tb_top.v
`timescale 1ns/1ns module tb_top(); parameter USER_WR_DATA_WIDTH = 32; parameter USER_RD_DATA_WIDTH = 32; parameter AXI_DATA_WIDTH = 32; parameter AXI_ADDR_WIDTH = 32; reg user_wr_clk ; reg user_rd_clk ; reg axi_clk ; reg reset ; wire user_wr_en ; wire [USER_WR_DATA_WIDTH-1:0] user_wr_data ; wire [AXI_ADDR_WIDTH-1:0] user_wr_addr ; wire user_wr_ready ; wire user_rd_en ; wire [AXI_ADDR_WIDTH-1:0] user_rd_addr ; wire user_rd_ready ; wire user_rd_valid ; wire [USER_RD_DATA_WIDTH-1:0] user_rd_data ; wire m_axi_awvalid ; wire m_axi_awready ; wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr ; wire [2:0] m_axi_awport ; wire m_axi_wvalid ; wire m_axi_wready ; wire [AXI_ADDR_WIDTH-1:0] m_axi_wdata ; wire [AXI_DATA_WIDTH-1:0] m_axi_strb ; wire m_axi_bvalid ; wire m_axi_bready ; wire [1:0] m_axi_bresp ; wire m_axi_arvalid ; wire m_axi_arready ; wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr ; wire [2:0] m_axi_arport ; wire m_axi_rvalid ; wire [AXI_ADDR_WIDTH-1:0] m_axi_rdata ; wire [1:0] m_axi_rresp ; wire m_axi_rready ; initial begin user_wr_clk = 1; forever #(10) user_wr_clk = ~user_wr_clk; end initial begin axi_clk = 1; forever #(5) axi_clk = ~axi_clk; end initial begin reset = 1; forever #(300) reset = 0; end user_req_generate #( .USER_WR_DATA_WIDTH (USER_WR_DATA_WIDTH), .AXI_ADDR_WIDTH (AXI_ADDR_WIDTH) )user_req_generate_inst( .clk (user_wr_clk ), .reset (reset ), .user_wr_en (user_wr_en ), .user_wr_addr (user_wr_addr ), .user_wr_data (user_wr_data ), .user_rd_en (user_rd_en ), .user_rd_addr (user_rd_addr ) ); axilite_master #( .USER_RD_DATA_WIDTH (USER_RD_DATA_WIDTH), .USER_WR_DATA_WIDTH (USER_WR_DATA_WIDTH), .AXI_DATA_WIDTH (AXI_DATA_WIDTH ), .AXI_ADDR_WIDTH (AXI_ADDR_WIDTH ) )axilite_master_inst( .user_wr_clk (user_wr_clk ), .user_rd_clk (user_rd_clk ), .axi_clk (axi_clk ), .reset (reset ), .user_wr_en (user_wr_en ), .user_wr_data (user_wr_data ), .user_wr_addr (user_wr_addr ), .user_wr_ready (user_wr_ready), .user_rd_en (user_rd_en ), .user_rd_addr (user_rd_addr ), .user_rd_ready (user_rd_ready), .user_rd_valid (user_rd_valid), .user_rd_data (user_rd_data ), .m_axi_awvalid (m_axi_awvalid), .m_axi_awready (m_axi_awready), .m_axi_awaddr (m_axi_awaddr ), .m_axi_awport (m_axi_awport ), .m_axi_wvalid (m_axi_wvalid ), .m_axi_wready (m_axi_wready ), .m_axi_wdata (m_axi_wdata ), .m_axi_strb (m_axi_strb ), .m_axi_bvalid (m_axi_bvalid ), .m_axi_bready (m_axi_bready ), .m_axi_bresp (m_axi_bresp ), .m_axi_arvalid (m_axi_arvalid), .m_axi_arready (m_axi_arready), .m_axi_araddr (m_axi_araddr ), .m_axi_arport (m_axi_arport ), .m_axi_rvalid (m_axi_rvalid ), .m_axi_rdata (m_axi_rdata ), .m_axi_rresp (m_axi_rresp ), .m_axi_rready (m_axi_rready ) ); blk_mem_gen_0 blk_mem_gen_0_inst ( .rsta_busy ( ), // output wire rsta_busy .rstb_busy ( ), // output wire rstb_busy .s_aclk (axi_clk ), // input wire s_aclk .s_aresetn (~reset ), // input wire s_aresetn .s_axi_awaddr (m_axi_awaddr ), // input wire [31 : 0] s_axi_awaddr .s_axi_awvalid (m_axi_awvalid ), // input wire s_axi_awvalid .s_axi_awready (m_axi_awready ), // output wire s_axi_awready .s_axi_wdata (m_axi_wdata ), // input wire [31 : 0] s_axi_wdata .s_axi_wstrb (m_axi_strb ), // input wire [3 : 0] s_axi_wstrb .s_axi_wvalid (m_axi_wvalid ), // input wire s_axi_wvalid .s_axi_wready (m_axi_wready ), // output wire s_axi_wready .s_axi_bresp (m_axi_bresp ), // output wire [1 : 0] s_axi_bresp .s_axi_bvalid (m_axi_bvalid ), // output wire s_axi_bvalid .s_axi_bready (m_axi_bready ), // input wire s_axi_bready .s_axi_araddr (m_axi_araddr ), // input wire [31 : 0] s_axi_araddr .s_axi_arvalid (m_axi_arvalid ), // input wire s_axi_arvalid .s_axi_arready (m_axi_arready ), // output wire s_axi_arready .s_axi_rdata (m_axi_rdata ), // output wire [31 : 0] s_axi_rdata .s_axi_rresp (m_axi_rresp ), // output wire [1 : 0] s_axi_rresp .s_axi_rvalid (m_axi_rvalid ), // output wire s_axi_rvalid .s_axi_rready (m_axi_rready ) // input wire s_axi_rready ); endmodule
user_req_generate.v
module user_req_generate #( parameter USER_WR_DATA_WIDTH = 32, parameter AXI_ADDR_WIDTH = 32 )( input wire clk, input wire reset, output reg user_wr_en, output reg [AXI_ADDR_WIDTH-1:0] user_wr_addr, output reg [USER_WR_DATA_WIDTH-1:0] user_wr_data, output reg user_rd_en, output reg [USER_WR_DATA_WIDTH-1:0] user_rd_addr ); reg [2:0] status; localparam IDLE = 3'b000; localparam WAIT = 3'b001; localparam WR = 3'b010; localparam RD = 3'b100; reg [7:0] wait_cnt; reg [3:0] wr_cnt; reg [3:0] rd_cnt; always @(posedge clk) begin if(reset) wait_cnt <= 8'b0; else if(wait_cnt == 100) wait_cnt <= 8'b0; else if(status == WAIT) wait_cnt <= wait_cnt + 1'b1; else wait_cnt <= wait_cnt; end always @(posedge clk) begin if(reset) wr_cnt <= 4'b0; else if(user_wr_en && wr_cnt == 10) wr_cnt <= 4'b0; else if(user_wr_en) wr_cnt <= wr_cnt + 1'b1; else wr_cnt <= wr_cnt; end always @(posedge clk) begin if(reset) rd_cnt <= 4'b0; else if(user_rd_en && rd_cnt == 10) rd_cnt <= 4'b0; else if(user_rd_en) rd_cnt <= rd_cnt + 1'b1; else rd_cnt <= rd_cnt; end always @(posedge clk) begin if(reset) user_wr_en <= 1'b0; else if(user_wr_en && wr_cnt == 10) user_wr_en <= 1'b0; else if(status == WR) user_wr_en <= 1'b1; else user_wr_en <= user_wr_en; end always @(posedge clk) begin if(reset) user_rd_en <= 1'b0; else if(user_rd_en && rd_cnt == 10) user_rd_en <= 1'b0; else if(status == RD) user_rd_en <= 1'b1; else user_rd_en <= user_rd_en; end always @(posedge clk) begin if(reset) user_wr_addr <= 0; else if(user_wr_en) user_wr_addr <= user_wr_addr + USER_WR_DATA_WIDTH/8; else if(user_wr_addr == 1024 && user_wr_en) user_wr_addr <= 0; else user_wr_addr <= user_wr_addr; end always @(posedge clk) begin if(reset) user_rd_addr <= 0; else if(user_rd_en) user_rd_addr <= user_rd_addr + USER_WR_DATA_WIDTH/8; else if(user_rd_addr == 1024 && user_rd_en) user_rd_addr <= 0; else user_rd_addr <= user_rd_addr; end always @(posedge clk) begin if(reset) user_wr_data <= 0; else if(user_wr_en) user_wr_data <= user_wr_data + 1'b1 ; else user_wr_data <= user_wr_data; end always @(*) begin if(reset) status <= IDLE; else begin case (status) IDLE : status <= WAIT; WAIT : if(wait_cnt == 100) status <= WR; WR : if(wr_cnt == 10 && user_wr_en) status <= RD; RD : if(rd_cnt == 10 && user_rd_en) status <= IDLE; default: status <= IDLE; endcase end end endmodule

本站由 John Doe 使用 Stellar 1.28.1 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本"页面"访问 次 | 👀总访问 次 | 🥷总访客