3. FIFO深度与带宽关系:深度对吞吐率的影响、深度与延迟的权衡、最小深度计算公式
好,咱们接着聊FIFO。前面讲了带宽和深度各自是什么,现在该把它们串起来了。
说白了,FIFO深度不是拍脑袋定的。你选深了,浪费面积;选浅了,系统直接卡死。我见过不少新手,上来就写个深度256的FIFO,问为什么,答“怕不够用”。嗯,这种“防御性设计”其实挺常见的,但咱们做芯片的,每一丝面积都得精打细算。
3.1 深度对吞吐率的影响
先问一个问题:FIFO深度越大,吞吐率越高吗?
直觉上好像是的——缓冲区大了,不容易满,数据流更顺畅。但实际情况没那么简单。
我举个例子。假设你有一个写时钟频率200MHz、读时钟频率100MHz的异步FIFO。写端每拍写一个数据,读端每两拍读一个数据。这时候,深度只要大于某个阈值,吞吐率就由读端决定了。你再怎么加深FIFO,读端还是每两拍读一个,吞吐率上不去。
深度对吞吐率的影响,其实有个“饱和点”。低于这个点,深度增加能明显提升吞吐率;高于这个点,再加深就是浪费。
核心结论:
- 深度不足 → 写端频繁被反压 → 吞吐率下降
- 深度足够 → 吞吐率由读写速率差决定 → 深度不再是瓶颈
- 深度过大 → 面积和功耗白白增加 → 性价比下降
我在一个视频处理项目中遇到过这种情况。当时用的FIFO深度是512,但实际分析下来,深度64就够用了。多出来的448个存储单元,每个周期都在白白耗电。后来改成深度128,留了点余量,面积省了将近40%。
3.2 深度与延迟的权衡
这里有个绕不开的矛盾:深度越大,延迟越大。
你想想看,数据写入FIFO后,要等前面的数据被读走,它才能被读到。深度越大,数据在FIFO里排队的时间就越长。对于实时性要求高的场景——比如视频流、控制环路——这个延迟可能是致命的。
| 深度 | 典型延迟(写时钟周期数) | 适用场景 |
|---|---|---|
| 4 | 2~4 | 高速控制、寄存器级同步 |
| 16 | 8~16 | 数据包缓冲、短时突发 |
| 64 | 32~64 | 视频行缓冲、中等突发 |
| 256+ | 128+ | 大块数据缓存、DDR接口 |
注意,这里的延迟不是固定的。FIFO空的时候,数据几乎零延迟通过;FIFO快满的时候,延迟接近深度值。所以我说“延迟是一个范围”,而不是一个固定值。
避坑指南:
我曾经在一个PCIe DMA设计中,把FIFO深度设成了1024。结果发现,每次DMA传输完成后,CPU要等很久才能读到数据。查了半天,原来是FIFO太深,数据在里边排队排了上千个周期。后来改成深度256,延迟降下来了,吞吐率一点没变。
3.3 最小深度计算公式
好了,到了最实用的部分。怎么算FIFO的最小深度?
公式其实不复杂,但你要理解背后的逻辑。核心思想是:在写端连续写入的最长时段内,读端能读走多少数据,剩下的就是FIFO必须存下来的。
先看最简情况:
最小深度 = 写时钟频率 / 读时钟频率 × (写使能率 / 读使能率) × 最大突发长度
嗯,这个公式有点抽象。我拆开来讲。
第一步:算写速率
写速率 = 写时钟频率 × 写使能率。比如200MHz时钟,每拍都写(使能率=1),那写速率就是200M数据/秒。
第二步:算读速率
读速率 = 读时钟频率 × 读使能率。比如100MHz时钟,每两拍读一次(使能率=0.5),那读速率就是50M数据/秒。
第三步:算速率差
速率差 = 写速率 - 读速率 = 200M - 50M = 150M数据/秒。也就是说,每秒钟FIFO里会多出150M个数据。
第四步:乘上最大突发长度
假设写端连续写入1000个数据(突发长度=1000),那这1000个数据写入需要的时间是:1000 / 200M = 5微秒。在这5微秒内,读端能读走:50M × 5微秒 = 250个数据。所以FIFO里最多会积压:1000 - 250 = 750个数据。
最小深度就是750。
完整公式:
最小深度 = 突发长度 - (突发长度 / 写时钟周期) × 读时钟周期 × 读使能率
或者写成更通用的形式:
最小深度 = 突发长度 × (1 - (读时钟频率 × 读使能率) / (写时钟频率 × 写使能率))
个人经验:
我习惯在算出来的最小深度上再加20%~30%的余量。为什么?因为实际电路中,读写使能信号可能有抖动,时钟可能有相位差,格雷码同步也有延迟。不加余量的话,FIFO很容易在边界条件下溢出。
但注意,余量别加太多。我见过有人算出来深度需要10,直接上256。这就有点过了。
3.4 一个实际案例
咱们看一个真实场景。一个以太网MAC接口,写时钟125MHz,每拍写一个字节(使能率=1)。读时钟200MHz,但读端每4拍才能处理一个字节(使能率=0.25)。最大以太网帧长1518字节。
算一下:
- 写速率 = 125M × 1 = 125M 字节/秒
- 读速率 = 200M × 0.25 = 50M 字节/秒
- 速率差 = 125M - 50M = 75M 字节/秒
- 一个帧写入时间 = 1518 / 125M ≈ 12.14 微秒
- 这段时间内读走的数据 = 50M × 12.14微秒 ≈ 607 字节
- 最小深度 = 1518 - 607 = 911 字节
加上30%余量,深度取1200左右。实际设计中,我选了深度2048的FIFO——因为标准FIFO深度都是2的幂次,2048是离1200最近的2的幂。
你看,这个深度既不是拍脑袋定的,也不是越大越好。每一步都有依据。
最后说一句,最小深度计算公式只是起点,不是终点。实际项目中,你还要考虑:
- 时钟抖动和相位差
- 读写使能信号的毛刺
- 格雷码同步的延迟(通常2~3个时钟周期)
- FIFO空满标志的生成延迟
这些因素都会让实际需要的深度比理论值大一点。但大多少,得靠仿真和实测来验证。我个人的习惯是:先按公式算,加30%余量,然后做仿真,看FIFO在极端情况下的水位线。如果水位线从来没超过深度的80%,那就可以考虑减一减。
嗯,深度这个话题就聊到这儿。记住一句话:FIFO深度不是越大越好,够用就行,留点余量就行。