0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

利用XILINX提供的FIFO IP进行读写测试

电子设计 来源:电子设计 作者:电子设计 2022-02-08 17:08 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

作者: ALINX

适用于板卡型号:
AXU2CGA/AXU2CGB/AXU3EG/AXU4EV-E/AXU4EV-P/AXU5EV-E/AXU5EV-P /AXU9EG/AXU15EG

实验Vivado工程为“fifo_test”。

FIFO是FPGA应用当中非常重要的模块,广泛用于数据的缓存,跨时钟域数据处理等。学好FIFO是FPGA的关键,灵活运用好FIFO是一个FPGA工程师必备的技能。本章主要介绍利用XILINX提供的FIFO IP进行读写测试。

1.实验原理

FIFO: First in, First out代表先进的数据先出,后进的数据后出。Xilinx在VIVADO里为我们已经提供了FIFO的IP核, 我们只需通过IP核例化一个FIFO,根据FIFO的读写时序来写入和读取FIFO中存储的数据。

其实FIFO是也是在RAM的基础上增加了许多功能,FIFO的典型结构如下,主要分为读和写两部分,另外就是状态信号,空和满信号,同时还有数据的数量状态信号,与RAM最大的不同是FIFO没有地址线,不能进行随机地址读取数据,什么是随机读取数据呢,也就是可以任意读取某个地址的数据。而FIFO则不同,不能进行随机读取,这样的好处是不用频繁地控制地址线。

o4YBAGAJi7qAAp71AABTmac2MoU816.jpg

虽然用户看不到地址线,但是在FIFO内部还是有地址的操作的,用来控制RAM的读写接口。其地址在读写操作时如下图所示,其中深度值也就是一个FIFO里最大可以存放多少个数据。初始状态下,读写地址都为0,在向FIFO中写入一个数据后,写地址加1,从FIFO中读出一个数据后,读地址加1。此时FIFO的状态即为空,因为写了一个数据,又读出了一个数据。

pIYBAGAJi_iAPrtaAABH8SIbtTU552.jpg

可以把FIFO想象成一个水池,写通道即为加水,读通道即为放水,假如不间断的加水和放水,如果加水速度比放水速度快,那么FIFO就会有满的时候,如果满了还继续加水就会溢出overflow,如果放水速度比加水速度快,那么FIFO就会有空的时候,所以把握好加水与放水的时机和速度,保证水池一直有水是一项很艰巨的任务。也就是判断空与满的状态,择机写数据或读数据。

根据读写时钟,可以分为同步FIFO(读写时钟相同)和异步FIFO(读写时钟不同)。同步FIFO控制比较简单,不再介绍,本节实验主要介绍异步FIFO的控制,其中读时钟为75MHz,写时钟为100MHz。实验中会通过VIVADO集成的在想逻辑分析仪ila,我们可以观察FIFO的读写时序和从FIFO中读取的数据。

2. 创建Vivado工程
2.1 添加FIFO IP核

在添加FIFO IP之前先新建一个fifo_test的工程, 然后在工程中添加FIFO IP,方法如下:

2.1.1点击下图中IP Catalog,在右侧弹出的界面中搜索fifo,找到FIFO Generator,双击打开。

pIYBAGAJjDiAcVjnAACIqTgAy3U223.jpg

2.1.2 弹出的配置页面中,这里可以选择读写时钟分开还是用同一个,一般来讲我们使用FIFO为了缓存数据,通常两边的时钟速度是不一样的。所以独立时钟是最常用的,我们这里选择“Independent Clocks Block RAM”,然后点击“Next”到下一个配置页面。

o4YBAGAJjHiAa4MTAACqO0XMJ_o468.jpg

2.1.3 切换到Native Ports栏目下,选择数据位宽16;FIFO深选择512,实际使用大家根据需要自行设置就可以。Read Mode有两种方式,一个Standard FIFO,也就是平时常见的FIFO,数据滞后于读信号一个周期,还有一种方式为First Word Fall Through,数据预取模式,简称FWFT模式。也就是FIFO会预先取出一个数据,当读信号有效时,相应的数据也有效。我们首先做标准FIFO的实验。

