FIFO的使用非常广泛,一般用于不同时钟域之间的数据传输,比如FIFO的一端是AD数据采集,另一端是计算机的PCI总线,假设其AD采集的速率为16位100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32bit,其最大传输速率为33*32=1056Mbps,在两个不同的时钟域间就可以采用FIFO来作为数据缓冲。另外对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

本文就讲通过ISE软件生成一个FIFO,并对其进行一些操作以求更加了解FIFO中各个信号的作用以及控制方法(有些简单步骤将省略不提)。

在这步中,由于现在做的不是soc工程,选择Native.

Next后,需选择时钟和存储器类型。1,时钟,由FIFO的作用可知大部分都是读写不同步的,这里我们也选择异步模式,即读写的时钟不同。2,存储器类型,这里主要是block RAM和distribute RAM之间的区别。简而言之,block RAM是FPGA中定制的ram资源,而distribute RAM则是由LUT构成的RAM资源。由此区别表明,当FIFO较大时应选择block RAM,当FIFO较小时,选择distribute RAM.另外一个很重要的就是block RAM支持读写不同宽度,而distribute不支持。在这里为了更全面的了解FIFO,选择block RAM以拥有非对称方向速率的特性。

读模式有两种选择,一般选择标准模式,至于First-Word Fall-Fhrough的含义请查看FIFO手册。写数据宽度定义为8位,写深度定义为256.读宽度定义为4位,而读深度将根据以上几个参数自动计算。但我们需要注意的是,在data port parameters处,有actual write depth和actual read depth,他们都比我们设置的要小,其意义以及原因将在例程中说明。

之后便是添加信号,信号越多越难操作,但同时也能让我们更加准确的控制FIFO,这里为了更好的了解FIFO,把所有能选的信号都选上。

接下来是复位信号以及可编程信号的配置。虽然在block RAM和distribute RAM中,复位信号不是必需的,但根据习惯,还是启用rst端口,且配置成同步复位,即整个FIFO共用一个复位信号,而不是读写不同的复位。至于编程信号,看选项就很容易理解了。配置如图,FIFO中数据达到200时,programmable full有效,数据为10时,programmable empty有效。

之后是写计数和读计数,都使之有效,由于写深度是256,读深度是512.因此写计数器的宽度定义为8,读计数器的狂度定义为9.其实不一定计数器一定要比深度大,当计数器计数最大值小于数据深度时,例如数据深度为512,而计数器大小为256,则每两个数据计数器计数一次。

最后可以看到我们配置的FIFO信息如下(注意几个关键信息),最后生成IP就好了。

通过点击View HDL Instantiation Template,我们可以看到所有需要例化的信号,以及格式。

在该FIFO例程中,首先是将1-255写入FIFO中,此时不读取,观察各个信号,然后再从FIFO中读出FIFO中存储的数据,此时不再写入,观察各信号。

代码如下:

module FIFO_top(

input clk,rst,

output  wire [3:0] dout

);

wire clk_50M_wire;

wire [7:0] din_wire;

wire valid,wr_ack;

wire overflow,underflow;

wire almost_empty,almost_full;

wire [8:0] rd_data_count;

wire [7:0] wr_data_count;

wire prog_full,prog_empty;

wire wr_en,rd_en;

wire full,empty;

///

//二分频电路

//100M为读时钟,50M为写时钟

reg clk_50M;

assign clk_50M_wire = clk_50M ;

always @(posedge clk or posedge rst) begin

if (rst) clk_50M<=0;

else clk_50M<=~clk_50M;

end

///

reg [2:0] cnt;

assign wr_en =(full==0 && rd_en==0 && cnt==5)?1:0 ;//非满时写,且满后就不再写了,即便之后数据被读取导致非满

assign rd_en = (empty==0 && wr_en==0)?1:0 ;//写时不读取,写完再读取

reg [7:0] din;

assign din_wire = din ;

always @(posedge clk_50M or posedge rst) begin

if (rst) begin

din<=1;

end

else begin

if(wr_en) din<=din+1;

else din<=din;

end

end

always @ (posedge clk_50M or posedge rst)

if(rst) cnt<=0;

else begin

