最近在准备2026年FPGA校招,看到很多面经里都提到手撕Verilog实现AXI4-Stream FIFO。我有点搞不懂,这个FIFO的深度到底怎么根据带宽和延迟来推导呢?比如数据输入速率是100MHz,输出速率是80MHz,最大延迟是10个时钟周期,那深度设成多少才合适?有没有具体的计算公式或者推导步骤?求大佬指点,最好能给出代码框架和资源对比,比如用BRAM还是分布式RAM更省资源。
2026年FPGA校招,手撕Verilog实现一个AXI4-Stream FIFO,深度怎么根据带宽和延迟推导?
8 个回答

这个问题其实核心就一句话:FIFO深度 = 最大累积数据量 / 每时钟写入字节数。你给的例子,写速100MHz、读速80MHz,差20MHz,最大延迟10个写时钟,那最大累积数据量就是 (100-80) 10 / 100 = 2个数据。但这里有个坑:延迟10个时钟是写时钟还是读时钟?如果是读时钟域的延迟,要换算成写时钟域再算。实际工程里AXI4-Stream FIFO还得考虑tready反压的时序,比如上游连续发数据时下游偶尔拉低tready,那累积量可能更大,建议用仿真跑最差情况。代码框架上,我习惯用双口RAM加读写指针,空/满标志用格雷码跨时钟域。资源选择上,深度<=16用分布式RAM,省一个BRAM给别的模块用;深度>=32且数据位宽不大,BRAM更省面积。你准备校招的话,重点不是背公式,而是能现场推导:先画读写时序图,标出最差情况下的写入和读出周期数,再算深度。追问一句:你面试时是要求用纯LUT实现还是允许调用Xilinx原语?这会影响你写代码的约束风格。

个人感觉你先把最基础的异步FIFO搞透,再去套AXI4-Stream的握手机制。深度推导其实是个数学建模问题:把写使能有效、读使能有效、反压这三个变量画成时序图,找出写指针超前读指针的最大差值。公式只是简化版,面试官更想看你会不会分析边界条件。代码方面,建议先手写一个不带握手的双口RAM FIFO,再在外面包一层tready/tvalid逻辑。资源选型上,深度小于16用分布式RAM,大于等于16用BRAM,但BRAM有latency,你得在空满判断里加上延迟补偿。最后提醒一句:面试手撕时别一上来就写代码,先口头讲清楚推导过程,再动手写,这比代码本身更拉分。

深度推导这事,别只盯着公式,公式只是帮你快速估算一个起点。你给的数字:写100MHz、读80MHz、最大延迟10个写时钟,按 (100-80)/100 10 = 2,得出深度至少2。但面试官实际想看的是你知不知道这个'最大延迟'是哪个时钟域的数。如果延迟是读时钟域的10个周期,得先换算成写时钟域:10 100/80 = 12.5,向上取13,再套公式 (100-80)/100 13 ≈ 2.6,深度取3。更关键的是,AXI4-Stream FIFO的深度还要考虑反压。比如下游tready拉低时,上游可能连续发数据,那累积量就不是简单的速率差乘延迟了。我一般做法是:先画一个最坏情况的时序图,假设上游连续写、下游每n个时钟只读一次,算出写指针最多超前读指针多少个数据,这就是理论深度。然后加1~2个余量,避免边界条件溢出。代码框架上,推荐用双口RAM + 格雷码读写指针,空满判断用指针差。资源选择:深度小于16用分布式RAM,因为BRAM的最小深度是16或32,用了也浪费;深度大于等于32时,BRAM更省面积,而且BRAM自带输出寄存器,能改善时序。面试手撕时,别急着写代码,先跟面试官说'我先分析一下最差情况下的数据累积量,再确定深度',这比直接写个固定深度的FIFO更能体现工程思维。你目前是主要练手撕Verilog,还是也在准备系统架构题?

深度 = (写速率 – 读速率) 最大延迟 / 写时钟周期,注意延迟要换算到写时钟域。AXI4-Stream的反压让累积量可能变大,建议仿真跑最差情况。代码用双口RAM加格雷码指针,深度小用分布式RAM,大用BRAM。

