FIFO Generator 去哪了?
在使用 Versal FPGA 时,AMD 没有提供任何实现普通 FIFO 的 IP 块(IP block),可供在 Verilog 或 VHDL 中进行实例化(instantiation)使用。广为人知的 FIFO Generator IP 在这些 FPGA 上不可用,至少对 Vivado 2022.1 及更早版本来说是如此。
因此,如果把现有 FPGA 设计中的 FPGA 部分改为 Versal FPGA,很可能需要对项目做一些改动。几乎所有的 FPGA 项目都会用到 FIFO Generator。
Memory Generator 也是如此:这个有时用来创建 block RAM 的 IP 在 Versal FPGA 上同样被取消了。不过,这个 IP 用得较少,因为 block RAM 通常依靠推断(inference)来创建。换句话说,在 Verilog(或 VHDL)中,人们通常会声明一个数组(array),目的是创建 RAM。
请注意,带 AXI 接口的 FIFO 和 RAM 仍然可以作为 IP 使用。对 Versal FPGA 来说,支持缺失的只是那些带有“原生(native)”接口的 FIFO 和 block RAM。
有几种方法可以绕过这个问题。我下面给出两种可行的方式。
关于 FIFO 的通用教程,请参考这个系列页面。
方案 1:使用 AMD 参数化宏
AMD 参数化宏(AMD Parameterized Macros)在 Vivado 中适用于该软件所支持的所有 FPGA(即 7 系列及更新的 FPGA)。这些宏可以像 Verilog 或 VHDL 中的任何模块(module)一样在实例化(instantiation)中使用。它们的文档与 FPGA 原语(primitive)文档放在一起(例如,Versal Architecture Premium Series Libraries Guide,UG1485)。
不过,原语(primitive)与参数化宏之间有一个重要区别:当综合器(synthesizer)遇到原语时,通常只会在综合后的网表(netlist)中产生一个逻辑单元。而参数化宏则会像 Verilog 模块一样,产生一大堆逻辑单元。
有几个参数化宏可以生成 FIFO,尤其是下面这两个:
- xpm_fifo_sync:生成同步 FIFO(synchronous FIFO,使用单一时钟)。
- xpm_fifo_async:生成异步 FIFO(asynchronous FIFO,双时钟)。
这两个宏生成的 FIFO 具有“原生”(native)接口,也就是像 wr_en 和 rd_en 这样的端口。当初 FIFO Generator 提供的大多数选项,都可以通过设置宏的实例化(instantiation)参数来启用。例如,这些 FIFO 既可以是“标准 FIFO”(Standard FIFO),也可以是“首字直通”FIFO(First Word Fall Through,FWFT)。
另外还有几个用于实现不同类型 RAM 的宏。此外,也有好几种 AXI-Stream FIFO,不过它们都可以用 IP 块创建,即使在 Versal FPGA 上也是如此。
关于如何使用这些宏的完整信息,请参阅相应的 Libraries Guide,对 Versal FPGA 来说就是 UG1485。也可以从 Vivado 中获取实例化(instantiation)模板:选择 Tools > Language Templates,然后进入 Verilog > AMD Parameterized Macros (XPM) > XPM > XPM_FIFO,再根据情况选择 Synchronous FIFO 或 Asynchronous FIFO。
下面是一个创建基本同步 FIFO 的示例,其功能与该页面所示的 FIFO 相同。
module fifo_8x2048
#(parameter width = 8, depth = 2048)
(
input clk,
input rst,
input wr_en,
input [(width-1):0] din,
input rd_en,
output [(width-1):0] dout,
output full,
output empty
);
xpm_fifo_sync #(
.DOUT_RESET_VALUE("0"),
.ECC_MODE("no_ecc"),
.FIFO_MEMORY_TYPE("auto"),
.FIFO_READ_LATENCY(1),
.FIFO_WRITE_DEPTH(depth),
.FULL_RESET_VALUE(1),
.READ_DATA_WIDTH(width),
.READ_MODE("std"),
.SIM_ASSERT_CHK(0),
.USE_ADV_FEATURES("0000"),
.WAKEUP_TIME(0),
.WRITE_DATA_WIDTH(width)
)
xpm_fifo_sync_inst (
.almost_empty(),
.almost_full(),
.data_valid(),
.dbiterr(),
.dout(dout),
.empty(empty),
.full(full),
.overflow(),
.prog_empty(),
.prog_full(),
.rd_data_count(),
.rd_rst_busy(),
.sbiterr(),
.underflow(),
.wr_ack(),
.wr_data_count(),
.wr_rst_busy(),
.din(din),
.injectdbiterr(1'b0),
.injectsbiterr(1'b0),
.rd_en(rd_en),
.rst(rst),
.sleep(1'b0),
.wr_clk(clk),
.wr_en(wr_en)
);
endmodule
方案 2:使用嵌入式 FIFO Generator
嵌入式 FIFO Generator(Embedded FIFO Generator)实际上与众所周知的 FIFO Generator 几乎相同,但它只能用在块设计(block design)中。
因此,一个明显的解决方案是创建一个块设计,并添加一个嵌入式 FIFO Generator,然后像之前的 FIFO Generator 一样设置这个 IP 块的参数。接下来,把该 FIFO 的所有端口都连接到外部端口。最后得到的块设计有着与 FIFO 相同的端口,行为也像 FIFO,所以它就是一个 FIFO。
这个方案有点丑,尤其是 FIFO 的端口名会变得比平时更长。例如,端口名不再是 wr_en,而是 FIFO_WRITE_0_wr_en。
结论
尽管 FIFO Generator 从 Vivado 的 IP 目录(IP Catalog)中消失得既突然又令人费解,但用参数化宏或块设计来替代这个 IP 通常并不困难。
从更宏观的角度看,即使是在仍支持 FIFO Generator 的 FPGA 上,也许最好也不要再使用它,而不必考虑这种做法对将来把设计移植到 Versal FPGA 的可能性有什么影响。