if(cnt==3'd5) cnt<=cnt;

else cnt<=cnt+1;

end

FIFO FIFO (

.rst(rst), // input rst

.wr_clk(clk_50M_wire), // input wr_clk 50M

.rd_clk(clk), // input rd_cFIFOlk 100M

.din(din_wire), // input [7 : 0] din

.wr_en(wr_en), // input wr_en

.rd_en(rd_en), // input rd_en

.dout(dout), // output [3 : 0] dout

.full(full), // output full

.almost_full(almost_full), // output almost_full

.wr_ack(wr_ack), // output wr_ack

.overflow(overflow), // output overflow

.empty(empty), // output empty

.almost_empty(almost_empty), // output almost_empty

.valid(valid), // output valid

.underflow(underflow), // output underflow

.rd_data_count(rd_data_count), // output [8 : 0] rd_data_count

.wr_data_count(wr_data_count), // output [7 : 0] wr_data_count

.prog_full(prog_full), // output prog_full 200

.prog_empty(prog_empty) // output prog_empty 10

);

endmodule

1,复位信号rst: 由结果可知,其为高电平有效,且复位后其他信号的初始值是可以在产生FIFO中配置的,之前配置为0;很重要的一点是,复位后的几个写周期内(2,3个周期)是无法进行写操作的,所以在本例程中,复位一段时间后再拉高wr_en以确保首先写入的是1.

2,写使能信号wr_en与写响应信号wr_ack:关于该信号,很重要的一点是,写入的值是wr_en拉高时的值;还是说当wr_en拉高后,下一周期才能进行写操作?如果是前者,由波形所示,写入的第一个值应该是1;如果是后者,写入的应该是2。这就需要根据读取的第一个值来判断了。而经查看,读取的第一个值为1,也就是说,只要wr_en拉高,立马就进行写操作。

从下图还能明白wr_ack的工作模式,即写入成功时,wr_ack将在下一周期拉高。也就是说,wr_ack反映的是上一周期的写操作。

3,读使能信号rd_en与读响应信号valid:在读操作中,第一个读取的数据应该是0,第二个是1(原因之后解释)。由波形可知,当rd_en有效的那个上升沿,并没有进行读操作,而是在下一个周期才真正读取了数据,同时valid被拉高,这是与写操作所不同的地方。

4,写计数wr_data_count和rd_data_count:因为写数据会有256个,读数据会有512个,一旦count的大小不够,count从一开始就会失效,成为高阻态,所以应该给wr_data_count设置成8位,rd_data_count设置成9位。当把wr_data_count设置成7位,rd_data_count设置成8位时,结果见图。

正常设置时,即wr_data_count设置成8位,rd_data_count设置成9位。

在写的过程中,可以看到,wr_data_count正常计数,每次加一,但是其值滞后2个周期。而由于读操作是每次4位,写操作是每次8位,即每次写操作都意味着需要读两次才能读出数据,所以每次写操作,rd_data_count都是加2。

在读过程中,rd_data_count是每次减1。同理,wr_data_count则是每2次读操作才减1。

对于这两个信号,也有不太正常的地方。如下图,当进行了读操作的时候,wr_data_count依旧保持在255不变,rd_data_count则在505和504之间切换,且其最大值不是预期的510.

可能的原因在于wr_data_count是属于写时钟域的,读操作进行后需要一段时间才能反映到写时钟域的各个参数,这在之后的empty等信号也可以得出类似结论。

至于rd_data_count应该是受读操作以及full或者wr_data_count等信号的共同影响,导致其在505和504之间不停变换。

官方文档也提到说,wr_data_count以及rd_data_count是大概的,不是非常准确。

5,prog_full;almost_full;full:Prog_full在之前的设置中是200,该值是根据wr_data_count判定的,即当wr_data_count为200时,prog_full置一。但是由于wr_data_count滞后2个周期,所以真正写入到FIFO中的值应该有202个了。

full以及almost_full由图可知,在数据数满足要求后的下一个周期被拉高。而且当读操作进行后,这两个信号并不是立刻被拉低,和之前所提到的一样,这两个信号属于写时钟域,读操作反映到这两个信号上需要一定的时间

6,prog_empty;almost_empty;empty:

Prog_empty之前设置的是10,由波形图知,其信号还是比较准确的。

Almost_empty以及empty则提早了一个周期被拉高

也可以看到,当写操作进行时,empty等信号也不是立刻变低的,其原因也应该是属于不同时钟域。

7,underflow;overflow: 改动程序,使写信号一直有效,可以看到当full变高后的下一周期因为继续进行写操作,使得overflow也被拉高。

再改动程序,写操作一段时间后,读信号一直有效。可以看到当empty有效后,继续读操作,underflow将在下一周期被拉高。

8,关于FIFO实际读写深度的问题:在之前的设置中可以看到,我们原本设置的写深度是256,读深度是512;但是边上显示的实际读写深度分别是255,510.从结果中我们也可以看到:当写到255时(数据是1~255),full被拉高。读数据以及读数据深度是根据写数据和写深度来的,自然也就是510了。也就是说实际写深度会比设置的小1,这是在工程中需要注意的地方。

9,关于读写不对称的问题:所谓的读写不对称,即读写的位大小以及读写速率不一样。在本例程中,写入的数据是8位的,而读出的数据是4位的。那么读操作的时候是怎么样一个读出法呢?在写操作中,我们是顺序写入1~255的。通过观察读数据可知,读出的数据为:0,1,0,2,0,3……这就说明当读写非对称时,是先读取数据的高位的。

10,关于FIFO的深度计算问题:在很多笔试面试中,都会问的FIFO的深度计算问题。因此,了解这方面也是很有必要的。

网上有很多关于这方面的公式,在此就不做讨论了。其实很简单,只要先计算单位时间内读写数据量的差值,然后乘以持续时间,就是FIFO的最小深度了。但是这里还需要注意几点:

1,背靠背问题,假设写数据100个wr_clk内写入80个数据,这时就需要考虑最坏的情况,就是前20个时钟不写入,接着80个时钟写入,再后来的80个时钟继续写入,最后的20个时钟不写入。这样写入数据最集中的情况就有160个时钟写入160个数据了。

2,需要留有深度裕量,即实际的深度会比设置的小,因此应该多设置点FIFO深度,以避免丢失数据。

转载于:https://www.cnblogs.com/flyuea/p/8417280.html

xilinx FIFO的使用及各信号的讨论相关推荐

  1. Xilinx FIFO使用小结

    FIFO的使用非常广泛,一般用于不同时钟域之间的数据传输,或者用于不同数据宽度之间的数据匹配.在实际的工程应用,可以根据需要自己写FIFO.不考虑资源的情况下,也可以使用Xilinx提供的IP核来完成 ...

  2. Xilinx fifo研究总结

    最近数据缓存方面用到了较多的fifo,发现Xilinx的fifo的depth.rdcnt.full flag等参数的时序会因为fifo的种类(standard or fwft).时钟(dc or si ...

  3. (42)Xilinx FIFO IP核配置(三)(第9天)

    (42)Xilinx FIFO IP核配置(三)(第9天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)Xilinx FIFO IP核配置(三)(第9天) 5) ...

  4. 关于SIGHUP信号的讨论

    参考链接: <Linux终端关闭后台进程也结束原因分析和nohup的使用> <理解SIGHUP产生的过程> <Linux shell 退出后任务仍然运行引发的探究> ...

  5. Xilinx FIFO IP核使用

    0 文章目录 1)FIFO简介 2)FIFO接口说明 3)FIFO IP定制 4)FIFO IP参数说明 5)FIFO IP仿真 6)FIFO使用经验 6)结束语 1 FIFO简介 1)FIFO是英文 ...

  6. xilinx FIFO

    1.FIFO复位问题 摘自<FIFO Generator v9.3  PG057 December 18, 2012 >P126

  7. XILINX FPGA数字信号处理——13、信号同步原理实现

  8. ISE_FIFO_IP核接口测试(一)

    引荐博文: xilinx FIFO的使用及各信号的讨论 Xilinx ISE FIFO读写操作仿真学习 这两篇博文都很好,一共介绍了两种比较全面的fifo数据接口测量方案. 下面进行博主自己的fifo ...

  9. FPGA逻辑设计回顾(6)多比特信号的CDC处理方式之异步FIFO

    文章目录 前言 异步FIFO的概念 异步FIFO为什么可以解决CDC问题? 异步FIFO的RTL实现 参考资料 前言 异步FIFO是处理多比特信号跨时钟域的最常用方法,简单来说,异步FIFO是双口RA ...

  10. Xilinx IP解析之FIFO Generator v13.2

    一. IP概述 可参考Xilinx官网fifo_generator概述, 以下翻译自官网此IP的概述. 产品描述: LogiCORE™IP FIFO生成器内核生成经过充分验证的先进先出(FIFO)内存 ...

