文章目录

  • 写在前面
  • 1.FIFO的定义以及为什么要用FIFO、FIFO的分类
    • 1.1什么是FIFO
    • 1.2为什么要用FIFO
    • 1.3FIFO的分类
  • 2.异步FIFO的工作原理
    • 2.1FIFO的结构
    • 2.2FIFO的工作流程
  • 3.FIFO的空满判断
    • 3.1亚稳态介绍及亚稳态的危害[8]
    • 3.2FIFO为什么要使用格雷码代替二进制
      • 3.2.1格雷码与二进制的转换
      • 3.2.2 FIFO使用格雷码代替二进制表示地址的原因[7]
    • 3.3 如何判断FIFO的空满
    • 3.4 FIFO的虚空虚满[2]
  • 参考资料

写在前面

本人在今天学习FIFO之前,对FIFO的了解仅限于它的名字,First in First out,一些博客中提及异步FIFO要比同步FIFO更加复杂,所以就头铁地直接开始学习异步FIFO。本篇文章是在学习了一些视频教程并阅读了一些其他博客之后,总结得到的,所以如果有不对的地方或者不完善的地方欢迎大家在评论区里指出,我会及时更改。

本文所涉及到的参考博客和参考视频都会列在文章末尾,需要的同学可以去阅读。另外本文并未涉及到异步FIFO的Verilog实现,之后我会去学习一些开源代码,尝试实现。

1.FIFO的定义以及为什么要用FIFO、FIFO的分类

1.1什么是FIFO

FIFO即first in first out,是先进先出的数据缓存器,类似于C++中的queue,只能通过内部读写指针来顺序地写入数据,顺序地读出数据,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
在FPGA中生成FIFO有两种方式:

  • 当所需要的FIFO较小时,可以使用分布式RAM(distributed RAM)或者寄存器来生成,通常一个基于寄存器生成的FIFO的深度为32字节(即可以存储32个数据)
  • 当所需要的FIFO较大时,可以使用嵌入式存储单元(也称Block RAM或简称为BRAM)来生成。BRAM 由一定数量固定大小的存储块构成的。

1.2为什么要用FIFO

FIFO是系统的缓冲单元,如果没有FIFO存储器,整个系统就不可能正常工作。
FIFO的功能可以概括为
(1)对连续的数据流进行缓存,防止在进机和存储操作时丢失数据;
(2)数据集中起来进行进机和存储,可避免频繁的总线操作,减轻CPU的负担;
(3)允许系统进行DMA操作,提高数据的传输速度。这是至关重要的一点,如果不采用DMA操作,数据传输将达不到传输要求,而且大大增加CPU的负担,无法同时完成数据的存储工作。

FIFO可以用来跨时钟域进行数据传输(FIFO写满再读) (图片来自BV1ci4y1T7KY)

FIFO可以用来在不同不同宽度的数据接口间进行数据传输

1.3FIFO的分类

FIFO可分为同步FIFO和异步FIFO,顾名思义,同步FIFO 是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作;异步FIFO 指读写时钟不一致,读写时钟互相独立。

2.异步FIFO的工作原理

随着现代集成电路芯片设计规模的不断扩大,一个系统中往往含有数个时钟。多时钟域带来的一个问题就是,如何设计异步时钟之间的接口电路。异步FIFO是解决这个问题的一种简便方案。使用异步FIFO可以在两个不同时钟系统之间快速方便地传输实时数据。在网络接口、图像处理等方面,异步FIFO得到了广泛的应用。

2.1FIFO的结构


上图中的信号解释如下:
wfull: 满标志, 表示FIFO已经满,不能再写入数据。
rempty:空标志,表示FIFO已经空,不能再读取数据。

wclk: 写时钟
rclk: 读时钟

winc: 写使能
rinc: 读使能

rptr: 读指针,总是指向当前要被读出的数据,复位时,指向第1个单元(编号为0)
wptr: 写指针,总是指向下一个将要被写入的单元,复位时,指向第1个单元(编号为0)

wdata:写数据
rdata: 读数据

wrst_n: 写复位
rrst_n:读复位

wq2_rptr: 输出到全判断模块的格雷码地址指针
rq2_wptr: 同步模块传入的写指针

FIFO的重要参数
FIFO的宽度:FIFO一次读写操作的数据位数(比如一次读/写8位二进制数);
FIFO的深度:FIFO可以存储多少个N位的数据(如果宽度为N)

