FIFO数据缓存器:
FIFO (First Input First Output) 一种先进先出的数据缓存器,先进入的数据先从FIFO缓存器中读出,与RAM相比没有外部读写地址线,使用比较简单,但只能顺序写入数据,顺序的读出数据,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
FIFO数据缓存器的作用:
FIFO一般用于不同时钟域之间的数据传输,比如FIFO的一端是AD数据采集,另一端为PCI总线,那么在两个不同的时钟域间就可以采用FIFO来作为数据缓冲。另外对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。
FIFO数据缓存器按工作时钟域分类:
根据FIFO工作时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作;异步FIFO是指读写时钟不一致,读写时钟是互相独立的。对于异步FIFO一般有两种理解,一种是读写操作不使用时钟,而是直接采用wr_en(Write Enabled)和rd_en(Read Enabled)来进行控制;另一种,是指在FPGA和ASIC设计中,异步FIFO具有两个时钟的双口FIFO, 读些操作在各自的时钟延上进行,在两个不同时钟下,可以同时进行读或写。异步FIFO在FPGA设计汇总占用的资源比同步FIFO大很多,所以尽量采用同步FIFO设计。然而对于ARM 系统内绝大部分外设接口都是异步 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中写数据而造成溢出(Overflow)。 |
FIFO空标志 |
FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(Underflow)。 |
FIFO读时钟 |
读操作所遵循的时钟,在每个时钟沿来临时读数据。 |
FIFO写时钟 |
写操作所遵循的时钟,在每个时钟沿来临时写数据。 |
FIFO读指针 |
指向下一个读出地址,读完后自动加1。 |
FIFO写指针 |
指向下一个要写入的地址的,写完后自动加1。 |
FIFO数据缓存器设计的难点:
FIFO数据缓存器设计的难点在于怎样判断FIFO的空/满状态。为了保证数据正确的写入或读出,而不发生益处或读空的状态出现,必须保证FIFO在满的情况下,不能进行写操作。在空的状态下不能进行读操作。怎样判断FIFO的满/空就成了FIFO设计的核心问题。
Vijay A. Nebhrajani的《异步FIFO结构》一文中,提出了两个关于FIFO空/满标志的算法。
算法一:构造一个指针宽度为N+1,深度为2^N字节的FIFO(为便方比较将格雷码指针转换为二进制指针)。当指针的二进制码中最高位不一致而其它N位都相等时,FIFO为满(在Clifford E. Cummings的文章中以格雷码表示是前两位均不相同,而后两位LSB相同为满,这与换成二进制表示的MSB不同其他相同为满是一样的)。
举例说明:一个深度为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的概念、应用及其结构,然后分析实现异步FIFO的难点问题及其解决办法;在传统设计的基础上提出一种新颖的电路结构并对其进行综合仿真和FPGA实现。
关键词:异步电路 FIFO 亚稳态格雷码
1 异步FIFO介绍
在现代的集成电路芯片中,随着设计规模的不断扩大,一个系统中往往含有数个时钟。多时钟域带来的一个问题就是,如何设计异步时钟之间的接口电路。异步FIFO(First In First Out)是解决这个问题一种简便、快捷的解决方案。使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据。在网络接口、图像处理等方面,异步FIFO得到了广泛的应用。
异步FIFO是一种先进先出的电路,使用在需要产时数据接口的部分,用来存储、缓冲在两个异步时钟之间的数据传输。在异步电路中,由于时钟之间周期和相位完全独立,因而数据的丢失概率不为零。如何设计一个高可靠性、高速的异步FIFO电路便成为一个难点。本文介绍解决这一问题的一种方法。
由图1可以看出:整个系统分为两个完全独立的时钟域——读时钟域和写时间域;FIFO的存储介质为一块双端口RAM,可以同时进行读写操作。在写时钟域部分,由写地址产生逻辑产生写控制信号和写地址;读时钟部分由读地址产生逻辑产生读控制信号和读地址。在空/满标志产生部分,由读写地址相互比较产生空/满标志。
2 异步FIFO的设计难点
设计异步FIFO有两个难点:一是如何同步异步信号,使触发器不产生亚稳态;二是如何正确地设计空、满以及几乎满等信号的控制电路。
下面阐述解决问题的具体方法。
2.1 亚稳态问题的解决
在数字集成电路中,触发器要满足setup/hold的时间要求。当一个信号被寄存器锁存时,如果信号和时钟之间不满足这个要求,Q端的值是不确定的,并且在未知的时刻会固定到高电平或低电平。这个过程称为亚稳态(Metastability)。图2所示为异步时钟和亚稳态,图中clka和clkb为异步时钟。
亚稳态必定会发生在异步FIFO中。图中在异步FIFO中,电路外部的输入和内部的时钟之间是毫无时间关系的,因此setup/hold冲突是必然的;同在电路内部的两个没有关系的时钟域之间的信号传递,也必须会导致setup/hold冲突。
虽然亚稳态是不可避免的,但是,下面的设计改进可以将其发生的概率降低到一个可以接受的程度。
①对写地址/读地址采用格雷码。由实践可知,同步多个异步输入信号出现亚稳态的概率远远大于同步一个异步信号的概率。对多个触发器的输出所组成的写地址/读地址可以采用格雷码。由于格雷码每次只变化一位,采用格雷码可以有效地减少亚稳态的产生。
②采用触发器来同步异步输入信号,如图3中的两极触发器可以将出现亚稳态的几率降低到一个很小的程度。但是,正如图3所示,这种方法同时带来了对输入信号的一级延时,需要在设计时钟的时候加以注意。
2.2 空/满标志的产生
空/满标志的产生FIFO的核心部分。如何正确设计此部分的逻辑,直接影响到FIFO的性能。
空/满标志产生的原则是:写满不溢出,读空不多读。即无论在什么进修,都不应出现读写地址同时对一个存储器地址操作的情况。在读写地址相等或相差一个或多个地址的时候,满标志应该有效,表示此时FIFO已满,外部电路应对FIFO发数据。在满信号有效时写数据,应根据设计的要求,或保持、或抛弃重发。同理,空标志的产生也是如此,即:
空标志<=(|写地址-读地址|<=预定值)AND(写地址超前读地址)
满标志<=(|写地址-读地址|<=预定值)AND(读地址超前写地址)
最直接的做法是,采用读写地址相比较来产生空满标志。如图4所示,当读写地址的差值等于一个预设值的时候,空/满信号被置位。这种实现方法逻辑简单,但它是减法器形成的一个比较大的组合逻辑,因而限制了FIFO的速度。所以,一般只采用相等不相等的比较逻辑,避免使用减法器。
图5是另外一种常用的设计,比较器只对读写地址比较是否相等。在读写地址相等的时候有两种情况:满或者空。所以,附加了一个并行的区间判断逻辑来指示是空还是满。这个区间判断逻辑将整个地址空间分为几个部分,以指示读写地址的相对位置。这种做法提高了整个电路的速度,但是也有其缺点。主要是直接采用读写地址等于不等于的比较逻辑来进行空/满标志的判断,可以带来误判。
3 新颖的FIF0空/满标志控制逻辑
3.1 对读写地址的分析
由以上对FIFO的分析可以看出,由地址直接相减和将地址相互比较产生空/满标志都不可取。如何简单地进行直接比较,又不提高逻辑的复杂程度呢?对地址加延时可以做到这一点。设读地址为Rd_bin_addr,用读地址Rd_addr产生读地址的格雷码Rd_next_gray_addr,将Rd_next_gray_addr延一拍得到Rd_gray_addr,再将Rd_gray_addr延一拍得到Rd_last_gray_addr。在绝对时间上,Rd_next_gray_addr、Rd_gray_addr、Rd_last_gray_addr这些地址先后关系,从大到小排列,并且相差一个地址,如图6所示。
写地址的格雷码的产生也与此类似,即:Wt_next_gray_addr、Wt_gray_addr、Wt_last_gray_addr。利用这6个格雷码进行比较,同时加上读写使能,就能方便而灵活地产生空/满标志。
以空标志Empty的产生为例,当读写格雷码地址相等或者FIFO内还剩下一个深度的字,并且正在不空的情况下执行读操作,这时Emptr标志应该置为有效(高电平有效)。
即EMPTY<=(Rd_gray_addr=Wt_gray_addr)and(Read_enable=1)或EMPTY<=(Rd_next_gray_addr=Wt_gray_addr)and(Read_enable=1)
同理可类推满标志的产生逻辑。
3.2 基于延时格雷码的FIFO标志产生逻辑
图7是使用上述思想设计的地址产生和标志产生的逻辑。首先,在地址产生部分,将产生的格雷码地址加一级延时,利用其前一级地址与当前的读地址作比较。其次,在空/满标志有效的时候,采用了内部保护机制,不使读/写地址进一步增加而出现读写地址共同对一个存储单元操作的现象。
3.3 仿真信号波形
利用图7电路设计的思想构造了一个256×8的FIFO,用MODELSIM进行仿真。图8为系统中主要信号对读空情况的仿真波形。
图6 经过延时后格雷码之间的关系
图8中,WDATA为写数据,RDATA为读数据,WCLK为写时钟,RCLK为读时钟,REMPTY为空信号,AEMPTY的几乎空信号,RPTR为读地址WPTR为写地址,RGNEXT为下一位读地址格雷码,RBIN读地址二进制,RBNEXT为下一位读地址的二进制码。
由图8可以看出,由于读时钟高于写时钟,读地址逐渐赶上写地址,其中由AEMPTY信号指示读地址和写地址的接近程度。当这个信号足够长而被触发器捕捉到时,真正的空信号REMPTY有效。
4 电路优点的分析
由图7可见,该电路最大的瓶颈为二进制到格雷码和比较器的延时之和。由于这两个组合逻辑的延时都很小,因此该电路的速度很高。经测试,在Xilinx的FPGA中,时钟频率可达140MHz。另外,由于将异步的满信号加了一级锁存,从而输出了可靠而稳定的标志。
5 总结
在实际工作中,分别用图4、图5与图7中所示的逻辑实现了一个256×8的FIFO。综合工具为SYNPLIFY7.0,由Foundation Series 3.3i布局布线后烧入Xilinx公司的WirtexEV100ECS144。三者的性能指标比较见表1。
表1 三种不同设计的比较
逻辑设计方式 |
时钟频率/MHz |
有效结果输出频率/MHz |
slice数目/个 |
图4所示逻辑 |
160 |
78.9 |
17 |
图5所示逻辑 |
160 |
92 |
15 |
图7所示逻辑 |
160 |
140 |
13 |
由表1可知,图7所示的异步FIFO的电路速度高,面积小,从而降低了功耗,提高了系统的稳定性