FIFO 是先入先出缓冲,分同步 FIFO(读写同时钟,简单)和异步 FIFO(读写不同时钟,跨时钟域用);同步 FIFO 用计数器判空满,异步 FIFO 用格雷码指针跨域+空满判断;深度由读写速率差和突发长度决定(FIFO深度 ≥ 突发长度×(1-读速率/写速率));空标志读指针=写指针,满标志写指针追上读指针。
本文概述
FIFO 是 FPGA 常用模块,面试常考:同步异步、深度计算、空满判断、格雷码。回答要给原理和公式。
核心要点
同步 FIFO:读写同时钟,用一个计数器(count)判空满,简单,适合同域数据缓冲
异步 FIFO:读写不同时钟,读写指针用格雷码跨时钟域,防止亚稳态,适合 CDC
空标志:读指针追上写指针(rd_ptr == wr_ptr);满标志:写指针追上读指针(差一个深度)
异步 FIFO 深度计算:depth ≥ burst_size × (1 - rclk_rate/wclk_rate),留余量
格雷码:相邻码只有 1 位变化,跨时钟域同步时不会多位同时变化导致亚稳态

面试官考察点
FIFO 核心题。面试官看你是否理解异步 FIFO 和 CDC。重点听:格雷码、空满、深度计算。
回答思路
讲同步异步区别,格雷码原理,空满判断,深度计算。
参考回答
同步 FIFO。
读写同一个时钟,用一个计数器 count 记录数据量;
写:wr_ptr++,count++;读:rd_ptr++,count--;
空:count==0;满:count==DEPTH;
简单,资源少,适合同时钟域数据缓冲(如流水线对齐、突发缓冲)。
异步 FIFO。
写时钟 wclk 和读时钟 rclk 不同(跨时钟域 CDC);
写指针在 wclk 域,读指针在 rclk 域,不能直接比较(亚稳态);
指针用格雷码编码,然后打两拍同步到对方时钟域;
写满判断:wptr_gray(同步到 rclk 的 rptr)== 满条件;
读空判断:rptr_gray(同步到 wclk 的 wptr)== 空条件。
为什么用格雷码。
二进制指针跨时钟域时,多位同时变化(如 0111→1000,4 位都变),同步时可能采到中间态(亚稳态);
格雷码相邻数值只有 1 位变化(如 3→4:0010→0110,只有 1 位变),同步时最多 1 位亚稳态,结果要么是旧值要么是新值,不会出错;
异步 FIFO 必须用格雷码指针,这是标准做法。
二进制→格雷码:gray = bin ^ (bin >> 1)
格雷码→二进制:bin[n-1] = gray[n-1]; bin[i] = bin[i+1] ^ gray[i]
空满判断(异步 FIFO)。
空:rptr_gray == wptr_gray_sync(读指针追上写指针,FIFO 空);
满:wptr_gray == {~rptr_gray_sync[MSB:MSB-1], rptr_gray_sync[MSB-2:0]}(写指针比读指针多一圈);
满判断技巧:格雷码最高两位相反,其余相同 = 满;
空满标志在各自时钟域生成(空在 rclk,满在 wclk),避免跨域。
FIFO 深度计算。
写速率 wclk,读速率 rclk,突发长度 burst
最坏情况:连续写 burst 个,同时在读
深度 ≥ burst × (1 - rclk/wclk) + 余量
例:wclk=100MHz, rclk=80MHz, burst=256
深度 ≥ 256 × (1-0.8) = 51.2 → 取 64 或 128
如果写速率 ≤ 读速率,深度只需要缓冲突发(depth ≥ burst_size);
如果写速率 > 读速率,长时间会溢出,FIFO 只能缓冲突发,不能解决持续速率差;
实际深度取 2 的幂(方便指针回绕),留 20~50% 余量;
考虑读写同时、时钟相位差、同步延迟等因素。
FIFO 实现方式。
| 方式 | 容量 | 特点 |
|---|---|---|
| 分布式 RAM(寄存器) | 小(<64) | 速度快,资源多 |
| Block RAM | 大(18Kb/36Kb) | 专用 RAM,适合大 FIFO |
| URAM(UltraRAM) | 更大(288Kb) | UltraScale 器件,超大 FIFO |
Xilinx FIFO Generator IP 可以直接生成同步/异步 FIFO,配置深度、位宽、时钟;
小 FIFO 可以自己写(寄存器数组+指针),大 FIFO 用 IP(Block RAM);
异步 FIFO 建议用 IP,自己写容易出错(格雷码、空满判断)。
注意。
异步 FIFO 复位要注意:读写时钟域都要复位,复位释放要同步;
FIFO 读写不能同时在同一个位置(空时不能读,满时不能写);
almost_empty/almost_full 可编程阈值,用于流控;
FIFO 深度不是越大越好,大了增加延迟和资源。












