Wo ist der FIFO Generator geblieben?
Bei Verwendung von Versal-FPGAs stellt AMD keinen IP-Block bereit, der einen einfachen FIFO implementiert und in einer Verilog- oder VHDL-Instanziierung (instantiation) verwendet werden kann. Der bekannte FIFO Generator ist für diese FPGAs nicht verfügbar. Das gilt zumindest für Vivado 2022.1 und frühere Versionen.
Wenn also der FPGA-Teil eines bestehenden FPGA-Designs auf einen Versal-FPGA umgestellt wird, sind mit hoher Wahrscheinlichkeit Änderungen an den Projekten nötig. Fast alle FPGA-Projekte verwenden den FIFO Generator.
Das Gleiche gilt für den Memory Generator: Auch dieser IP-Block ist bei Versal-FPGAs nicht mehr verfügbar. Er wird allerdings seltener eingesetzt, weil Block-RAMs häufig per Inferenz erzeugt werden. Anders gesagt: Für ein RAM deklariert man in Verilog (oder VHDL) normalerweise einfach ein Array.
Beachten Sie: FIFOs und RAMs mit AXI-Schnittstelle sind weiterhin als IP-Blöcke verfügbar. Die fehlende Unterstützung für Versal-FPGAs betrifft nur FIFOs und Block-RAMs mit „nativer“ Schnittstelle.
Es gibt mehrere Möglichkeiten, dieses Problem zu umgehen. Ich werde zwei vorstellen.
Eine allgemeine Einführung in FIFOs finden Sie in dieser Artikelserie.
Option #1: AMD Parameterized Macros verwenden
AMD Parameterized Macros sind in Vivado für alle FPGAs verfügbar, die von der Software unterstützt werden (also Serie-7-FPGAs und neuere). Diese Makros können wie jedes Verilog- oder VHDL-Modul in einer Instanziierung verwendet werden. Die Dokumentation dazu finden Sie zusammen mit den FPGA-Primitiven (englisch: primitive), zum Beispiel im Versal Architecture Premium Series Libraries Guide, UG1485.
Es gibt jedoch einen wichtigen Unterschied zwischen Primitiven und Parameterized Macros: Stößt der Synthesizer (synthesizer) auf ein Primitive, erzeugt er in der synthetisierten Netzliste normalerweise nur ein Logikelement. Ein Parameterized Macro dagegen erzeugt eine ganze Reihe von Logikelementen – genau wie ein Verilog-Modul.
Es gibt mehrere parametrisierte Makros, die FIFOs erzeugen, insbesondere diese beiden:
xpm_fifo_syncerzeugt einen synchronen FIFO (mit einem einzigen Takt).xpm_fifo_asyncerzeugt einen asynchronen FIFO (Dual-Clock).
Die von diesen beiden Makros erzeugten FIFOs haben eine „native“ Schnittstelle, also Ports wie wr_en und rd_en. Fast alle Optionen, die der FIFO Generator bot, lassen sich durch die Instanziierungsparameter des Makros aktivieren. Diese FIFOs können unter anderem als Standard-FIFOs oder als First Word Fall Through (FWFT) ausgelegt werden.
Außerdem gibt es einige Makros zum Implementieren verschiedener RAM-Typen. Unabhängig davon gibt es auch mehrere AXI-Stream-FIFOs unterschiedlicher Art; die lassen sich aber auch für Versal-FPGAs als IP-Blöcke erzeugen.
Vollständige Informationen zur Verwendung dieser Makros finden Sie im jeweiligen Libraries Guide; für Versal-FPGAs ist das UG1485. Eine Instanziierungsvorlage erhalten Sie auch mit Vivado: Wählen Sie Tools > Language Templates und gehen Sie zu Verilog > AMD Parameterized Macros (XPM) > XPM > XPM_FIFO. Dort wählen Sie dann den Synchronous FIFO oder Asynchronous FIFO, je nach Anwendungsfall.
Hier ist ein Beispiel, wie man einen grundlegenden synchronen FIFO erstellt, der dieselbe Funktion hat wie der auf dieser Seite gezeigte.
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
Option #2: Der Embedded FIFO Generator
Der Embedded FIFO Generator ist praktisch dasselbe wie der bekannte FIFO Generator, nur dass er ausschließlich innerhalb eines Block-Designs (block design) verwendet werden kann.
Die naheliegende Lösung ist also, ein Block-Design zu erzeugen und einen Embedded FIFO Generator hinzuzufügen. Anschließend stellt man die Parameter dieses IP-Blocks genau so ein wie beim bisherigen FIFO Generator. Danach verbindet man alle Ports des FIFOs mit externen Ports. Das Ergebnis ist ein Block-Design, das die Ports eines FIFOs besitzt, sich wie ein FIFO verhält und damit schlicht ein FIFO ist.
Diese Lösung ist ein wenig unschön, vor allem weil die Namen der FIFO-Ports länger werden als gewohnt. Statt wr_en heißt der Port dann zum Beispiel FIFO_WRITE_0_wr_en.
Fazit
Auch wenn der FIFO Generator plötzlich und ohne erkennbaren Grund aus dem Vivado-IP-Katalog verschwunden ist, ist es in der Regel nicht schwierig, diesen IP-Block durch ein Parameterized Macro oder ein Block-Design zu ersetzen.
Im weiteren Zusammenhang gesehen ist es vielleicht eine gute Idee, den FIFO Generator auch für FPGAs nicht mehr zu verwenden, die ihn unterstützen – ganz gleich, ob man eine Migration auf Versal-FPGAs anstrebt oder nicht.