如果觉得上图太过复杂,可以看看下图[6]:

2.2FIFO的工作流程

从以上两张图片中可以得知,FIFO是一块双端口的内存。一个端口由发送者控制,用于写入数据;另一个端口由接收者控制,用于读取数据。发送者和接收者各自维护一套FIFO的状态: empty、full,然后根据状态进行存取数据的操作。

FIFO的状态是由读指针和写指针之间的运算和比较决定的。但这两个指针处于不同的时钟城,不能在一个时钟域直接使用另一个时钟域的指针,所以需要把这两个指针同步到对应的时钟域再进行比较。

当地址以二进制来记录表示时:
当有16个数据时,需要有4个bit来表示地址,这样2^4==16,才能将地址和数据一一对应起来。但是下图中为什么有5个二进制位呢?因为我们需要有一个进位来辅助我们判断FIFO的状态,是读空了还是写满了。故而地址指针位数 = 表示数据的二进制位数 + 1,以下图为例则为4 + 1 = 5

对于FIFO而言,当FIFO为空时,写指针和读指针完全相等(00000==00000),表示FIFO为空,然后不断地向FIFO中写入数据,写指针不断自增1,直至将FIFO写满(wptr = 10000, rptr=00000,读指针追上了写指针)。FIFO写满后,便不能再写入,读指针开始不断地读数据,读指针不断自增1,当将FIFO读空后(wptr = 10000, rptr=10000),写指针自下而上不断重新写入,直至写满(wptr = 00000, rptr=10000),循环往复。

上图来自BV1DF411u7DA,可以去看看小姐姐录的课程,讲的很不错。

满空信号的生成:
1、读空信号是在读时钟域生成的,从而保证能够实时的没有延迟的确定读空;
当读空发生时,是读指针追赶上写指针,两个指针值相同(包括最高位),此时其格雷码也是相同的。

2、写满信号是在写时钟域生成的,从而保证能够实时的没有延迟的确定写满;
当写指针追赶上读指针的时候发生,此时两个指针的二进制计数器的低(n-1)位相同,最高位不同。但是由于扩展了格雷码,而对于n位格雷码,其(n-1)位是关于中间值镜像对称的。

简单地直接把二进制的指针从一个时钟域锁存到另一个时钟域,这样是有问题的。例如写指针当前位置是4’b0111, 把它同步到接收者的时钟域,在接收者锁存的时候,如果写指针变为4’b1000,那么接收者实际锁存到的值可能是4’0000~4’b1111 之间的任意一一个, 因为在锁存时每一位都在变化着。

为了解决同步指针的问题,就要使用格雷码传递指针。因为对格雷码每次做加1或减1操作时只能改变其中的一位,所以对格雷码使用同步器,格雷码的每次改变只会导致一根信号线发生改变。于是就消除了数据通过同步器时的错误情况。在传递指针时,要把二进制的指针变换到格雷码的指针并保存到寄存器中,在新时钟域同步后,再把格雷码的指针变换到二进制的指针,最后计算比较生成FIFO的状态。

3.FIFO的空满判断

3.1亚稳态介绍及亚稳态的危害[8]

亚稳态指的是FPGA内部触发器的输出未知或不确定的状态。

左边这是一个触发器的模型。假设一开始输入D的逻辑电平为0,时钟CLK的逻辑电平为0,A节点上的逻辑电平为1,B节点上的逻辑电平为0。此时如果输入D从0变到1,按照我们学过的数电模电知识,A也应该相应的从1变到0,B应该相应的从0变到1,但是要注意逻辑0与逻辑1只是模拟值的一个区间,这个跳变不是瞬间完成的,而且跳变要经过中间未定义的模拟电平值。下面是一个TTL模拟电平与数字电平的示例,2V5V代表逻辑电平1,0V0.8V代表逻辑电平0,中间的0.8V~2V没有定义,不妨称之为“模糊电平”。

如果此时CLK突然产生了一个上升沿,“时钟门”相当于就被关闭了(如右边所示),A与B由于还没完成跳变,就处在了“模糊电平”,需要一定的时间才能恢复到明确定义的逻辑电平,此时就引起了亚稳态。

上面是对这个触发器的仿真结果。横轴是仿真时间,纵轴是仿真的电压值。输入的跳变边缘分别以100ps为步长进行移动,可以非常明显的看到,一方面输出会有较长时间处于不明确的电压值,另一方面,最后的输出结果也是不确定的。
可以看出来,由于输入与clk的变化不同步而导致了亚稳态。所以从宏观角度来说,亚稳态的产生是由于输入的异步性。


