1. axi4_lite的作用
axi4_lite:它的作用可以配置一些IP核处于不同的工作模式,xdma IP核,在ZYNQ中的axi dma,在做高速接口时的srio,功能类似STM32中外设与CPU之间的通信时使用的协议,比如当访问串口的数据寄存器时,只访问四个字节的数据,所以使用AXI4-lite
就特别合适。再比如,在PL
写一个用于PS
端操作的外设时,其外设寄存器一般通过AXI4-lite
总线和PS
交互。
- 数据总线只能是32位或者64位。
- 每次传输只能传输一个数据。
- 所有访问都是不可修改(Non-modifiable),不可缓冲(Non-bufferable)。
- 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
```