最新文章

  1. 如何避免重构带来的危险
  2. SpringBoot+Vue+Itext实现前端请求文件流的方式下载PDF
  3. php时间转分钟前,PHP把时间转换成几分钟前几小时前几天前
  4. Qt文档阅读笔记-QWebView官方解析与实例
  5. 特征工程系列之降维:用PCA压缩数据
  6. 用JAVA使用mysql命令操作导入SQL脚本
  7. POJ 1191 棋盘分割(区间DP)题解
  8. IDEA代码行宽设置
  9. 阿里云云计算助理工程师认证(ACA)50个资源合集和备考题库
  10. 如何方便手机在线抖音去水印更有热门技巧
  11. mysql 怎么加读锁_MYSQL—加写锁,加读锁,解锁
  12. 一部手机必须能用 7 年?苹果、三星、Google:三年支持差不多!
  13. Java Web三大组件
  14. 在线的棋牌类网络游戏java服务端实现
  15. 血仍未冷——写在37岁生日
  16. Android游戏开发学习笔记(三):视频的播放
  17. 牛腩新闻发布--本地超链接打不开
  18. 小学计算机四年级教学计划,小学信息技术四年级第二学期教学计划
  19. 【BZOJ2002】【HNOI2010】弹飞绵羊(LCT)
  20. 大学应用计算机二级,大学计算机二级ps考试试题内容(3)

热门文章

  1. PyQt+QtDesigner及相关插件的安装和设置
  2. 帆软查询前后鼠标进入到某个位置隐藏或显示参数面板
  3. 帆软动态分页之多数据集层式报表
  4. 三星a9s参数_三星A9s配置怎么样 三星A9s参数配置介绍
  5. matlab按图像边缘抠图_12. 泊松图像编辑
  6. android中得到屏幕的高宽(像素)
  7. 项目的升级-给RemoveButterKnife插件增加新功能
  8. nagios 监控slave(check_mysql_health插件)
  9. js中的innerText、innerHTML、属性值、value与jQuery中的text()、html()、属性值、val()总结...
  10. Laravel学习笔记之Demo1——URL生成和存储