Vivado 种实现 FIFO 的 4 种方法

2020-01-09

…孔乙己自己知道不能和他们谈天,便只好向孩子说话。有一回对我说道,“你读过书么?”我略略点一点头。他说,“读过书,……我便考你一考。茴香豆的茴字,怎样写的?”我想,讨饭一样的人,也配考我么?便回过脸去,不再理会。孔乙己等了许久,很恳切的说道,“不能写罢?……我教给你,记着!这些字应该记着。将来做掌柜的时候,写账要用。”我暗想我和掌柜的等级还很远呢,而且我们掌柜也从不将茴香豆上账;又好笑,又不耐烦,懒懒的答他道,“谁要你教,不是草头底下一个来回的回字么?”孔乙己显出极高兴的样子,将两个指头的长指甲敲着柜台,点头说,“对呀对呀!……Vivado 种实现 FIFO 的方法有 4 种,你知道么?”我愈不耐烦了,努着嘴走远。孔乙己刚用指甲蘸了酒,想在柜上写字,见我毫不热心,便又叹一口气,显出极惋惜的样子。

首先,根据综合之后的形式,Xilinx FPGA 中 FIFO 的实现方式一般有 4 种:

  1. Build-in FIFO:7 系列以及之后的 FPGA 中的 Block RAM 可以被配置为 FIFO 模式(可以使用 FIFO 原语(FIFO18/FIFO36)来调用)。Build-in FIFO 中包含固化的复位、读写控制、接口握手信号和 CDC 逻辑,因此几乎无需额外的逻辑资源。正因为此,FIFO 原语的工作时钟频率可以很高,同时又几乎不用考虑时序问题。功能方面 Build-in FIFO 原生支持异步时钟、FWFT 模式、ECC。但是其不支持读写计数,只有 UltraScale 之后的器件才支持非对称位宽。考虑 Build-in FIFO 的特点,一般是大深度(>1k)或者高速 FIFO 的首选实现方案
  2. Block RAM:使用 FPGA 中的 Block RAM 来储存数据。此时 BRAM18/36 被配置为双口 RAM 模式。双读写接口中 A 口用于写,B 口用于读,采用额外的 CLB 逻辑来实现复位、读写控制、握手信号和 CDC 逻辑。额外的这种方式类似于 (1),但可以支持不对称位宽以及读写计数。由于需要额外的 CLB 资源,因此工作时钟频率可能会受到影响(一般 BRAM 频率比 CLB 高很多)
  3. Distribute RAM:类似于 (2),但采用 CLB(LUT/FF/etc.)资源构建双口 RAM。数据被储存在 LUT 中,此时 LUT 被配置为 DRAM 模式。相比于 (1) 和 (2),这种方式不需要 BRAM,但是工作频率稍慢,适合深度较小或适中(<=1k)的 FIFO。特别是在深度比较小时,LUT 用作储存特别高效,并且支持异步时钟模式,是多位宽数据 CDC 的优选
  4. Shift Register:采用 CLB 资源构建,数据被储存在 FF 中。不支持异步时钟,由于减少了 LUT 的使用,其工作频率比 (3) 高一些。但是由于 FF 作为储存资源非常低效,因此其深度一般较小(16 或 32)

其次,不论最终的实现形式是上面哪种,设计方法主要有 5 个:

  1. 直接采用 HDL 描述。可以实现 (2),(3),(4) 类型的 FIFO。但是由于 Build-in FIFO 是无法由 HDL 描述推测出来的,因此无法实现 (1)。不同的实现一般需要不同的设计。此外即便是经验丰富的 FPGA 工程师,有时候也会搞砸 CDC 的设计。
  2. Device Primitive Instantiation,直接原语例化。可以轻松实现 (1),但是需要仔细查看 Xilinx 文档了解细节,特别是需要级联时,比较繁杂。当移植器件系列时可能需要调整
  3. Device Macro Instantiation,调用 Xilinx UNIMACRO 库。Xilinx UNIMACRO 是一个库,它并不是直接例化原语,但是又比 IP 更加轻量。使用时仅需在 HDL 中进行例化,Vivado 会根据器件系列、FIFO 深度选择合适的设计实现
  4. Xilinx Parameterized Macros,调用 Xilinx XPM 库。类似于 (3),但是针对 UltraScale 及之后的器件,XPM 取代了 UNIMACRO
  5. Xilinx Vivao IP,即 Vivado 中集成的 FIFO Generator IP。重量级方案,可以灵活配置不同的实现、参数。但是更换器件、系列时需要重新升级 IP,调整参数。并且 Xilinx 的 IP 集成工作流程有点复杂,很多时候选择轻量级的 (4) 更舒心

© 2021 Kele, CC BY-NC-SA 4.0