[X]关闭

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

文档创建者:uisrc
浏览次数:383
最后更新:2023-12-30
文档课程分类
AMD: FPGA部分(2024样板资料) » 2_FPGA实验篇(仅旗舰) » 2-FPGA PL DDR使用
软件版本: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总线专题篇"相关课程内容。本文实验使用我们已经修改好的代码来完成验证。
2504661-20231230111822481-965475253.jpg
这个IP后面可以用于AXI4总线的仿真验证
2.3创建FPGA逻辑工程
2504661-20231230111823029-1245718078.jpg
设置IP路径
2504661-20231230111823514-629800555.jpg
2504661-20231230111823916-1028449684.jpg
添加已经创建好的IP
2504661-20231230111824269-809781074.jpg
输入关键词fdma,在最后可以看到,双击添加Ip
2504661-20231230111824622-1269623248.jpg
可以看到本文的FDMA版本升级到3.2版
2504661-20231230111824999-754692755.jpg
完成连线
继续添加剩余IP
2504661-20231230111825319-192093262.jpg
2504661-20231230111825607-1561346142.jpg







2504661-20231230111825918-1079113397.jpg
设置IP参数
2504661-20231230111826282-1906533205.jpg
2504661-20231230111826664-28742111.jpg
2504661-20231230111827088-700460665.jpg
2504661-20231230111827599-1338111611.jpg
完成连线
2504661-20231230111828091-818338030.jpg
设置地址分配:
2504661-20231230111828457-282843128.jpg
2.4添加FDMA接口控制代码
2504661-20231230111828809-410827669.jpg

2504661-20231230111829216-79737916.jpg
2504661-20231230111829649-661900975.jpg
添加完成后如下图:
2504661-20231230111830058-963771623.jpg
fdma_axi_slave_test.v源码如下
/*******************************MILIANKE*******************************
*Company : MiLianKe Electronic Technology Co., Ltd.
*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仿真文件
添加仿真文件
2504661-20231230111830453-289364459.jpg
以下文件路径以实际工程的路径为准
2504661-20231230111830856-1701267533.jpg
添加完成后:
2504661-20231230111836266-25615286.jpg
仿真文件非常简单,只要提供时钟激励就可以。
`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。
2504661-20231230111836762-2058670359.jpg
本次写传输中,wburst_len_req自动发起计算AXI4总线需要发起的传输长度,本次传输中,FDMA的用户代码每次发起传输长度为500,因此FDMA部分会自动控制AXI部分的传输长度,第一次axi burst长度为256,第二次axi burst长度为244。
2504661-20231230111837203-1888042453.jpg
一次FDMA写传输的起始时序
2504661-20231230111837591-855935587.jpg
连续burst,自动管理burst长度,以及一次FDMA写传输结束时序
2504661-20231230111838078-1871935958.jpg
本次读传输中,rburst_len_req自动发起计算AXI4总线需要发起的传输长度,本次传输中,FDMA的用户代码每次发起传输长度为500,因此FDMA部分会自动控制AXI部分的传输长度,第一次axi burst长度为256,第二次axi burst长度为244。
2504661-20231230111838503-1235803775.jpg
一次FDMA读传输的起始时序
2504661-20231230111838979-384292289.jpg
连续burst,自动管理burst长度,以及一次FDMA读传输结束时序
2504661-20231230111844411-2009179617.jpg

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则