目录
FIFO概念
1. 什么是 FIFO?
FIFO 是英文 First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的 区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序 的读出数据,其数据地址由内部读写指针自动加 1 完成,不能像普通存储器那样可以由地址 线决定读取或写入某个指定的地址。
2. 什么情况下用 FIFO?
FIFO 一般用于不同时钟域之间的数据传输,比如 FIFO 的一端是 A/D 数据采集,另一 端是计算机的 PCI 总线,假设其 A/D 采集的速率为 16 位 100KSPS,那么每秒的数据量为 100K× 16bit=1.6Mbps,而 PCI 总线的速度为 33MHz,总线宽度 32bit,其最大传输速率为 1056Mbps,在两个不同的时钟域间就可以采用 FIFO 来作为数据缓冲。另外对于不同宽度的 数据接口也可以用 FIFO,例如单片机位 8 位数据输出,而 DSP 可能是 16 位数据输入,在 单片机与 DSP 连接时就可以使用 FIFO 来达到数据匹配的目的。
3. FIFO 的宽度
THE WIDTH,它指的是 FIFO 一次读写操作 的数据位,就像 MCU 有 8 位和 16 位,ARM 32 位等等,FIFO 的宽度在单片成品 IC 中是固 定的,也有可选择的,如果用 FPGA 自己实现一个 FIFO,其数据位,也就是宽度是可以自 己定义的。
4. 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都无法保证数据不溢出。因此可以认为这种情况下写数据的传输是“突发Burst”的,即写操作并不连续,设计者需要根据满标志控制或者自己来控制写操作的起止。
宏观地,从整个时间域上看,"写数据=读数据",这个条件必须要满足,如果这个大条件不满足的话,用FIFO是没有效果的。但是在发送方"突发"发送数据的时间T内,是很有可能写数据>读数据的,因此FIFO的深度要能够保证,在这段时间T内,如果接收方未能将发送方发送的数据接收完毕的话,剩下的数据都是可以存储在FIFO内部而且不会溢出的,那么在发送方停止发送数据的"空闲时隙"内,接收方可以从容地接收剩下来的数据。
如果数据流连续不断则FIFO深度无论多少,只要读写时钟不同源同频则都会丢数;
FIFO用于缓冲块数据流,一般用在写快读慢时,
FIFO深度 / (写入速率 - 读出速率) = FIFO被填满时间 应大于 数据包传送时间= 数据量 / 写入速率。
FIFO深度计算的关键在于:在规定时间内传输的数据等于接收的数据,写快读慢的情况下,突发burst写入的数据减去该burst时间内读出的数据,多余的数据需要能缓冲下来,让接收端在剩下空闲的时间能从容地把多余的数据读出来。
1.读写没有空闲周期。(fA>fB)
fA = 80MHz
fB = 50MHz
Burst Length = 120
读写之间没有空闲周期,是连续读写一个突发长度。
解法:
写一个数据需要的时间 = 1 / 80MHz = 12.5ns
写一个突发需要的时间 = 120 * 12.5ns = 1500ns
读一个数据需要的时间 = 1 / 50MHz = 20ns
每1500ns,120个数据被写入FIFO,但读一个数据需要20ns的时间
则1500ns内读出多少个数据,1500 / 20 = 75
剩下的没有读出,就存在FIFO中,则需要120 - 75 = 45
快捷方法:FIFO深度 =120 - 120*50/80 = 45
补充:
读写没有空闲,若fA<=fB,则FIFO不会写满,深度为1即可。
2.读写都有空闲周期。(读写速率大小随意,可以相等)
fA = 80MHz
fB = 50MHz
Burst Length = 120
两个连续写入之间的空闲周期为 = 1(写使能占得百分比为50%)
两个连续读取之间的空闲周期为 = 3(读使能占得百分比为25%)
解法:
每写入一个数据等待1个周期再写入下个数据,即2周期写入1个数据。
每读出一个数据等待3个周期再读出下个数据,即4周期读出1个数据。
写一个数据需要的时间 = 2 * (1 / 80MHz) = 25ns
写一个突发需要的时间 = 120 * 25ns = 3000ns
读一个数据需要的时间 = 4 * (1 / 50MHz) = 80ns
每3000ns,120个数据被写入FIFO,但读一个数据需要80ns的时间
则3000ns内读出多少个数据,3000 / 80 = 37.5,FIFO深度=120-37.5=83。
快捷方法:FIFO深度 = 120 - 120*(50/4)/(80/2)=82.5=83。
3.考虑背靠背,读写速率相等。
读写速率相等
每100个时钟写入80个数据
每10个时钟读取8个数据
突发长度为160 (这个条件其实多余)
解法:
每100个时钟写入80个数据,那剩下20个时钟周期去哪了?
每10个时钟读取8个数据,那剩下2个时钟周期去哪了?
剩下的周期在哪我们不管,只考虑最差的情况,即前20个时钟周期空闲,后80个周期写完80个数据,立马又是写请求,这次是前80个时钟周期写完80个数据,后20个时钟周期空闲。即连续的写入,又称为背靠背。也就可以看成一个突发写入是80+80=160。
写一个突发需要的时间:160时钟周期
则160个时钟周期内读出多少个数据,160*8/10=128。
FIFO深度 = 160 - 128 = 32。
4.考虑背靠背,读写速率不等。
fA = 20MHz
fB = 40MHz
每1000个时钟周期写入500个数据
每4个时钟周期读出1个数据
解法:
考虑到“背靠背”的情况突发长度则为500 * 2 = 1000
则为每1000个时钟周期写入1000个数据
每4个周期,读取一个数据。
写一个数据需要的时间 = 1 / 20MHz = 50ns
写一个突发需要的时间 = 1000 * 50ns = 50000ns
读一个数据需要的时间 = 4 * (1 / 40MHz) = 100ns
每50000ns,120个数据被写入FIFO,但读一个数据需要100ns的时间
可以计算出,50000ns内读出多少个数据,50000 /100 = 500
剩下的没有读出,就存在FIFO中,则需要1000- 500 = 500
再看几道例题参考博客: