Chapter 2: Link-Level Flow Control and Buffering


对于接收侧 FIFO,需要至少 Lf + Lb 的深度吸收过冲。即 RxFIFO 满时拉低 ready,至少需要等待 Lf + Lb 个 clk 才能作用到 RxFIFO 的 valid。此外,若 RxFIFO 深度刚好等于 Lf + Lb,则需要保证 RxFIFO 为空时才能拉高 ready。
当 RxFIFO 为空时,拉高 ready 到接收到数据需要等待 Lf + Lb 个 clk;在 RxFIFO 收到第一包数据(即非空状态)时,会拉低 ready,在此期间最多可接收 Lf + Lb 包数据;在这 Lf + Lb 包数据全部被消耗掉,RxFIFO 回到空状态后,才能再次拉高 ready。综上,理论最高吞吐率为 50%,即有一半时间处于断流,且 RxFIFO 利用率不足。

那么如何提高吞吐?可以扩充 RxFIFO,设深度为 Lf + Lb + k,则当 FIFO 剩余空间 ≥ Lf + Lb 时 ready = 1。FIFO 除了 Lf + Lb 空间用来吸收过冲,还能额外缓存 k 个包,则吞吐率为 (Lf + Lb + k) / 2(Lf + Lb)。显然,当 k = Lf + Lb 时,吞吐率为 100%,此时 RxFIFO 深度为 2(Lf + Lb)。


Credit 流控举例:t0 时刻,Tx 消耗初始 Credit,发包延迟 1 clk;t1 时刻,Forward 传递延迟 1 clk;t2 时刻,Rx 接收数据包并更新 Credit 计数,Backward 传递延迟 1 clk;t3 时刻,Tx 再次获得新的 Credit 并立即消费。从 Tx 消费 Credit 到 Tx 获得新的 Credit 经历 3 clk,当 Credit_Num = 1 时,吞吐为 1/3;当 Credit_Num = 3 时,吞吐可达 100%。若前向和后向总延迟为 Lf + Lb,则:
Throughput=Credit_NumLf+Lb\\text{Throughput} = \\frac{\\text{Credit\\_Num}}{Lf + Lb}Throughput=Lf+LbCredit_Num
可知达到 100% 吞吐需要 Credit_Num = Lf + Lb。

REQ-ACK 握手机制:
- 方式一:Tx 发包后等待 ACK,告知该数据已被接收,再发下一包——这种方式吞吐率差。
- 方式二:Tx 会缓存发出去的包,经过几个 clk 后:若收到 ACK,表示被成功接收,则清除该包数据缓存;若收到 NACK,表示 Rx 丢包,则后续优先调度重传。
Bufferless 流控:属于 REQ-ACK 握手的退化,在 Rx/Tx 各留一个必要的寄存器,收到 NACK 后由更高级的协议层恢复数据包重传。实质上是用协议层恢复数据包重传的复杂度,换取缓存的开销。
「flit」一词源于 “flow-control digit”。
存在两种流控策略:
- Virtual Cut Through (VCT):一般用于 Off-Chip 网络,流控粒度是整个 Packet,必须保证每个节点 Buffer 深度能足够缓存整个数据包。
- Wormhole (WH):一般用于 On-Chip 网络,流控粒度是 flit,每节点 Buffer 保证吸收过冲且 100% 吞吐即可。发生阻塞时,数据包的多个 flit 可能会分散到多个节点。






