跳转至

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

```verilog 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




```verilog 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

```verilog 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

```Verilog 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

```Verilog 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

```