pIYBAGAJjL6ADsfOAABnSiJw5sE934.jpg

2.1.4 切换到Data Counts栏目下,使能Write Data Count(已经FIFO写入多少数据)和Read Data Count(FIFO中有多少数据可以读),这样我们可以通过这两个值来看FIFO内部的数据多少。点击OK,Generate生成FIFO IP。

pIYBAGAJjPyAH_GBAACWnsqqP7M930.jpg

2.2 FIFO的端口定义与时序

pIYBAGAJjTuALD9oAAA8IT4wu0c489.png

FIFO的数据写入和读出都是按时钟的上升沿操作的,当wr_en信号为高时写入FIFO数据,当almost_full信号有效时,表示FIFO只能再写入一个数据,一旦写入一个数据了,full信号就会拉高,如果在full的情况下wr_en仍然有效,也就是继续向FIFO写数据,则FIFO的overflow就会有效,表示溢出。

pIYBAGAJjXmAHnzVAACKyV16h2g989.jpg

标准FIFO写时序

当rd_en信号为高时读FIFO数据,数据在下个周期有效。valid为数据有效信号,almost_empty表示还有一个数据读,当再读一个数据,empty信号有效,如果继续读,则underflow有效,表示下溢,此时读出的数据无效。

pIYBAGAJjcCAcVlpAAB7eGMlgwo632.jpg

标准FIFO读时序

而从FWFT模式读数据时序图可以看出,rd_en信号有效时,有效数据D0已经在数据线上准备好有效了,不会再延后一个周期。这就是与标准FIFO的不同之处。

pIYBAGAJjf6AcGZoAAB7qgk7TUk107.jpg

FWFT FIFO读时序

关于FIFO的详细内容可参考pg057文档,可在xilinx官网下载。

3. FIFO测试程序编写

我们按照异步FIFO进行设计,用PLL产生出两路时钟,分别是100MHz和75MHz,用于写时钟和读时钟,也就是写时钟频率高于读时钟频率。