[公式] :表示的是在时钟上升沿到来前数据需要保持稳定的最小时长。
[公式] : 表示的是在时钟上升沿到来后数据需要保持稳定的最小时长。
[公式] ​(clock−to−output):表示的是在时钟到来,这么长时间的延迟之后寄存器输出的数据就可以被读取了(即此时的输出数据是稳定的)
正常情况下,在时钟边沿到来之前,触发器的输入要维持一个最小的时长[公式],同样的也要在时钟边沿到来之后维持一个最小的时长[公式],并且要想得到一个平稳的正确的输出,要在时钟上升沿到来后等待一个[公式]。图中的时序就明显不符合这个要求,在 [公式] 还没结束的时候时钟就产生了时钟上升沿,导致的明显结果就是信号输出变化稳定到固定的0或者1状态的时间远超过了寄存器的固有 [公式] ,如果输出信号输入到的后级在进行信号捕获时,信号的输出变化还没有稳定,那么就会对后级产生影响,这样就会对整个电路系统带来不可预知的危害。

3.2FIFO为什么要使用格雷码代替二进制

3.2.1格雷码与二进制的转换

格雷码(Gray Code) 在数电里大家应该都学过,很熟悉了。
所谓格雷码就是任意相邻两个数字的代码只有一位二进制数不同的编码。
下图是维基百科上4位二进制数的二进制编码及格雷码编码的表格:


普通n位2进制数转换为n位格雷码(最低位下标由0开始)
1.最高位不变,G(n-1) = B(n-1)
2. G(i) = B(i) ⊕\oplus⊕ B(i+1) \space\space\space\space\space\space\space\space\space          (0<=i<=n−2)(0<=i<=n-2)(0<=i<=n−2)

以B=4′b1001B = 4'b1001B=4′b1001转换为G=4′g1101G = 4'g1101G=4′g1101 (此处4’g代表4位格雷码,是为了简便而做的记法)为例:
G[3]=B[3]=1G[2]=B[3]⊕B[2]=1G[1]=B[2]⊕B[1]=0G[0]=B[1]⊕B[0]=1G[3] = B[3] = 1 \\ G[2] = B[3] \oplus B[2] = 1 \\ G[1] = B[2] \oplus B[1] =0 \\ G[0] = B[1] \oplus B[0] =1 G[3]=B[3]=1G[2]=B[3]⊕B[2]=1G[1]=B[2]⊕B[1]=0G[0]=B[1]⊕B[0]=1

n位格雷码转换为普通n位2进制数(最低位下标由0开始)
1.最高位不变,B(n-1) = G(n-1)
2. B(i) = B(i+1) ⊕\oplus⊕ G(i) \space\space\space\space\space\space\space\space\space          (0<=i<=n−2)(0<=i<=n-2)(0<=i<=n−2)

以G=4′g1011G = 4'g1011G=4′g1011转换为B=4′b1101B = 4'b1101B=4′b1101 为例:
B[3]=G[3]=1B[2]=B[3]⊕G[2]=1B[1]=B[2]⊕G[1]=0B[0]=B[1]⊕G[0]=1B[3] = G[3] = 1 \\ B[2] = B[3] \oplus G[2] = 1 \\ B[1] = B[2] \oplus G[1] =0 \\ B[0] = B[1] \oplus G[0] =1 B[3]=G[3]=1B[2]=B[3]⊕G[2]=1B[1]=B[2]⊕G[1]=0B[0]=B[1]⊕G[0]=1

3.2.2 FIFO使用格雷码代替二进制表示地址的原因[7]

异步FIFO使用格雷码的唯一目的就是:
即使在亚稳态进行读写指针抽样也能进行正确的空满状态判断

二进制数在增减时,经常发生多位突变,比如6位地址111111会在下一时刻变成000000,在实际电路中,这个变化过程要持续很长一段时间,会由111111经历6个状态转移到达000000。比如111111-> 101111 -> 100111 ->100110 -> 100100 -> 000100-> 000000。
由于写时钟与读时钟不同步,异步的写时钟很可能会在状态不稳定的中间某个状态抽样,这样就会得到错误的读指针,进而做出错误的状态判断,导致系统异常。而且由于多位同时突变,凭借概率论常识可知发生错误的可能性很大。