校招手撕AXI4-Stream FIFO,面试官其实不指望你推导出一个完美深度,他们更想看你会不会处理边界。你给的数据,按公式算深度是2或3,但实际工程里我会设成4或8,因为格雷码指针的满判断需要两拍延迟,深度太浅容易误判。资源上,深度≤8用分布式RAM,因为BRAM的最小深度一般是16,用它做8深度的FIFO,利用率只有50%,还不如用LUT搭。另外提一句,代码里别忘了处理tready和tvalid的握手逻辑——写入条件必须是tvalid && tready,读出条件类似。你准备面试时,建议先手写一个不带握手的同步FIFO,再改成带握手的,最后再跨时钟域,一步步来。你目前Verilog基础到什么程度了?同步FIFO能闭眼写吗?

校招手撕这道题,我面过几家,发现多数人死记公式深度= (100-80)10/100=2,然后就被追问卡住了。面试官真正想看你的是会不会处理反压。比如下游tready拉低5个周期,上游又连续发,这时累积量不是简单的速率差乘延迟,而是要考虑上游可能以100MHz连续写、下游以80MHz间歇读,最坏情况写指针能超前读指针多少个。我习惯先画一个时序图,假设上游连续写、下游每10个时钟读8次,算出写指针最大超前量,再加2拍格雷码同步延迟做裕量。资源上,深度<=8用分布式RAM,因为BRAM最小深度16,你用8深度FIFO会浪费一半BRAM,不如用LUT搭。代码框架建议先写一个不带握手的同步FIFO,再在外面包一层tready/tvalid握手逻辑,这样调试起来步骤清晰。你目前Verilog写FIFO是自己从头搭还是用IP核?

深度推导这事,关键要分清楚最大延迟是哪个时钟域的。你给的100MHz写、80MHz读、最大延迟10个时钟,如果这10个是写时钟域,那深度按公式(100-80)/100 10 =2,取3;但如果延迟是读时钟域的10个周期,得先换算成写时钟域:10 100/80 =12.5,向上取13,再套公式 (100-80)/100 13 ≈2.6,深度取3。但实际AXI4-Stream FIFO的深度还要考虑tready反压的累积效应。比如下游偶尔拉低tready,上游可能连续写进多个数据,这时的累积量等于写时钟周期内连续写入的数据数,而不是速率差乘延迟。我一般做法是先假设上游连续写、下游每n个周期只读一次,算出写指针最多超前读指针多少个数据,这就是理论深度,然后加2拍格雷码同步延迟做安全裕量。代码实现上,我习惯用双口RAM加格雷码指针,空满标志用格雷码跨时钟域。资源选择:深度<=8用分布式RAM,因为BRAM最小深度16,利用率低;深度>=16且数据位宽不大时用BRAM更省面积。你准备面试的话,建议先手写一个异步FIFO,再改成带tready/tvalid握手的,这样一步步来。你目前异步FIFO的格雷码指针同步能闭眼写吗?

其实你问的这个深度推导,很多校招攻略都只给了公式,但面试官真正想看到的,是你对反压(backpressure)这个工程概念的敏感度。我举个例子:假设你的写端是100MHz连续发数据,读端是80MHz,但读端偶尔会因为下游处理不过来而拉低tready,比如连续拉低5个周期。这时候,写端并不知道读端停了,它可能还在以100MHz的速度往里写,那这5个周期里累积的数据就是5个,而不是公式算出来的2个。所以深度推导的核心,不是套公式,而是先搞清楚你的系统里最坏情况是什么:是读端持续以80MHz处理但偶尔有长延迟,还是读端会被频繁反压导致写指针飞快超前?我自己的做法是,先画一个读写指针的时序图,把最极端的写使能和读使能波形画出来,数一数写指针最多能比读指针多出多少个数据,这个数就是理论最小深度,然后再加上格雷码同步需要的两拍延迟作为安全裕量。比如你给的例子,如果延迟10个写时钟是读端反压导致的,那实际累积量可能远大于2,我建议设成8或16。资源上,如果深度<=8,用分布式RAM(LUT搭)更省,因为BRAM的最小深度一般是16或32,用BRAM做8深度FIFO,利用率不到一半,而且BRAM的读写有latency,会引入额外的空满判断延迟。如果深度>=16,并且数据位宽不太宽,BRAM更省面积和功耗。代码框架上,建议先写一个不带握手的同步FIFO(双口RAM加读写指针),再在外面包一层tvalid和tready的握手逻辑,这样调试时可以先确认内部FIFO工作正常,再查握手信号时序。你目前是用Vivado还是Quartus?不同工具对BRAM的推断规则略有差异,会影响你选分布式还是BRAM。
发表回答
登录后可在本页底部提交回答