3-1-02AXI4-FULL-uiFDMA IP仿真验证

发布时间 2023-12-30 11:20:43作者: 米联客(milianke)

软件版本:vitis2021.1(vivado2021.1)

操作系统:WIN10 64bit

硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA

登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!

2.1概述

本文试验中对前面编写的FDMA IP进行仿真验证。

2.2saxi_full_mem IP介绍

这个IP的源码可以基于XILINX提供的axi-full-slave的模板简单修改就可以实现,如果读者想要更加详细的学习AXI总线想内容,可以阅读或者观看米联客"米联客2022版AXI4总线专题篇"相关课程内容。本文实验使用我们已经修改好的代码来完成验证。

这个IP后面可以用于AXI4总线的仿真验证

2.3创建FPGA逻辑工程

设置IP路径

添加已经创建好的IP

输入关键词fdma,在最后可以看到,双击添加Ip

可以看到本文的FDMA版本升级到3.2版

完成连线

继续添加剩余IP

 

 

 

 

 

 

 

设置IP参数

完成连线

设置地址分配:

2.4添加FDMA接口控制代码

 

添加完成后如下图:

fdma_axi_slave_test.v源码如下

/*******************************MILIANKE*******************************

*Company : MiLianKe Electronic Technology Co., Ltd.

*WebSite:https://www.milianke.com

*TechWeb:https://www.uisrc.com

*tmall-shop:https://milianke.tmall.com

*jd-shop:https://milianke.jd.com

*taobao-shop1: https://milianke.taobao.com

*Create Date: 2021/04/25

*Module Name:fdma_axi_slave_test

*File Name:fdma_axi_slave_test.v

*Description:

*The reference demo provided by Milianke is only used for learning.

*We cannot ensure that the demo itself is free of bugs, so users

*should be responsible for the technical problems and consequences

*caused by the use of their own products.

*Copyright: Copyright (c) MiLianKe

*All rights reserved.

*Revision: 1.0

*Signal description

*1) I_ input

*2) O_ output

*3) IO_ input output

*4) S_ system internal signal

*5) _n activ low

*6) _dg debug signal

*7) _r delay or register

*8) _s state mechine

*********************************************************************/