那么怎样才能避免这个问题的发生呢?显然,在中间状态抽样,这个是不可避免的,这是异步系统天生的缺陷。我们的目标是:即使在中间状态抽样,也要不影响空满状态的判断

符合这个要求的编码方法是每次只能有1个比特发生改变。这样当只有一个比特发生改变时,即使在中间状态抽样,其结果也不外乎两种:递增前原指针和递增后新指针。显然递增后新指针是最新情况的反映,如果抽样到这个指针,那么和我们的设计预期是一致的,如果抽样到递增前的原指针,会有什么结果呢?假设现在抽样读指针,那么最坏的情况就是把“不满”判断成了“满”,使得本来被允许的写操作被禁止了,但是这并不会对逻辑产生影响,只是带来了写操作的延迟。同样的,如果现在抽样写指针,那么最坏的情况就是把“不空”判断成了“空”,使得本来被允许的读操作被禁止了,但是这也不会对逻辑产生影响,只是带来了读操作的延迟。

显然每次只变化1比特的编码方案可以有效解决中间状态下空满状态的判断问题,格雷码就是这样的一种编码。
格雷码每次只有一位跳变,但也需要使用两级寄存才安全。如果产生了亚稳态,使用两级寄存器后数据很大概率会回到某一个稳定状态,防止亚稳态传播。

在异步的FIFO中,采用格雷码进行计数,相邻的数据仅仅只有1bit变化,这样在两个时钟域同步的时候仅仅可能只有1bit产生亚稳态,通过同步以后,亚稳态可以消除,最坏的情况是这1bit采错,但是即使是采错地址也只是相差1个,这对判断空满标志不会产生影响。

3.3 如何判断FIFO的空满

使用格雷码判断FIFO空:读写指针分别指向的地址对应的格雷码完全相同
使用格雷码判断FIFO满:读写指针分别指向的地址对应的两个格雷码最高位和次高位不同,其余位相同,则认为FIFO满例如使用4位二进制表示地址以与数据一一对应,wptr=11000(格雷码),rptr=00000(格雷码),两者最高位与次高位不同,其余位相同,认为FIFO满。

3.4 FIFO的虚空虚满[2]

FIFO的虚空和虚满不会影响FIFO的功能,还可以增加FIFO的安全性。
同步FIFO可以使用计数方式来判断空满,但是异步FIFO不能,因为写指针和读指针根本不在同一个时钟域,计数器无法处理这样的计数。
由于读写指针不在同一个时钟域,二者需要同步到同一个时钟域后进行判断大小。
具体的操作就是在各自的时钟域内进行读写操作,同时:

1.判断是否写满时,需要将读指针转换成格雷码形式,再同步到写时钟域,与写指针比较,判断是否写满!
这里存在一个小问题,当读指针转换成格雷码以及同步到写时钟域的过程中,读写指针可能还都在递增,这样的话,等同步后的读指针与写指针相等时(不包括最高位),实际的读指针可能已经变了,这样的话其实还有几个空间没有写满!但这样设计就有问题吗?没有问题!这叫保守设计,可以增加FIFO的安全性。
下面是判断是否写满的示意图:

上面是写满判断的情况,下面为读空判断的可能情形:
2.当判断是否读空时,需要把写指针同步到读时钟域,具体过程是先将写指针转换为格雷码,再同步到读时钟域,之后和读指针比较,如果二者相等,则空标志置位!
还是和第一种情况有同样的问题,当写指针转换成格雷码以及同步到读时钟域的过程中,写指针和读指针都可能还在递增,这样当二者判断相等的时候,则写指针可能还多写了几个空间,实际上并没有读空。
这样操作有问题吗?同样没有问题,这样也保证来了FIFO的安全,防止被读空。
下面给出手绘示意图:

参考资料

1.https://www.cnblogs.com/streetlive/p/12872619.html
2.FPGA基础知识极简教程(4)从FIFO设计讲起之异步FIFO篇
3.FPGA中常用资源介绍
4.VHDL Register based FIFO
5.一文看懂FIFO
6.FIFO设计-异步FIFO篇
7.异步FIFO为什么要使用格雷码(笔记)
8.深入理解FPGA中的亚稳态概念
9.Synchronizers: A Tutorial

