xilinx axi datamover IP使用demo

官方使用手册:
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开始的累加数

读出的数据正常

相关推荐
Turing_kun14 小时前
基于FPGA的实时图像处理系统(1)——SDRAM回环测试
fpga开发
I'm a winner1 天前
新手入门Makefile:FPGA项目实战教程(二)
笔记·fpga开发
我爱C编程2 天前
基于FPGA的8PSK+卷积编码Viterbi译码通信系统,包含帧同步,信道,误码统计,可设置SNR
fpga开发·通信·8psk·帧同步·snr·卷积编码·维特比译码
I'm a winner2 天前
新手入门 Makefile:FPGA 项目实战教程(三)
fpga开发
范纹杉想快点毕业2 天前
嵌入式 C 语言编程规范个人学习笔记,参考华为《C 语言编程规范》
linux·服务器·数据库·笔记·单片机·嵌入式硬件·fpga开发
lazyduck2 天前
从半年到一年的 bug 往事:TCP modbus的卡死与补救
fpga开发·modbus
范纹杉想快点毕业3 天前
《嵌入式 C 语言编码规范与工程实践个人笔记》参考华为C语言规范标准
服务器·c语言·stm32·单片机·华为·fpga开发·51单片机
Chipi Chipi3 天前
FPGA即插即用Verilog驱动系列——串口数据、命令解析
fpga开发
FPGA_ADDA4 天前
基于 AMDXCVU47P HBM2 FPGA 的 2 路 100G 光纤 PCIe 高性能计算加速卡
fpga开发·vu47p·100g光纤pcie·高性能计算加速卡
霖004 天前
高级项目——基于FPGA的串行FIR滤波器
人工智能·经验分享·matlab·fpga开发·信息与通信·信号处理