`timescale 1ns / 1ps

module fdma_axi_slave_test(

  input sysclk

);

 

wire [31:0]   fdma_raddr;

reg           fdma_rareq;

wire          fdma_rbusy;

wire [31:0]   fdma_rdata;

wire [15:0]   fdma_rsize;

wire          fdma_rvalid;

wire [31:0]   fdma_waddr;

reg           fdma_wareq;

wire          fdma_wbusy;

wire [31:0]   fdma_wdata;

wire [15:0]   fdma_wsize;

wire          fdma_wvalid;

wire          ui_clk;

 

parameter TEST_MEM_SIZE   = 32'd20000; //测试内存的地址范围

parameter FDMA_BURST_LEN  = 16'd500; //测试一次的长度

parameter ADDR_MEM_OFFSET = 0; //地址偏移量

parameter ADDR_INC = FDMA_BURST_LEN*4; //下一次FDMA burst的地址增加

   

parameter WRITE1 = 0;

parameter WRITE2 = 1;

parameter WAIT   = 2;

parameter READ1  = 3;

parameter READ2  = 4;

 

reg [31: 0] t_data;

reg [31: 0] fdma_waddr_r;

reg [2  :0] T_S = 0;

 

assign fdma_waddr = fdma_waddr_r + ADDR_MEM_OFFSET; //设置偏移地址

assign fdma_raddr = fdma_waddr; //读写地址相同

 

assign fdma_wsize = FDMA_BURST_LEN; //设置FDMA控制器一次写burst的数据长度

assign fdma_rsize = FDMA_BURST_LEN; //设置FDMA控制器一次读burst的数据长度

assign fdma_wdata ={t_data,t_data,t_data,t_data};

   

   

////延迟复位

reg [8:0] rst_cnt = 0;

always @(posedge ui_clk)

    if(rst_cnt[8] == 1'b0)

         rst_cnt <= rst_cnt + 1'b1;

     else

         rst_cnt <= rst_cnt;

 

//FDMA 读写控制器,每次先写后读,读出后对比数据正确性

always @(posedge ui_clk)begin

    if(rst_cnt[8] == 1'b0)begin

        T_S <=0;  

        fdma_wareq  <= 1'b0;

        fdma_rareq  <= 1'b0;

        t_data<=0;

        fdma_waddr_r <=0;      

    end

    else begin

        case(T_S)      

        WRITE1:begin

            if(fdma_waddr_r==TEST_MEM_SIZE) fdma_waddr_r<=0; //超出测试内存范围,重新测试

                if(!fdma_wbusy)begin//fdma进入空闲,fdma_wbusy=0,请求写

                    fdma_wareq  <= 1'b1; //设置写请求

                    t_data  <= 0; //设置初值

                end

                if(fdma_wareq&&fdma_wbusy)begin//fdma响应请求后,fdma_wbusy=1,进入下一个状态

                    fdma_wareq  <= 1'b0;

                    T_S         <= WRITE2;

                end

        end

        WRITE2:begin

            if(!fdma_wbusy) begin//fdma完成请求后,fdma_wbusy=0,进入下一个状态

                 T_S <= WAIT;

                 t_data  <= 32'd0;

            end

            else if(fdma_wvalid) begin//fdma_wvalid有效期间必须写入有效数据

                t_data <= t_data + 1'b1;

            end

        end

        WAIT:begin//not needed

            T_S <= READ1;

        end

        READ1:begin

            if(!fdma_rbusy)begin//fdma进入空闲,fdma_rbusy=0,请求读

                fdma_rareq  <= 1'b1; //设置读请求

                t_data   <= 0; //设置初值

            end

            if(fdma_rareq&&fdma_rbusy)begin//fdma响应请求后,fdma_rbusy=1,进入下一个状态

                 fdma_rareq  <= 1'b0; //清除读请求

                 T_S         <= READ2;

            end

        end

        READ2:begin

            if(!fdma_rbusy) begin//fdma完成请求后,fdma_rbusy=0,进入下一个状态

                 T_S <= WRITE1;

                 t_data  <= 32'd0;

                 fdma_waddr_r  <= fdma_waddr_r + ADDR_INC; //当本次读写周期完成增加地址,地址以BYTE计算

            end

            else if(fdma_rvalid) begin//fdma_rvalid有效期间读出的数据有效

                t_data <= t_data + 1'b1;

            end

        end  

        default:

            T_S <= WRITE1;    

        endcase

    end

  end

 //对比是否有错误数据

wire test_error = (fdma_rvalid && (t_data[15:0] != fdma_rdata[15:0]));

 

//ila_0 ila_dbg (

//  .clk(ui_clk),

//  .probe0({fdma_wdata[15:0],fdma_wareq,fdma_wvalid,fdma_wbusy}),

//  .probe1({fdma_rdata[15:0],t_data[15:0],fdma_rvalid,fdma_rbusy,T_S,test_error})

//);

 

  system system_i

       (.FDMA_S_0_fdma_raddr(fdma_raddr),

        .FDMA_S_0_fdma_rareq(fdma_rareq),

        .FDMA_S_0_fdma_rbusy(fdma_rbusy),

        .FDMA_S_0_fdma_rdata(fdma_rdata),

        .FDMA_S_0_fdma_rready(1'b1),

        .FDMA_S_0_fdma_rsize(fdma_rsize),

        .FDMA_S_0_fdma_rvalid(fdma_rvalid),

        .FDMA_S_0_fdma_waddr(fdma_waddr),

        .FDMA_S_0_fdma_wareq(fdma_wareq),

        .FDMA_S_0_fdma_wbusy(fdma_wbusy),

        .FDMA_S_0_fdma_wdata(fdma_wdata),

        .FDMA_S_0_fdma_wready(1'b1),

        .FDMA_S_0_fdma_wsize(fdma_wsize),

        .FDMA_S_0_fdma_wvalid(fdma_wvalid),

        .sysclk(sysclk),

        .ui_clk(ui_clk)

        );        

 

endmodule

以上代码中调用的system.bd的图形代码接口。在状态机中,每次写500个长度32bit的数据,再读出来判断数据是否正确,因此传输20000字节的数据需要传输10次,每次FDMA传输的地址递增2000。

2.5仿真文件

添加仿真文件

以下文件路径以实际工程的路径为准

添加完成后:

仿真文件非常简单,只要提供时钟激励就可以。

`timescale 1ns / 1ps

module fdma_axi_slave_test_tb();

 reg sysclk;

 fdma_axi_slave_test fdma_axi_slave_test_inst

(

    .sysclk(sysclk)

 );

initial begin

     sysclk  = 0;

     #100;

end

    always #10 sysclk = ~sysclk;  

endmodule

2.6实验结果

下图中红色框内分别代表了FDMA一次burst的写操作和一次burst的读操作。FDMA 控制器会根据用户代码设置的fdma_wsize和fdma_rsize以及设置的FDMA IP参数中,AXI4总线支持的最大burst 长度,来决定进行多少次的AXI4 burst。

本次写传输中,wburst_len_req自动发起计算AXI4总线需要发起的传输长度,本次传输中,FDMA的用户代码每次发起传输长度为500,因此FDMA部分会自动控制AXI部分的传输长度,第一次axi burst长度为256,第二次axi burst长度为244。

一次FDMA写传输的起始时序

连续burst,自动管理burst长度,以及一次FDMA写传输结束时序

本次读传输中,rburst_len_req自动发起计算AXI4总线需要发起的传输长度,本次传输中,FDMA的用户代码每次发起传输长度为500,因此FDMA部分会自动控制AXI部分的传输长度,第一次axi burst长度为256,第二次axi burst长度为244。

一次FDMA读传输的起始时序

连续burst,自动管理burst长度,以及一次FDMA读传输结束时序

另外放大后可以看到rvalid不是连续的,这个读者也可以自己去优化saxi_ful_mem ip让这IP支持连续的rvalid