什么是 FIFO ?
FIFO 是英文 First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加 1 完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
什么情况下用 FIFO ?
FIFO 一般用于不同时钟域之间的数据传输,比如 FIFO 的一端时 AD 数据采集,另一端时计算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps, 而 PCI 总线的速度为 33MHz ,总线宽度 32bit, 其最大传输速率为 1056Mbps, 在两个不同的时钟域间就可以采用 FIFO 来作为数据缓冲。另外对于不同宽度的数据接口也可以用 FIFO ,例如单片机位 8 位数据输出,而 DSP 可能是 16 位数据输入,在单片机与 DSP 连接时就可以使用 FIFO 来达到数据匹配的目的。
FIFO 的一些重要参数
FIFO 的宽度:也就是英文资料里常看到的 THE WIDTH ,它指的是 FIFO 一次读写操作的数据位,就像 MCU 有 8 位和 16 位, ARM 32 位等等, FIFO 的宽度在单片成品 IC 中是固定的,也有可选择的,如果用 FPGA 自己实现一个 FIFO ,其数据位,也就是宽度是可以自己定义的。
FIFO 的深度: THE DEEPTH ,它指的是 FIFO 可以存储多少个 N 位的数据(如果宽度为 N )。如一个 8 位的 FIFO ,若深度为 8 ,它可以存储 8 个 8 位的数据,深度为 12 ,就可以存储 12 个 8 位的数据, FIFO 的深度可大可小,个人认为 FIFO 深度的计算并无一个固定的公式。在 FIFO 实际工作中,其数据的满 / 空标志可以控制数据的继续写入或读出。在一个具体的应用中也不可能由一些参数算数精确的所需 FIFO 深度为多少,这在写速度大于读速度的理想状态下是可行的,但在实际中用到的 FIFO 深度往往要大于计算值。一般来说根据电路的具体情况,在兼顾系统性能和 FIFO 成本的情况下估算一个大概的宽度和深度就可以了。而对于写速度慢于读速度的应用, FIFO 的深度要根据读出的数据结构和读出数据的由那些具体的要求来确定。
满标志: FIFO 已满或将要满时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的写操作继续向 FIFO 中写数据而造成 溢出 (overflow)。
空标志: FIFO 已空或将要空时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的读操作继续从 FIFO 中读出数据而造成无效数据的读出( underflow )。
读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。
读指针:指向下一个读出地址。读完后自动加 1 。
写指针:指向下一个要写入的地址的,写完自动加 1 。
读写指针其实就是读写的地址,只不过这个地址不能任意选择,而是连续的。
FIFO 的分类
根均 FIFO 工作的时钟域,可以将 FIFO 分为同步 FIFO 和异步 FIFO 。同步 FIFO 是指读时钟和写时钟为同一个时钟。在时钟沿来临时同时发生读写操作。异步 FIFO 是指读写时钟不一致,读写时钟是互相独立的。
FIFO 设计的难点
FIFO 设计的难点在于怎样判断 FIFO 的空 / 满状态。为了保证数据正确的写入或读出,而不发生溢出或读空的状态出现,必须保证 FIFO 在满的情况下,不能进行写操作。在空的状态下不能进行读操作。怎样判断 FIFO 的满 / 空就成了 FIFO 设计的核心问题。由于同步 FIFO 几乎很少用到,这里只描述异步 FIFO 的空 / 满标志产生问题。
在用到触发器的设计中,不可避免的会遇到 亚稳态 的问题(关于亚稳态这里不作介绍,可查看相关资料)。在涉及到触发器的电路中,亚稳态无法彻底消除,只能想办法将其发生的概率将到最低。其中的一个方法就是使用格雷码。格雷码在相邻的两个码元之间只有一位变换(二进制码在很多情况下是很多码元在同时变化)。这就会避免计数器与时钟同步的时候发生亚稳态现象。但是格雷码有个缺点就是只能定义2^n的深度,而不能像二进制码那样随意的定义FIFO的深度,因为格雷码必须循环一个2^n,否则就不能保证两个相邻码元之间相差一位的条件,因此也就不是真正的各雷码了。第二就是使用冗余的触发器,假设一个触发器发生亚稳态的概率为P,那么两个及联的触发器发生亚稳态的概率就为P的平方。但这回导致延时的增加。亚稳态的发生会使得FIFO出现错误,读/写时钟采样的地址指针会与真实的值之间不同,这就导致写入或读出的地址错误。由于考虑延时的作用,空/满标志的产生并不一定出现在FIFO真的空/满时才出现。可能FIFO还未空/满时就出现了空/满标志。这并没有什么不好,只要保证FIFO不出现overflow or underflow 就OK了。
很多关于 FIFO 的文章其实讨论的都是空 / 满标志的不同算法问题。
在 Vijay A. Nebhrajani 的《异步 FIFO 结构》一文中,作者提出了两个关于 FIFO 空 / 满标志的算法。
第一个算法:构造一个指针宽度为 N+1 ,深度为 2^N 字节的 FIFO (为便方比较将格雷码指针转换为二进制指针)。当指针的二进制码中最高位不一致而其它 N 位都相等时, FIFO 为满(在 Clifford E. Cummings 的文章中以格雷码表示是前两位均不相同,而后两位 LSB 相同为满,这与换成二进制表示的 MSB 不同其他相同为满是一样的)。当指针完全相等时, FIFO 为空。这也许不容易看出,举个例子说明一下:一个深度为 8 字节的 FIFO 怎样工作(使用已转换为 二进制 的指针)。FIFO_WIDTH=8,FIFO_DEPTH= 2^N = 8,N = 3,指针宽度为N+1=4。起初rd_ptr_bin和wr_ptr_bin均为“0000”。此时FIFO中写入8个字节的数据。wr_ptr_bin =“1000”,rd_ptr_bin=“0000”。当然,这就是满条件。现在,假设执行了8次的读操作,使得rd_ptr_bin =“1000”,这就是空条件。另外的8次写操作将使wr_ptr_bin 等于“0000”,但rd_ptr_bin 仍然等于“1000”,因此FIFO为满条件。
显然起始指针无需为“ 0000 ”。假设它为“ 0100 ”,并且 FIFO 为空,那么 8 个字节会使 wr_ptr_bin = “ 1100 ”, , rd_ptr_bin 仍然为“ 0100 ”。这又说明 FIFO 为满。
在 Vijay A. Nebhrajani 的这篇《异步 FIFO 结构》文章中说明了怎样运用格雷码来设置空满的条件,但没有说清为什么深度为 8 的 FIFO 其读写指针要用 3+1 位的格雷码来实现,而 3+1 位的格雷码可以表示 16 位的深度,而真实的 FIFO 只有 8 位,这是怎么回事?而这个问题在 Clifford E. Cummings 的文章中得以解释。三位格雷码可表示 8 位的深度,若在加一位最为 MSB ,则这一位加其他三位组成的格雷码并不代表新的地址,也就是说格雷码的 0100 表示表示 7 ,而 1100 仍然表示 7 ,只不过格雷码在经过一个以 0 位 MSB 的循环后进入一个以 1 为 MSB 的循环,然后又进入一个以 0 位 MSB 的循环,其他的三位码仍然是格雷码,但这就带来一个问题,在 0100 的循环完成后,进入 1000 ,他们之间有两位发生了变换,而不是 1 位,所以增加一位 MSB 的做法使得该码在两处: 0100~1000 , 1100~0000 有两位码元发生变化,故该码以不是真正的格雷码。增加的 MSB 是为了实现空满标志的计算。 Vijay A. Nebhrajani 的文章用格雷码转二进制,再转格雷码的情况下提出空满条件,仅过两次转换,而 Clifford E. Cummings 的文章中直接在格雷码条件下得出空满条件。其实二者是一样的,只是实现方式不同罢了。
第二种算法: Clifford E. Cummings 的文章中提到的 STYLE #2 。它将 FIFO 地址分成了 4 部分,每部分分别用高两位的 MSB 00 、 01 、 11 、 10 决定 FIFO 是否为 going full 或 going empty ( 即将满或空 ) 。如果写指针的高两位 MSB 小于读指针的高两位 MSB 则 FIFO 为“几乎满”,
若写指针的高两位 MSB 大于读指针的高两位 MSB 则 FIFO 为“几乎空”。
在 Vijay A. Nebhrajani 的《异步 FIFO 结构》第三部分的文章中也提到了一种方法,那就是方向标志与门限。设定了 FIFO 容量的 75% 作为上限,设定 FIFO 容量的 25% 为下限。当方向标志超过门限便输出满 / 空标志,这与 Clifford E. Cummings 的文章中提到的 STYLE #2 可谓是异曲同工。他们都属于保守的空满判断。其实这时输出空满标志 FIFO 并不一定真的空 / 满。
说到此,我们已经清楚地看到, FIFO 设计最关键的就是产生空 / 满标志的算法的不同产生了不同的 FIFO 。但无论是精确的空满还是保守的空满都是为了保证 FIFO 工作的可靠。
源文档 < http://baike.baidu.com/view/132385.htm >
FIFO ( First In First Out) 简单说就是指先进先出。由于微电子技术的飞速发展,新一代 FIFO 芯片容量越来越大,体积越来越小,价格越来越便宜。作为一种新型大规模集成电路, FIFO 芯片以其灵活、方便、高效的特性,逐渐在高速数据采集、高速数据处理、高速数据传输以及多机处理系统中得到越来越广泛的应用。
FIFO 存储器简介
在系统设计中,以增加 数据 传输率、处理大量数据流、匹配具有不同传输率的系统为目的而广泛使用 FIFO 存储器,从而提高了系统性能。FIFO存储器是一个先入先出的双口缓冲器,即第一个进入其内的数据第一个被移出,其中一个 存储器 的输入口,另一个口是存储器的输出口。对于单片FIFO来说,主要有两种结构:触发导向结构和零导向传输结构。触发导向传输结构的FIFO是由寄存器阵列构成的,零导向传输结构的FIFO是由具有读和写地址指针的双口RAM构成。
FIFO 存储器是系统的缓冲环节,如果没有 FIFO 存储器,整个系统就不可能正常工作,它主要有几方面的功能:
1 )对连续的数据流进行缓存,防止在进机和存储操作时丢失数据;
2 )数据集中起来进行进机和存储,可避免频繁的总线操作,减轻 CPU 的负担;
3 )允许系统进行 DMA 操作,提高数据的传输速度。这是至关重要的一点,如果不采用 DMA 操作,数据传输将达不到传输要求,而且大大增加 CPU 的负担,无法同时完成数据的存储工作。
因此,选择合适的存储芯片对于提高系统性能很重要,在以往的设计中经常采用的是“乒乓型”存储方式,这种方式就是采用两片存储器,数据首先进入其中一片,当数据满时再让数据进入第二片存储器,同时通过逻辑控制,将第一片存储器中的数据取走,以此类推,两片轮流对数据进行缓存。这种方式有着较明显的缺点,首先是控制复杂,要有专门的逻辑来维护这种轮流机制 ; 其次,数据流的流向要不断变化,限制了数据流的速率,还容易产生干扰。从数据传输上说,缓存芯片容量越大,对后续时序要求就越低,可减少总线操作的频次;但从数据存储上说,就意味着需要开辟更大的内存空间来进行进行缓冲,会增加计算机的内存开销,而且容量越大,成本也越高。因此,在综合考虑系统性能和成本的基础上,选择满足系统需要的芯片即可。
FIFO 是 First In/First - Out 的缩写,是先入先出的意思。 FIFO 存储器分为写入专用区和读取专用区。读操作与写操作可以异步进行,写入区上写入的数据按照写入的顺序从读取端的区中读出,类似于吸收写入端与读出端速度差的一种缓冲器。计算机的串口,一般也都具有 FIFO 缓冲器(不是单一的 FIFO 存储器,而是嵌入在设备内部)。
FIFO 存储器的连接模式如图所示。在 FIFO 存储器而不是地址总线上附加了表示内部缓冲器状态( Buffer Full ,缓冲器已满; Buffer Empty ,缓冲器为空)的状态引脚,连接于 FIFO 的双方利用该状态进行操作的控制。另外,还设计了在接通电源及复位( Reset )或由于操作中的某些异常等原因而重新初始化(无数据状态) FIFO 的复位引脚,这可以说是 FIFO 存储器的特点。
深 入了解 FIFO