官方使用手册:
https://docs.amd.com/v/u/5.0-English/pg022_axi_datamover
功能说明:这个IP主要实现在axi 内存地址总线搬移数据,用户只需要配置CMD接口的起始地址和搬移数据字节数,就可以通过axi stream S2MM接口将数据搬移到指定axi 内存总线地址,将数据从指定axi内存总线地址中搬移出来通过axi stream MM2S接口输出。
1、为了方便代码编写,基于BD简单搭建了一个小工程,主要实现通过datamover读写axi 总线接口的bram数据
IP配置如下:
2、顶层控制代码如下
c
module test_top(
input clk_i,
input rst_i_n
);
//================================================================================
localparam IDLE = 3'd0;//空闲
localparam WR_CMD = 3'd1;//S2MM写命令
localparam WR_BURST = 3'd2;//S2MM数据搬移
localparam RD_CMD = 3'd3;//MM2S写命令
localparam RD_BURST = 3'd4;//MM2S数据搬移
localparam RST = 3'd5;//复位
localparam BURST_LEN= 23'h80;//测试搬移数据总字节数
reg [2:0] state = IDLE;
wire [31:0] M_AXIS_MM2S_0_tdata;
wire [3:0] M_AXIS_MM2S_0_tkeep;
wire M_AXIS_MM2S_0_tlast;
wire M_AXIS_MM2S_0_tready;
wire M_AXIS_MM2S_0_tvalid;
reg [71:0] S_AXIS_MM2S_CMD_0_tdata;
wire S_AXIS_MM2S_CMD_0_tready;
reg S_AXIS_MM2S_CMD_0_tvalid;
reg [31:0] S_AXIS_S2MM_0_tdata;
reg [3:0] S_AXIS_S2MM_0_tkeep;
reg S_AXIS_S2MM_0_tlast;
wire S_AXIS_S2MM_0_tready;
reg S_AXIS_S2MM_0_tvalid;
reg [71:0] S_AXIS_S2MM_CMD_0_tdata;
wire S_AXIS_S2MM_CMD_0_tready;
reg S_AXIS_S2MM_CMD_0_tvalid;
design_1_wrapper design_1_i(
.M_AXIS_MM2S_0_tdata(M_AXIS_MM2S_0_tdata),
.M_AXIS_MM2S_0_tkeep(M_AXIS_MM2S_0_tkeep),
.M_AXIS_MM2S_0_tlast(M_AXIS_MM2S_0_tlast),
.M_AXIS_MM2S_0_tready(M_AXIS_MM2S_0_tready),
.M_AXIS_MM2S_0_tvalid(M_AXIS_MM2S_0_tvalid),
.S_AXIS_MM2S_CMD_0_tdata(S_AXIS_MM2S_CMD_0_tdata),
.S_AXIS_MM2S_CMD_0_tready(S_AXIS_MM2S_CMD_0_tready),
.S_AXIS_MM2S_CMD_0_tvalid(S_AXIS_MM2S_CMD_0_tvalid),
.S_AXIS_S2MM_0_tdata(S_AXIS_S2MM_0_tdata),
.S_AXIS_S2MM_0_tkeep(S_AXIS_S2MM_0_tkeep),
.S_AXIS_S2MM_0_tlast(S_AXIS_S2MM_0_tlast),
.S_AXIS_S2MM_0_tready(S_AXIS_S2MM_0_tready),
.S_AXIS_S2MM_0_tvalid(S_AXIS_S2MM_0_tvalid),
.S_AXIS_S2MM_CMD_0_tdata(S_AXIS_S2MM_CMD_0_tdata),
.S_AXIS_S2MM_CMD_0_tready(S_AXIS_S2MM_CMD_0_tready),
.S_AXIS_S2MM_CMD_0_tvalid(S_AXIS_S2MM_CMD_0_tvalid),
.clk_i(clk_i),
.rst_n(rst_i_n && (state != RST))
);
//========================================main===================================//
//CMD命令,一般的读写只需要关注BIT(搬移数据长度)和SADDR地址字段
always @(posedge clk_i) begin
S_AXIS_MM2S_CMD_0_tdata <= {
4'd0 , //[71:68] RSVD
4'd0 , //[67:64] TAG
32'd0 , //[63:32] SADDR 32bit axi address
1'd0 , //[31] DRR
1'd1 , //[30] EOF
6'd0 , //[29:24] DSA
1'd1 , //[23] Type
BURST_LEN //[22:0] BIT
};
S_AXIS_S2MM_CMD_0_tdata <= {
4'd0 , //[71:68] RSVD
4'd0 , //[67:64] TAG
32'd0 , //[63:32] SADDR 32bit axi address
1'd0 , //[31] DRR
1'd1 , //[30] EOF
6'd0 , //[29:24] DSA
1'd1 , //[23] Type
BURST_LEN //[22:0] BIT
};
end
assign M_AXIS_MM2S_0_tready = 'd1;
always @(posedge clk_i) begin
if (rst_i_n == 0) begin
state <= RST;
S_AXIS_S2MM_0_tdata <= 'd0;
S_AXIS_S2MM_0_tkeep <= 'd0;
S_AXIS_S2MM_0_tlast <= 'd0;
S_AXIS_S2MM_0_tvalid <= 'd0;
S_AXIS_S2MM_CMD_0_tvalid <= 'd0;
S_AXIS_MM2S_CMD_0_tvalid <= 'd0;
end
else begin
case (state)
RST: begin
state <= IDLE;
end
IDLE: begin
state <= WR_CMD;
S_AXIS_S2MM_0_tdata <= 'd0;
S_AXIS_S2MM_0_tkeep <= 'd0;
S_AXIS_S2MM_0_tlast <= 'd0;
S_AXIS_S2MM_0_tvalid <= 'd0;
S_AXIS_S2MM_CMD_0_tvalid <= 'd0;
S_AXIS_MM2S_CMD_0_tvalid <= 'd0;
end
WR_CMD: begin
if (S_AXIS_S2MM_CMD_0_tvalid && S_AXIS_S2MM_CMD_0_tready) begin
state <= WR_BURST;
S_AXIS_S2MM_CMD_0_tvalid <= 'd0;
end
else begin
S_AXIS_S2MM_CMD_0_tvalid <= 'd1;
end
end
WR_BURST: begin
S_AXIS_S2MM_0_tkeep <= 'hffff;
if (S_AXIS_S2MM_0_tvalid && S_AXIS_S2MM_0_tready) begin
S_AXIS_S2MM_0_tdata <= S_AXIS_S2MM_0_tdata + 'd1;
if (S_AXIS_S2MM_0_tdata == BURST_LEN/4-2) begin//data width is 32,4byte
S_AXIS_S2MM_0_tlast <= 'd1;
end
else begin
S_AXIS_S2MM_0_tlast <= 'd0;
end
end
else begin
S_AXIS_S2MM_0_tlast <= 'd0;
end
if (S_AXIS_S2MM_0_tvalid && S_AXIS_S2MM_0_tready && S_AXIS_S2MM_0_tlast) begin
state <= RD_CMD;
S_AXIS_S2MM_0_tvalid <= 'd0;
end
else begin
S_AXIS_S2MM_0_tvalid <= 'd1;
end
end
RD_CMD: begin
if (S_AXIS_MM2S_CMD_0_tvalid && S_AXIS_MM2S_CMD_0_tready) begin
state <= RD_BURST;
S_AXIS_MM2S_CMD_0_tvalid<= 'd0;
end
else begin
S_AXIS_MM2S_CMD_0_tvalid<= 'd1;
end
end
RD_BURST: begin
if (M_AXIS_MM2S_0_tvalid && M_AXIS_MM2S_0_tready && M_AXIS_MM2S_0_tlast) begin
state <= IDLE;
end
end
default: begin
state <= IDLE;
end
endcase
end
end
endmodule
需要注意的是一定要满足axi stream规范,S2MM的tlast不能早或者晚来。
CMD的data每个bit解释参考文档说明:
只需要给个简单的测试激励就可以仿真了:
c
module tb_top();
reg clk_i = 0;
reg rst_n = 0;
always #10 clk_i = ~clk_i;
initial begin
rst_n = 0;
#100
rst_n = 1;
end
test_top test_top(
.clk_i(clk_i),
.rst_i_n(rst_n)
);
endmodule
仿真波形如下:
写入从0开始的累加数
读出的数据正常