…孔乙己自己知道不能和他们谈天,便只好向孩子说话。有一回对我说道,“你读过书么?”我略略点一点头。他说,“读过书,……我便考你一考。茴香豆的茴字,怎样写的?”我想,讨饭一样的人,也配考我么?便回过脸去,不再理会。孔乙己等了许久,很恳切的说道,“不能写罢?……我教给你,记着!这些字应该记着。将来做掌柜的时候,写账要用。”我暗想我和掌柜的等级还很远呢,而且我们掌柜也从不将茴香豆上账;又好笑,又不耐烦,懒懒的答他道,“谁要你教,不是草头底下一个来回的回字么?”孔乙己显出极高兴的样子,将两个指头的长指甲敲着柜台,点头说,“对呀对呀!……Vivado 种实现 FIFO 的方法有 4 种,你知道么?”我愈不耐烦了,努着嘴走远。孔乙己刚用指甲蘸了酒,想在柜上写字,见我毫不热心,便又叹一口气,显出极惋惜的样子。
首先,根据综合之后的形式,Xilinx FPGA 中 FIFO 的实现方式一般有 4 种:
- 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 的首选实现方案
- Block RAM:使用 FPGA 中的 Block RAM 来储存数据。此时 BRAM18/36 被配置为双口 RAM 模式。双读写接口中 A 口用于写,B 口用于读,采用额外的 CLB 逻辑来实现复位、读写控制、握手信号和 CDC 逻辑。额外的这种方式类似于 (1),但可以支持不对称位宽以及读写计数。由于需要额外的 CLB 资源,因此工作时钟频率可能会受到影响(一般 BRAM 频率比 CLB 高很多)
- Distribute RAM:类似于 (2),但采用 CLB(LUT/FF/etc.)资源构建双口 RAM。数据被储存在 LUT 中,此时 LUT 被配置为 DRAM 模式。相比于 (1) 和 (2),这种方式不需要 BRAM,但是工作频率稍慢,适合深度较小或适中(<=1k)的 FIFO。特别是在深度比较小时,LUT 用作储存特别高效,并且支持异步时钟模式,是多位宽数据 CDC 的优选
- Shift Register:采用 CLB 资源构建,数据被储存在 FF 中。不支持异步时钟,由于减少了 LUT 的使用,其工作频率比 (3) 高一些。但是由于 FF 作为储存资源非常低效,因此其深度一般较小(16 或 32)
其次,不论最终的实现形式是上面哪种,设计方法主要有 5 个:
- 直接采用 HDL 描述。可以实现 (2),(3),(4) 类型的 FIFO。但是由于 Build-in FIFO 是无法由 HDL 描述推测出来的,因此无法实现 (1)。不同的实现一般需要不同的设计。此外即便是经验丰富的 FPGA 工程师,有时候也会搞砸 CDC 的设计。
- Device Primitive Instantiation,直接原语例化。可以轻松实现 (1),但是需要仔细查看 Xilinx 文档了解细节,特别是需要级联时,比较繁杂。当移植器件系列时可能需要调整
- Device Macro Instantiation,调用 Xilinx UNIMACRO 库。Xilinx UNIMACRO 是一个库,它并不是直接例化原语,但是又比 IP 更加轻量。使用时仅需在 HDL 中进行例化,Vivado 会根据器件系列、FIFO 深度选择合适的设计实现
- Xilinx Parameterized Macros,调用 Xilinx XPM 库。类似于 (3),但是针对 UltraScale 及之后的器件,XPM 取代了 UNIMACRO
- Xilinx Vivao IP,即 Vivado 中集成的 FIFO Generator IP。重量级方案,可以灵活配置不同的实现、参数。但是更换器件、系列时需要重新升级 IP,调整参数。并且 Xilinx 的 IP 集成工作流程有点复杂,很多时候选择轻量级的 (4) 更舒心
© 2021 Kele, CC BY-NC-SA 4.0