`timescale1ns/1ps ////////////////////////////////////////////////////////////////////////////////// module fifo_test ( input clk, //25MHz时钟 input rst_n //复位信号,低电平有效 ); reg [15:0] w_data ; //FIFO写数据 wire wr_en ; //FIFO写使能 wire rd_en ; //FIFO读使能 wire[15:0] r_data ; //FIFO读数据 wire full ; //FIFO满信号 wire empty ; //FIFO空信号 wire[8:0] rd_data_count ; //可读数据数量 wire[8:0] wr_data_count ; //已写入数据数量 wire clk_100M ; //PLL产生100MHz时钟 wire clk_75M ; //PLL产生100MHz时钟 wire locked ; //PLL lock信号,可作为系统复位信号,高电平表示lock住 wire fifo_rst_n ; //fifo复位信号, 低电平有效 wire wr_clk ; //写FIFO时钟 wire rd_clk ; //读FIFO时钟 reg [7:0] wcnt ; //写FIFO复位后等待计数器 reg [7:0] rcnt ; //读FIFO复位后等待计数器 wire clkbuf ; BUFG BUFG_inst ( .O(clkbuf),// 1-bit output: Clock output. .I(clk)// 1-bit input: Clock input. ); //例化PLL,产生100MHz和75MHz时钟 clk_wiz_0 fifo_pll ( // Clock out ports .clk_out1(clk_100M), // output clk_out1 .clk_out2(clk_75M), // output clk_out2 // Status and control signals .reset(~rst_n), // input reset .locked(locked), // output locked // Clock in ports .clk_in1(clkbuf) // input clk_in1 ); assign fifo_rst_n = locked ; //将PLL的LOCK信号赋值给fifo的复位信号 assign wr_clk = clk_100M ; //将100MHz时钟赋值给写时钟 assign rd_clk = clk_75M ; //将75MHz时钟赋值给读时钟 /* 写FIFO状态机 */ localparam W_IDLE =1 ; localparam W_FIFO =2 ; reg[2:0] write_state; reg[2:0] next_write_state; always@(posedge wr_clk ornegedge fifo_rst_n) begin if(!fifo_rst_n) write_state <= W_IDLE; else write_state <= next_write_state; end always@(*) begin case(write_state) W_IDLE: begin if(wcnt ==8'd79)//复位后等待一定时间,safety circuit模式下的最慢时钟60个周期 next_write_state <= W_FIFO; else next_write_state <= W_IDLE; end W_FIFO: next_write_state <= W_FIFO; //一直在写FIFO状态 default: next_write_state <= W_IDLE; endcase end //在IDLE状态下,也就是复位之后,计数器计数 always@(posedge wr_clk ornegedge fifo_rst_n) begin if(!fifo_rst_n) wcnt <=8'd0; elseif(write_state == W_IDLE) wcnt <= wcnt +1'b1; else wcnt <=8'd0; end //在写FIFO状态下,如果不满就向FIFO中写数据 assign wr_en =(write_state == W_FIFO)?~full :1'b0; //在写使能有效情况下,写数据值加1 always@(posedge wr_clk ornegedge fifo_rst_n) begin if(!fifo_rst_n) w_data <=16'd1; elseif(wr_en) w_data <= w_data +1'b1; end /* 读FIFO状态机 */ localparam R_IDLE =1 ; localparam R_FIFO =2 ; reg[2:0] read_state; reg[2:0] next_read_state; ///产生FIFO读的数据 always@(posedge rd_clk ornegedge fifo_rst_n) begin if(!fifo_rst_n) read_state <= R_IDLE; else read_state <= next_read_state; end always@(*) begin case(read_state) R_IDLE: begin if(rcnt ==8'd59) //复位后等待一定时间,safety circuit模式下的最慢时钟60个周期 next_read_state <= R_FIFO; else next_read_state <= R_IDLE; end R_FIFO: next_read_state <= R_FIFO ; //一直在读FIFO状态 default: next_read_state <= R_IDLE; endcase end //在IDLE状态下,也就是复位之后,计数器计数 always@(posedge rd_clk ornegedge fifo_rst_n) begin if(!fifo_rst_n) rcnt <=8'd0; elseif(write_state == W_IDLE) rcnt <= rcnt +1'b1; else rcnt <=8'd0; end //在读FIFO状态下,如果不空就从FIFO中读数据 assign rd_en =(read_state == R_FIFO)?~empty :1'b0; //----------------------------------------------------------- //实例化FIFO fifo_ip fifo_ip_inst ( .rst (~fifo_rst_n ),// input rst .wr_clk (wr_clk ),// input wr_clk .rd_clk (rd_clk ),// input rd_clk .din (w_data ),// input [15 : 0] din .wr_en (wr_en ),// input wr_en .rd_en (rd_en ),// input rd_en .dout (r_data ),// output [15 : 0] dout .full (full ),// output full .empty (empty ),// output empty .rd_data_count (rd_data_count ),// output [8 : 0] rd_data_count .wr_data_count (wr_data_count )// output [8 : 0] wr_data_count ); //写通道逻辑分析仪 ila_m0 ila_wfifo ( .clk (wr_clk ), .probe0 (w_data ), .probe1 (wr_en ), .probe2 (full ), .probe3 (wr_data_count ) ); //读通道逻辑分析仪 ila_m0 ila_rfifo ( .clk (rd_clk ), .probe0 (r_data ), .probe1 (rd_en ), .probe2 (empty ), .probe3 (rd_data_count ) ); endmodule

在程序中采用PLL的lock信号作为fifo的复位,同时将100MHz时钟赋值给写时钟,75MHz时钟赋值给读时钟。

pIYBAGAJjjyAH08SAABEWaLyBm0354.jpg

有一点需要注意的是,FIFO设置默认为采用safety circuit,此功能是保证到达内部RAM的输入信号是同步的,在这种情况下,如果异步复位后,则需要等待60个最慢时钟周期,在本实验中也就是75MHz的60个周期,那么100MHz时钟大概需要(100/75)x60=80个周期。

pIYBAGAJjnuAIvdcAAEoJdFqP94664.jpg

因此在写状态机中,等待80个周期进入写FIFO状态

pIYBAGAJjsaAYLkIAACPaD2xz70893.jpg

在读状态机中,等待60个周期进入读状态

pIYBAGAJjwiAY-OnAACNns1gSpM714.jpg

如果FIFO不满,就一直向FIFO写数据

o4YBAGAJj0aAGqzQAAAjl8EkLiQ835.jpg

如果FIFO不空,就一直从FIFO读数据

pIYBAGAJj4SAK9ulAAAk-WCVGPE540.jpg

例化两个逻辑分析仪,分别连接写通道和读通道的信号

o4YBAGAJj8KAKqc3AABUidEQL1c430.jpg

4. 仿真

以下为仿真结果,可以看到写使能wr_en有效后开始写数据,初始值为0001,从开始写到empty不空,是需要一定周期的,因为内部还要做同步处理。在不空后,开始读数据,读出的数据相对于rd_en滞后一个周期。

在后面可以看到如果FIFO满了,根据程序的设计,满了就不向FIFO写数据了,wr_en也就拉低了。为什么会满呢,就是因为写时钟比读时钟快。如果将写时钟与读时钟调换,也就是读时钟快,就会出现读空的情况,大家可以试一下。

如果将FIFO的Read Mode改成First Word Fall Through

pIYBAGAJkISAR0CsAABrbYldnA8618.jpg

仿真结果如下,可以看到rd_en有效的时候数据也有效,没有相差一个周期

5. 板上验证

生成好bit文件,下载bit文件,会出现两个ila,先来看写通道的,可以看到full信号为高电平时,wr_en为低电平,不再向里面写数据。

pIYBAGAJkQGAbZcuAACJYRezMtQ940.jpg

而读通道也与仿真一致

pIYBAGAJkT-AUdkZAACCU7BrZzs651.jpg

如果以rd_en上升沿作为触发条件,点击运行,然后按下复位,也就是我们绑定的PL KEY1,会出现下面的结果,与仿真一致,标准FIFO模式下,数据滞后rd_en一个周期。

审核编辑:何安

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1655

    文章

    22281

    浏览量

    630051
  • 测试
    +关注

    关注

    8

    文章

    6025

    浏览量

    130687
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    RDMA设计6:IP架构2

    拥塞处理及流量控制机制,如 ECN 协议或 PFC 协议。CMAC 集成块模块用以实现网络连接的物理层。CMAC 集成块是由 Xilinx 公司提供的用于 100Gb Ethernet 的高带宽、可
    发表于 11-26 10:24

    使用AXI4接口IP进行DDR读写测试

    本章的实验任务是在 PL 端自定义一个 AXI4 接口的 IP 核,通过 AXI_HP 接口对 PS 端 DDR3 进行读写测试读写的内存
    的头像 发表于 11-24 09:19 2692次阅读
    使用AXI4接口<b class='flag-5'>IP</b>核<b class='flag-5'>进行</b>DDR<b class='flag-5'>读写</b><b class='flag-5'>测试</b>

    Xilinx BRAM IP核配置及其例化

    口RAM,一口读一口写,可以实现同时读写 Simple Port RAM,单口RAM,无法实现同时读写。 True Dual Port RAM,真双口RAM ,每个端口都可以进行读和写。 其中
    发表于 10-24 06:10

    如何利用Verilog HDL在FPGA上实现SRAM的读写测试

    本篇将详细介绍如何利用Verilog HDL在FPGA上实现SRAM的读写测试。SRAM是一种非易失性存储器,具有高速读取和写入的特点。在FPGA中实现SRAM读写
    的头像 发表于 10-22 17:21 3947次阅读
    如何<b class='flag-5'>利用</b>Verilog HDL在FPGA上实现SRAM的<b class='flag-5'>读写</b><b class='flag-5'>测试</b>

    FPGA利用DMA IP核实现ADC数据采集

    本文介绍如何利用FPGA和DMA技术处理来自AD9280和AD9708 ADC的数据。首先,探讨了这两种ADC的特点及其与FPGA的接口兼容性。接着,详细说明了使用Xilinx VIVADO环境下
    的头像 发表于 07-29 14:12 4639次阅读

    【RK3568+PG2L50H开发板实验例程】FPGA部分 | ROM、RAM、FIFO 的使用

    提供 A 和 B 两个端口,两个端口均可以独立进行读写 注意,当使用真双端口时,要避免出现同时读写同个地址,这会造成写入失败,在逻辑设计上需要避开这个情况。 以下给出比较常用的 RA
    发表于 07-10 10:37

    cy7c68013a异步slave fifo模式,外部mcu无法读写fifo怎么解决?

    cy7c68013a 异步slave fifo 模式,外部mcu无法读写fifo 上位机发送bulk数据,flag标志是对的,SLCS也拉低了,是设置的低有效, 检测到了flag不为空的标志后
    发表于 06-03 10:49

    Xilinx Shift RAM IP概述和主要功能

    Xilinx Shift RAM IP 是 AMD Xilinx 提供的一个 LogiCORE IP 核,用于在 FPGA 中实现高效的移位
    的头像 发表于 05-14 09:36 820次阅读

    AN65974示例如何链接fifo_slave_block 和 video_out的IP块?

    您好,我正在研究 AN65974 pdf 用于视频数据传输,但无法正确应用。 我有用于生成 1280x720x30fps 测试图像的 ip 核心块,并且我可以在显示器上看到,所以我确信 hdmi
    发表于 05-12 07:31

    智多晶FIFO_Generator IP介绍

    FIFO_Generator是智多晶设计的一款通用型FIFO IP。当前发布的FIFO_Generator IP是2.0版本,相比之前的1.
    的头像 发表于 04-25 17:24 1458次阅读
    智多晶<b class='flag-5'>FIFO</b>_Generator <b class='flag-5'>IP</b>介绍

    AXI接口FIFO简介

    AXI接口FIFO是从Native接口FIFO派生而来的。AXI内存映射接口提供了三种样式:AXI4、AXI3和AXI4-Lite。除了Native接口FIFO支持的应用外,AXI
    的头像 发表于 03-17 10:31 1769次阅读
    AXI接口<b class='flag-5'>FIFO</b>简介

    SDRAM控制器的设计——Sdram_Control.v代码解析(异步FIFO读写模块、读写SDRAM过程)

    前言 SDRAM控制器里面包含5个主要的模块,分别是PLL模块,异步FIFO 写模块,异步FIFO读模块,SDRAM接口控制模块,SDRAM指令执行模块。 其中异步FIFO模块解读
    的头像 发表于 03-04 10:49 2173次阅读
    SDRAM控制器的设计——Sdram_Control.v代码解析(异步<b class='flag-5'>FIFO</b><b class='flag-5'>读写</b>模块、<b class='flag-5'>读写</b>SDRAM过程)

    在ADS822加FIFO测试的时候老是卡死,为什么?

    请问下专家:为什么我在ADS822加FIFO测试的时候老是卡死,基本过程是这样的,我外部提供一个时钟,分别给ADS822做采样时钟与FIFO的写时钟,程序开始控制
    发表于 02-06 06:32

    FIFO IP核的使用教程

    在数字设计中,利用FIFO进行数据处理是非常普遍的应用,例如,实现时钟域交叉、低延时存储器缓存、总线位宽调整等。下图给出了FIFO生成器支持的一种可能配置。
    的头像 发表于 01-03 09:36 4013次阅读
    <b class='flag-5'>FIFO</b> <b class='flag-5'>IP</b>核的使用教程

    DAC3482内部的FIFO作用是什么?

    我现在正在使用DAC3482芯片,想请教一下其内部的FIFO作用是什么? FIFO读写指针分别由DATACLK和DACCLK(或其分频)来驱动,用于“缓冲”的作用,我有两种理解: 1.只能缓冲
    发表于 12-23 07:06