【FPGA学习记录1】异步FIFO的介绍相关推荐

  1. IC学习笔记3——异步FIFO

    IC学习笔记3--异步FIFO 异步FIFO的工作内容与同步FIFO类似,但是异步FIFO的控制并不像同步FIFO那么简单,因为异步FIFO工作在不同的时钟域,这将会带来一些问题,比如空满检测?是否还 ...

  2. FPGA学习记录(5)<低通带通FIR滤波器FPGA实现>

    目录 Matlab仿真低通的FIR滤波器BLACKMAN窗并使用FPGA实现 (1)FIR&IIR介绍 (2)FIR的FPGA实现与matlab仿真(FIR&BLACKMAN窗& ...

  3. FPGA学习记录——VGA的一些使用(一)

    参考书目:<FPGA Verilog开发实战指南--基于Xilinx Artix7>.<FPGA Verilog开发实战指南--基于Altera EP4CE10>. 参考视频: ...

  4. FPGA学习记录 ACX720 Vivado

    第一次写文章,目的是为了记录一下自己的学习过程(纯新手).加油!努力不会被辜负! 今天生成38译码器bit文件的时候出错了.有两个error.然后翻译了一下英文,发现是分配引脚出了问题,然后点了ope ...

  5. [FPGA 学习记录] FPGA 开发环境的搭建

    FPGA 开发环境的搭建 文章目录 一.Quartus II 主体软件安装[^1][^2] 1.1 选择软件安装位置 1.2 找到安装包存放位置 1.3 运行安装程序 1.4 开始安装 1.5 安装位 ...

  6. eBPF学习记录(一)eBPF介绍

    一.什么是eBPF eBPF, 从它的全称"扩展的伯克利数据包过滤器 (Extended Berkeley Packet Filter)" 来看,它是一种数据包过滤技术,是从 BP ...

  7. 对应猎豹网校的lua 视频教程 做的学习记录 前三课简单介绍1-3

    假设有一个1.lua 位置在 c:\Users\Administrator\Documents\lua\1.luafunction fact(n)if n==0 thenreturn 1elseret ...

  8. 异步fifo with 读控制

    之前做LDPC编码器时,学习了一下异步FIFO的相关知识,主要参考了http://www.cnblogs.com/aslmer/p/6114216.html,并在此基础上根据项目需求,添加了一个读控制 ...

  9. ASP.NETCore学习记录(一)

    ASP.NETCore学习记录(一) asp.net core介绍  Startup.cs  ConfigureServices  Configure  0. ASP.NETCore 介绍 ASP.N ...

最新文章

  1. apache-shiro杂记(三) 用了apache-shiro后,HttpSession.getServletContext() API无法正常工作了...
  2. 送给 Java 程序员的 Spring 学习指南
  3. .gitignore文件将已经纳入版本管理的文件删除
  4. php 基础知识 常见面试题
  5. tostring会空指针吗_追了多年的开发框架,你还认识指针吗?
  6. 服务器安装 accessdatabaseengine_.net IIS 服务器环境配置
  7. Linux vsftpd配置大全
  8. Unity使用Remote直接在手机上调试游戏
  9. 让对应背景随着轮播的图片变化而改变
  10. pytorch中tensor.topk
  11. Realtek 1296 (RTD1296) OpenWRT Android 双系统全功能开发板
  12. 51单片机c语言程序执行顺序,51单片机程序执行流程详细分析
  13. sicp3.5.2、3.5.3节部分习题尝试解答
  14. 微信企业号和微信公众号使用js-sdk说明和注意事项
  15. java excel 导入 格式转换_【转】JAVA实现EXCEL的导入和导出(二)
  16. 为什么编程入门很多人都会推荐Java?
  17. 个人对PIN码的基本理解
  18. Windows10下Vmware15.5虚拟机安装苹果的10.15.5(19F96)CDR镜像
  19. java 网页防止刷赞_李洋
  20. matlab 除了cov,matlab中cov的处理方法

热门文章

  1. spring boot多数据库数据源启动报错“required a single bean, but 2 were found”的正确解决办法
  2. 大学里软件工程专业学习的主要课程
  3. 七夕祝福网页制作_程序员怎么过七夕?
  4. 一经度是多少公里?一纬度是多少公里
  5. 非接环境(PPSE)和接触环境(PSE)的FCI有什么区别
  6. 接雨水---LeetCode----(20)--左右夹逼法
  7. 4-2 JSP ajax jstl
  8. 捋一捋人工智能(AI)、机器学习(ML)、深度学习(DL)之间的关系
  9. 中国宠物用品品牌“Touchdog它它”完成数千万元Pre-A 轮融资
  10. MYSQL自增的问题