Einführung
Dies ist der zweite Beitrag in einer vierteiligen Serie über partielle Rekonfiguration (Partial Reconfiguration) beziehungsweise Dynamic Function eXchange (DFX) mit Xilinx' Vivado. Dieser Beitrag soll die Schritte zur Aktivierung der partiellen Rekonfiguration in einem FPGA-Design erläutern. Es empfiehlt sich, den ersten Beitrag zu lesen, falls Sie das nicht schon getan haben, denn dort werden die Konzepte hinter diesen Schritten erklärt.
Xilinx hat die partielle Rekonfiguration (Partial Reconfiguration) im Jahr 2020 in „Dynamic Function eXchange“ (DFX) umbenannt. DFX ist der Ausdruck, der in Vivados Menüs und Hinweistexten verwendet wird. Der technische Begriff „Partielle Rekonfiguration“ wird hier trotzdem benutzt.
Der Einfachheit halber wird in diesem Beitrag angenommen, dass das Projekt nur eine rekonfigurierbare Partition enthält. Die Erweiterung auf mehrere Partitionen ist relativ unkompliziert.
Das hier beschriebene Verfahren beginnt bevor das Projekt für partielle Rekonfiguration aktiviert wurde. Grob zusammengefasst sind die Schritte:
- Das Projekt für das Floorplanning vorbereiten
- Eine erste Projekteinrichtung für partielle Rekonfiguration vornehmen
- Floorplanning durchführen
- Das Floorplanning anhand einer Implementierung des Designs prüfen und korrigieren
- Ein zweites rekonfigurierbares Modul (oder mehrere Module) hinzufügen
- Eine Implementierung durchführen, um Bitstrom-Dateien (Bitstream-Dateien) zu erhalten
- Das Projekt überprüfen
Vorbereitung für das Floorplanning
Mehr als jede andere Aufgabe erfordert das Floorplanning Denkarbeit. Es ist eine feine Balance zwischen dem Vermeiden von verschwendeter FPGA-Fläche und der Gewissheit, dass weder die statische Partition noch die rekonfigurierbaren Partitionen beim Platzieren und Verdrahten (Place and Route) vor größeren Hindernissen stehen.
Entsprechend widmet sich der Großteil dieses Beitrags genau diesem Thema.
In der fernen Vergangenheit war Floorplanning eine Technik, um die Timing-Constraints einzuhalten (Timing Closure). Es half den Tools, die Logik sinnvoll anzuordnen. Da die FPGA-Design-Tools im Laufe der Zeit immer besser geworden sind, ist es viele Jahre her, seit ich zuletzt gesehen habe, dass Floorplanning tatsächlich zum Erreichen der Timing-Constraints beigetragen hat. Heutzutage ist die beste Strategie fast immer, die Entscheidungen den Tools zu überlassen.
Bei der partiellen Rekonfiguration ist Floorplanning jedoch ein Muss. Das Ziel ist also, nichts schlimmer zu machen. Das ist meist eine Sache von Versuch und Irrtum. Der einfachste Weg zu guten Ergebnissen ist jedoch, zunächst eine Implementierung des Designs ohne Floorplanning durchzuführen und dann von der natürlichen Platzierung der Logik auszugehen. Im nächsten Schritt versucht man, die Bereiche so zu organisieren, dass es im Sinne der partiellen Rekonfiguration Sinn ergibt – mit der ursprünglichen Platzierung der Logik als Leitlinie.
Im Plugin-Nutzungsszenario kann das Floorplanning angepasst werden, während sich das Projekt im Laufe der Zeit weiterentwickelt. Das gilt jedoch nicht für das Remote-Update-Szenario, also wenn partielle Rekonfiguration dazu dient, Versionen eines bereits freigegebenen Designs zu aktualisieren: Beim Remote Update müssen alle partiellen Bitströme zum initialen Bitstrom passen. Dementsprechend ist der Teil des Designs mit statischer Logik eingefroren, sobald der initiale Bitstrom freigegeben wurde. Das bedeutet unter anderem, dass auch das Floorplanning unverändert bleiben muss.
Schon bevor man mit der partiellen Rekonfiguration beginnt, besteht die erste Aufgabe also darin, einen geeigneten Bereich im FPGA für die statische Logik zu finden. Es hat keinen Sinn, zu viel Zeit darauf zu verwenden – es reicht, einen Ausgangspunkt zu haben, mit dem man weitermachen kann, nachdem das Projekt in zwei Teile aufgeteilt wurde.
Lassen Sie sich nicht verwirren: Der Zweck dieses ersten Schritts ist nicht das Floorplanning an sich, sondern zu sehen, wie Vivado die Logik ohne Einschränkungen platziert, um daraus abzuleiten, welcher Bereich für die statische Logik reserviert werden soll. Die Schritte sind also:
- Führen Sie wie gewohnt eine Implementierung des Designs durch. Öffnen Sie das implementierte Design und betrachten Sie die Device-Ansicht. Versuchen Sie ein Gefühl dafür zu bekommen, wie viele Logikressourcen das statische Design verbraucht und wo Vivado sie bevorzugt platziert.
- Möglicherweise fällt das leichter, wenn die Teile, die als rekonfigurierbare Logik vorgesehen sind, vorübergehend aus dem Projekt entfernt werden (aber so, dass die statische Logik dadurch nicht wegen Logikoptimierung ebenfalls entfernt wird).
- Stellen Sie sicher, dass in der Device-Ansicht kein Logikelement ausgewählt ist, klicken Sie mit der rechten Maustaste irgendwo auf die Ansicht und wählen Sie „Draw Pblock“. Zeichnen Sie eine Region, die geeignet erscheint, die statische Logik aufzunehmen. Übernehmen Sie nicht unbedingt die Platzierung, die Vivado vorgenommen hat, sondern versuchen Sie, eine Form zu finden, die eine minimale Fläche belegt, ohne Hindernisse für die Platzierung der Logik und für das Erreichen der Timing-Constraints zu schaffen.
- Vivado öffnet daraufhin einen Dialog mit „Create a new Pblock“. Möglicherweise wird vorgeschlagen, den Pblock über Clock Regions zu definieren. Wenn das der Fall ist, tun Sie das nicht. Legen Sie den Pblock auf der Grundlage von Slices, DSPs und gegebenenfalls anderen Logikelementen an.
- Bei Ultrascale-FPGAs schlägt der Pblock-Dialog möglicherweise auch die Einbeziehung von IOBs vor. Deaktivieren Sie diese Option, sonst kann Vivado später beim Speichern oder Ändern der Größe des Pblocks hängen bleiben (wegen eines Bugs in Vivado).
- Achten Sie auf die Form des Pblocks, insbesondere auf den Bereich der Slices. Diese Information erhalten Sie im Eigenschaftenbereich des Pblocks in Vivados GUI (unter dem Reiter „General“) oder aus der Tcl-Konsole, wo etwa Folgendes geschrieben wird:
startgroup create_pblock pblock_1 resize_pblock pblock_1 -add {SLICE_X108Y148:SLICE_X149Y249 DSP48_X4Y60:DSP48_X5Y99 RAMB18_X4Y60:RAMB18_X6Y99 RAMB36_X4Y30:RAMB36_X6Y49} endgroup - Wenn in der Tcl-Konsole Warnungen erscheinen, ignorieren Sie sie.
- Beim Schließen des implementierten Designs fragt Vivado, ob gespeichert werden soll. Wählen Sie „No“, denn der eben erzeugte Pblock hat keinen Nutzen.
Ein Projekt für partielle Rekonfiguration einrichten
Xilinx' UG909 schlägt zwei Arbeitsabläufe für die partielle Rekonfiguration vor:
- Den Non-Project-Flow (in Kapitel 3), bei dem die Implementierung durch explizites Schreiben und Ausführen von Tcl-Skripten erfolgt.
- Den Project-Flow (in Kapitel 4), der der Verwendung der Vivado-GUI und der von ihr automatisch erzeugten Skripte entspricht.
Ich verwende hier den Project-Flow, auch wenn er einige Einschränkungen hat, von denen manche die Art der Quellen im rekonfigurierbaren Modul betreffen (insbesondere bei der Verwendung von Blockdesigns). Wie auch immer, es ist besser, mit dem Project-Flow zu beginnen, denn die dabei erzeugten Skripte für die Implementierung sind eine gute Grundlage für den Non-Project-Flow, falls dieser später benötigt wird.
Das sind die Schritte, um die Unterstützung für partielle Rekonfiguration in einem bestehenden Projekt zu aktivieren:
- Wählen Sie Tools > Enable Dynamic Function eXchange… und klicken Sie auf „Convert“. Die GUI sorgt dafür, dass Ihnen bewusst ist, dass die Umstellung des Projekts auf den Partial-Reconfiguration-Ablauf irreversibel ist – stimmen Sie also zu. Der Tcl-Befehl, der dabei tatsächlich ausgeführt wird, lautet:
set_property PR_FLOW 1 [current_project]
- Entscheiden Sie, welches Modul das Top-Level-Modul für die rekonfigurierbare Partition sein soll, und klicken Sie mit der rechten Maustaste auf dessen Quelldatei im Bereich Sources des Project Managers in Vivado. Wählen Sie „Create Partition Definition…“. Diese Option ist erst nach dem Aktivieren von DFX verfügbar – aber das haben Sie gerade getan.
- Daraufhin erscheint ein Dialog „Create Partition Definition“, der zwei Dinge abfragt: Den Namen für die Partition Definition. Dieser Name bezieht sich auf die Stelle in der Hierarchie, an der verschiedene rekonfigurierbare Module eingefügt werden können. Ein passender Name könnte „pr“ sein. Das zweite ist der Name des rekonfigurierbaren Moduls (Reconfigurable Module Name). Er gibt an, welche Logik in die Partition geht. Wenn partielle Rekonfiguration beispielsweise dazu dient, einen Audiofilter auszutauschen, wären sinnvolle Namen für das rekonfigurierbare Modul „lpf“, „bpf“ oder „hpf“, weil jeder Name aussagt, welcher Filter verwendet wird. Es kann auch der Name des Top-Level-Moduls sein, wenn das zum Verständnis beiträgt.
- Die Zeile des gewählten Moduls in der Quellenliste erscheint nun mit einer gelben Raute, zusammen mit dem Namen des Moduls und dem Instanznamen (z.B. „pr_block“ und „pr_block_ins“), wie in der Verilog-/VHDL-Datei definiert. Diese Namen sagen nichts darüber aus, welche Logik in die Partition eingesetzt wird, sondern entsprechen den Namen im HDL. Die Partition und das rekonfigurierbare Modul finden Sie im Reiter „Partition Definitions“ desselben Quellenbereichs.
- Wenn sich im rekonfigurierbaren Modul Instanziierungen von IP (z.B. ein FIFO) befinden, kann die IP hinzugefügt werden, indem man mit der rechten Maustaste auf ihre Zeile in den Quellen des Hauptprojekts (unter dem Bereich „Hierarchy“) klickt und „Move to configurable module…“ wählt. Das zugehörige Tcl-Kommando sieht zum Beispiel so aus:
move_files -of_objects [get_reconfig_modules lpf] [get_files /path/to/blkmem.xci]Dadurch wird die IP in den Reiter „Partition Definitions“ verschoben. - Nicht nur das: Der Reiter „Partition Definitions“ funktioniert wie eine Sammlung von Quellhierarchien für jedes rekonfigurierbare Modul. Um zum Beispiel HDL-Dateien hinzuzufügen, die ein rekonfigurierbares Modul benötigt, klicken Sie unter diesem Reiter auf „+“.
- Sobald das rekonfigurierbare Modul eingerichtet ist, definieren Sie die Parent-Implementierung (siehe vorheriger Beitrag zu Parent-Implementierungen, Child-Implementierungen und dem Wizard):
- Wählen Sie Tools > Dynamic Function eXchange Wizard.
- Klicken Sie auf der Willkommensseite und auf der Seite zum Bearbeiten der rekonfigurierbaren Module auf Next.
- Klicken Sie auf der Seite „Edit Configurations“ auf „+“, um eine Konfiguration hinzuzufügen. Die Standardbezeichnung config_1 ist in Ordnung, denn sie spielt keine große Rolle. Standardmäßig wählt Vivado für config_1 korrekt das rekonfigurierbare Modul aus – keine Überraschung, da es vorerst das einzige ist.
- Der nächste Bildschirm dient zum Hinzufügen von Konfigurations-Runs: Tun Sie das (vorerst) nicht.
- Beenden Sie den Wizard.
Der Versuch, in diesem Stadium eine Implementierung des Projekts durchzuführen, schlägt höchstwahrscheinlich mit einem Fehler fehl, der etwa so aussieht: „[DRP HDPR-30] Missing PBLOCK On Reconfigurable Cell: HD.RECONFIGURABLE cell 'pr_block_ins' must have PBLOCK assigned to itself or its descendant cells“. Einfach ausgedrückt bedeutet das, dass ein Floorplanning nötig ist.
Floorplanning durchführen
In diesem Stadium ist das Projekt gerade so weit eingerichtet, dass die Floorplanning-Aufgabe durchgeführt werden kann.
Bevor wir diese Aufgabe in kleine Schritte zerlegen, sind ein paar Dinge zu beachten:
- Die Fläche auf dem FPGA für die statische Logik sollte so klein wie möglich sein, aber ohne die Platzierung und Verdrahtung (Place and Route) zu erschweren. Eine grobe Abschätzung ihrer Form sollte bereits zuvor erfolgt sein (siehe „Vorbereitung für das Floorplanning“ oben).
- Die Formen sowohl der statischen als auch der rekonfigurierbaren Logik sollten so einfach wie möglich sein, vorzugsweise einfache Rechtecke oder andere Formen, die beim Routing keine Schwierigkeiten erzeugen.
- Das Routing der statischen Logik darf die Bereiche der rekonfigurierbaren Logik kreuzen. Das Gegenteil gilt in den meisten Fällen jedoch nicht.
- In dieser Floorplanning-Sitzung wird die Form der rekonfigurierbaren Logik gezeichnet. Wegen der beiden letzten Anmerkungen ist es ausgerechnet diese Form, die einfach gehalten werden sollte.
- Beachten Sie die Möglichkeiten und Einschränkungen des Floorplannings für Ihr jeweiliges FPGA, wie in Kapitel 6 bis 8 in UG909 beschrieben. Bei einem Series-7-FPGA ist es zum Beispiel wahrscheinlich am besten, die Grenzen der Bereiche an den Grenzen von Clock Regions auszurichten.
Nun zu den Schritten:
- Starten Sie die Synthese des Projekts (d.h. starten Sie den synth_1-Run). Die Synthese des rekonfigurierbaren Moduls wird automatisch als Out-of-Context-Run (OOC) durchgeführt, z.B. als lpf_synth_1. OOCs werden im letzten Beitrag näher erklärt.
- Sobald die Runs abgeschlossen sind, öffnen Sie das synthetisierte Design (eine Implementierung ist zu diesem Zeitpunkt nicht möglich, weil dem rekonfigurierbaren Modul noch kein Pblock zugeordnet ist).
- Zeichnen Sie einen Pblock für die rekonfigurierbare Logik. Im Gegensatz zur Vorbereitungsphase muss er der rekonfigurierbaren Logik zugeordnet werden. Stellen Sie also sicher, dass der obere linke Bereich auf dem Reiter Netlist geöffnet ist, klicken Sie mit der rechten Maustaste auf die Top-Level-Zelle, die in die rekonfigurierbare Partition geht (z.B. „pr_block_ins“), wählen Sie Floorplanning > Draw Pblock und zeichnen Sie einen Bereich auf dem FPGA. Die GUI-Bedienung erfolgt wie oben beschrieben (in „Vorbereitung für das Floorplanning“). Die Auswahl erfolgt also anhand von Slices und anderen Logikelementen.
- Wenn erneut IOBs zur Aufnahme in den Pblock vorgeschlagen werden, nehmen Sie diesen Vorschlag nicht an, sonst besteht die Gefahr, dass Vivado später bei der Verarbeitung hängen bleibt.
- Verlieren Sie nicht zu viel Zeit damit, denn es ist gut möglich, dass Sie es wegen Vivados Beschwerden korrigieren müssen. Denken Sie auch hier daran: Der Pblock wird für die rekonfigurierbare Logik gezeichnet, und die statische Logik nimmt die restliche Fläche ein.
- Nun zum Pblock-Properties-Fenster. Es kann sein, dass Sie mit der rechten Maustaste auf den Pblock in der Device-Ansicht klicken und „Pblock Properties…“ wählen müssen, damit es erscheint.
- Wählen Sie den Reiter „Properties“ (im Pblock-Properties-Fenster).
- Für Series-7-FPGAs (also nicht Ultrascale und später): Im Pblock-Properties-Fenster wird empfohlen, RESET_AFTER_RECONFIG zu setzen, wenn die Logik nach dem Laden des partiellen Bitstroms den internen FPGA-Reset erhalten soll (siehe nächsten Beitrag für mehr zum Zurücksetzen des rekonfigurierbaren Moduls). Daraus entsteht eine XDC-Constraint wie diese:
set_property RESET_AFTER_RECONFIG true [get_pblocks pblock_pr_block_ins]
Diese Constraint bringt unter anderem Flip-Flops auf ihre Standardwerte. Beachten Sie jedoch, dass das nichts mit Resets zu tun hat, die im HDL oder anderweitig in der Logik definiert sind. Beachten Sie außerdem, dass diese Funktion bei Series-7-FPGAs verlangt, dass die vertikalen Grenzen des Pblocks an Clock Regions ausgerichtet sind.
Bei Ultrascale-FPGAs und später ist dieser Reset immer aktiviert. - Es gibt außerdem die Eigenschaft SNAPPING_MODE, die bei Series-7-FPGAs standardmäßig undefiniert ist (was OFF entspricht). Bei manchen FPGAs wird es vermutlich notwendig, sie auf ROUTING oder ON zu setzen (das ist der Standard bei Ultrascale). Darauf komme ich später zurück.
- Drücken Sie als Nächstes STRG-S, um die Constraints zu speichern (oder klicken Sie auf das Disketten-Symbol in der oberen Leiste). Das fügt der XDC-Datei ein paar Zeilen hinzu, etwa so:
create_pblock pblock_pr_block_ins add_cells_to_pblock [get_pblocks pblock_pr_block_ins] [get_cells -quiet [list pr_block_ins]] resize_pblock [get_pblocks pblock_pr_block_ins] -add {SLICE_X40Y100:SLICE_X79Y149} resize_pblock [get_pblocks pblock_pr_block_ins] -add {DSP48_X2Y40:DSP48_X2Y59} resize_pblock [get_pblocks pblock_pr_block_ins] -add {RAMB18_X2Y40:RAMB18_X2Y59} resize_pblock [get_pblocks pblock_pr_block_ins] -add {RAMB36_X2Y20:RAMB36_X2Y29} - Schließen Sie das synthetisierte Design.
- Setzen Sie den synth_1-Run zurück.
- Versuchen Sie, einen Bitstrom zu erzeugen (durch Klicken auf „Generate Bitstream“). Zweck dieser Implementierung ist es zu prüfen, ob das Floorplanning irgendwelche Fehler aufweist. Mit anderen Worten: ob Vivado als Reaktion auf solche Fehler kritische Warnungen (Critical Warnings) ausgibt. Das mag wie eine unprofessionelle Methode klingen, ein Design zu validieren, aber sie ist einfach und zuverlässig.
Floorplanning korrigieren
Das ist wahrscheinlich der unangenehmste Teil der partiellen Rekonfiguration: das Floorplanning richtig hinzubekommen. Wenn Sie das für den Remote-Update-Einsatzzweck tun, ist diese Phase besonders wichtig, denn dieses Floorplanning bleibt während der gesamten Lebensdauer des Projekts bestehen.
Korrekturen am Floorplanning sind aus zwei Hauptgründen nötig: als Reaktion auf kritische Warnungen und in einer späteren Phase zur Optimierung der FPGA-Ausnutzung. Das Ziel ist, die Verschwendung von Ressourcen zu reduzieren und gleichzeitig Hindernisse für die Platzierung und Verdrahtung zu vermeiden.
Änderungen sind nicht schwierig, denn die Grenzen eines Pblocks lassen sich leicht verschieben. Man kann einen Pblock auch um weitere Rechtecke erweitern: Mit der rechten Maustaste auf den Pblock klicken und „Add Pblock Rectangle“ wählen.
Die kritischen Warnungen sagen oft, welche Korrekturen nötig sind. Lesen Sie trotzdem das jeweils relevante Kapitel (6, 7 oder 8) in Xilinx' Benutzerhandbuch UG909 zu den Einschränkungen des Floorplannings für Ihr FPGA.
Der Rest dieses Abschnitts behandelt mögliche Probleme mit Series-7-FPGAs. Ultrascale-FPGAs sind deutlich einfacher zu handhaben.
Ein häufiger Fehler bei Series-7-FPGAs ist die Aufteilung von Interconnect-Tile-Spalten, zum Beispiel:
[Constraints 18-993] The Pblock pblock_pr_block_ins has defined an area that causes the splitting of interconnect tile columns. Dynamic Function eXchange requires that the left and right paired interconnect tile columns cannot be split by a reconfigurable boundary. This is caused by either the left or right edge of a Pblock boundary, or by the Pblock spanning over logic types not included in the Pblock ranges. To avoid an unroutable situation, placement will be prohibited from both of these columns. To avoid placement restrictions, modify the Pblock to avoid splitting the two columns. The column of the split contains interconnect tile INT_L_X48Y299 (SLICE_X79Y299 SLICE_X78Y299). Please refer to the Xilinx document on Dynamic Function eXchange. Resolution: Set the Pblock property SNAPPING_MODE to value of ON, or modify the column/X specification of the pblock to avoid this edge.
und
[Constraints 18-996] The split between the left and right columns occurs between a reconfigurable Pblock and Static logic. The static sites are not reconfigurable. The Pblock should be adjusted to remove the column from the Pblock, unless the excluded reconfigurable and static sites are not needed for the design. Note that adjusting the Pblock will prevent prohibits and improve placement of the design, but may reduce the routability if the removed sites were needed to span across the static logic. Failure to modify the Pblock may lead to an unplaceable design if these prohibited sites are required by the design. Resolution: Set the Pblock property SNAPPING_MODE to value of ON, or modify the column/X specification of the pblock to avoid this edge. and
Um das zu beheben, setzen Sie die SNAPPING_MODE-Eigenschaft des Pblocks auf ROUTING oder ON (die Chancen stehen gut, dass ROUTING nicht ausreicht, also wählen Sie ON), wie in der ersten Warnung vorgeschlagen. Dadurch werden der XDC-Datei wahrscheinlich viele Constraints hinzugefügt, etwa dieser Art:
set_property PROHIBIT true [get_sites SLICE_X79Y349] set_property PROHIBIT true [get_sites SLICE_X78Y349] [ ... ] set_property PROHIBIT true [get_sites SLICE_X79Y191] set_property PROHIBIT true [get_sites SLICE_X78Y191] set_property PROHIBIT true [get_sites PMV_X0Y2] set_property PROHIBIT true [get_sites SLICE_X36Y190] set_property PROHIBIT true [get_sites SLICE_X37Y190] [ ... ] set_property PROHIBIT true [get_sites SLICE_X79Y176] set_property PROHIBIT true [get_sites SLICE_X78Y176] set_property PROHIBIT true [get_sites T14] set_property PROHIBIT true [get_sites R15] set_property PROHIBIT true [get_sites XADC_X0Y0] set_property PROHIBIT true [get_sites SLICE_X36Y175] set_property PROHIBIT true [get_sites SLICE_X37Y175] [ ... ]
und so weiter.
Die PROHIBIT-Einstellungen für die Slice-Sites sind diejenigen, die die genannte Critical Warning zum Schweigen bringen. Die übrigen PROHIBIT-Zuweisungen werden für Logik-Sites hinzugefügt, die zwar im geometrischen Bereich liegen, aber auf dem verwendeten FPGA für partielle Rekonfiguration nicht zulässig sind. Ultrascale-FPGAs und neuere erzeugen deutlich weniger PROHIBIT-Zeilen, wenn überhaupt.
Wenn es nur darum geht, die Critical Warning zu unterdrücken, kann man vermutlich alle PROHIBIT-Zeilen entfernen und eine einzige Zeile für die Slice-Sites stehen lassen. Dazu deckt man den Bereich von Slices ab, den Vivado als Reaktion auf die Änderung von SNAPPING_MODE hinzugefügt hat. Verwandeln Sie diesen Bereich also in etwas wie:
set_property PROHIBIT true [get_sites -range {SLICE_X79Y0 SLICE_X79Y349}]
Eine solche Zeile in der XDC-Datei kann das Problem mit der Aufteilung der Interconnect-Spalten lösen, ohne die Datei riesig zu machen.
Unabhängig davon kann auch eine Zeile dieser Art in der XDC-Datei auftauchen. Auch diese Zeile zu entfernen ist offenbar in Ordnung:
set_property HD.PLATFORM_WRAPPER true [get_cells pr_block_ins]
Die XDC-Datei auf das Minimum zu reduzieren, das die Critical Warnings unterdrückt, mag oberflächlich wirken. Die Alternative ist jedoch eine riesige Constraint-Datei, die später nur für Verwirrung sorgt. Meiner Erfahrung nach kann das Fehlen von Warnungen dieser Art als Bestätigung gewertet werden, dass der Floorplan des Designs in Ordnung ist.
Es ist wahrscheinlich, dass das Zurücksetzen der SNAPPING_MODE-Eigenschaft auf OFF unabhängig von den Änderungen an der XDC-Datei wieder Probleme verursacht.
Ein rekonfigurierbares Modul hinzufügen
Bisher erreicht die Implementierung praktisch dasselbe wie ein hierarchisches Design, nur mit ein paar zusätzlichen Einschränkungen. Obwohl ein partieller Bitstrom erzeugt wird, ist er ziemlich nutzlos, denn beim Laden bleibt das Design unverändert.
Das Ziel ist es also, einen weiteren partiellen Bitstrom zu erzeugen, der auf einem anderen rekonfigurierbaren Modul basiert. Dazu muss eine Child-Implementierung hinzugefügt werden.
Vergewissern Sie sich, dass Sie den vorherigen Beitrag frisch im Kopf haben, bevor Sie weiterlesen – insbesondere den Teil über Parent- und Child-Implementierungen sowie den Dynamic Function eXchange Wizard. Erinnern Sie sich außerdem an das, was weiter oben in diesem Beitrag gesagt wurde: Der Reiter „Partition Definitions“ enthält die aktuell definierten rekonfigurierbaren Module und ihre Quellen.
Öffnen Sie den Dynamic Function eXchange Wizard über das Menü Tools und klicken Sie im Willkommensfenster auf Next.
Klicken Sie im Fenster Edit Reconfigurable Modules auf „+“. Dadurch öffnet sich ein Dialog zum Hinzufügen eines rekonfigurierbaren Moduls. Das einzig Interessante an diesem Dialog ist der Name des rekonfigurierbaren Moduls (Reconfigurable Module Name): Das ist der Name, mit dem die rekonfigurierbare Logik identifiziert wird, wie oben bereits erklärt.
Der Dialog verlangt außerdem, dieses Modul mit dem Namen einer Partition Definition zu verknüpfen. Es gibt aber ohnehin nur eine solche Definition (weil dieser Beitrag annimmt, dass nur eine Partition definiert ist).
Mindestens eine Verilog-/VHDL-Quelldatei muss hinzugefügt werden, um fortzufahren: Weitere können später über den Reiter „Partition Definitions“ ergänzt werden. Es schadet nicht, den Namen des Top-Level-Moduls dieses rekonfigurierbaren Moduls anzugeben, insbesondere wenn er aus den Quelldateien selbst nicht hervorgeht.
Zurück im Wizard: Klicken Sie erneut auf Next, zum Fenster Edit Configurations. Klicken Sie auf „+“ und geben Sie einen Konfigurationsnamen ein. Dieser Name ist nur insofern wichtig, als er im Fenster Design Runs erscheint. Ein Name wie config_2 ist in Ordnung.
In der Liste der Konfigurationen erscheint eine neue Zeile. Ändern Sie das rekonfigurierbare Modul in der Spalte für die Partition so, dass jede Konfiguration ein anderes rekonfigurierbares Modul hat.
Das letzte Fenster ist Edit Configuration Runs und dient dazu, Runs Konfigurationen zuzuordnen. Der einfache Weg ist, alle in diesem Fenster aufgeführten Runs zu löschen (falls vorhanden) und auf „automatically create configuration runs“ zu klicken. Das bewirkt, was man ohnehin manuell tun würde: einen Parent-Run anlegen und ihn „impl_1“ nennen, dann Child-Runs anlegen, nach Belieben benennen und sie zu Kindern von „impl_1“ machen.
Der Wizard wählt für jeden Run eine Konfiguration aus – das lässt sich aber leicht ändern. Das einzig Wichtige ist, welche Konfiguration dem Parent-Run zugeordnet ist.
Übrigens: Wenn Sie im Wizard alle Runs löschen, verschwinden alle Child-Runs, aber impl_1 bleibt erhalten.
Endlich: Implementierung des Designs
Zum Erzeugen der Bitströme klicken Sie einfach wie gewohnt auf „Generate Bitstreams“ in Vivado. Wie bereits im vorherigen Beitrag erwähnt, werden bei einem Projekt mit partieller Rekonfiguration für jede Konfiguration zwei oder drei Bitströme erzeugt.
Bei einem Ultrascale-FPGA können die Bitfiles zum Beispiel sein:
- theproject.bit: Die initiale Bitstrom-Datei (Bitstream-Datei), die die statische Logik und die rekonfigurierbare Logik der jeweiligen Konfiguration enthält.
- pr_block_ins_lpf_partial.bit: Der partielle Bitstrom, der die rekonfigurierbare Logik der aktuellen Konfiguration lädt.
- Nur bei Ultrascale gibt es außerdem pr_block_ins_lpf_partial_clear.bit: Der Bitstrom, der vor dem Laden eines beliebigen partiellen Bitstroms geladen werden muss, wenn die aktuelle Konfiguration bereits im FPGA vorhanden ist.
Beachten Sie, dass für alle Implementierungen dieselbe Anzahl an Bitstrom-Dateien erzeugt wird. Mit anderen Worten: Auch für die Child-Implementierungen wird eine initiale Bitstrom-Datei erzeugt. Es ist also ohne Weiteres möglich, das FPGA mit einem der initialen Bitströme einer Child-Implementierung zu laden und von dort aus weiterzumachen.
Für einen einfachen Weg, partielle Bitströme über PCIe oder USB 3.x zu laden, siehe diese Seite.
Keine der Implementierungen sollte Critical Warnings aufweisen oder wegen Beschwerden über den Pblock bzw. das Floorplanning im Allgemeinen fehlschlagen, denn solche Probleme sollten bereits gelöst sein. Sollte so etwas trotzdem passieren, muss das Floorplanning wie oben beschrieben korrigiert werden.
Manchmal kann es vorkommen, dass Vivado beim Klicken auf „Generate Bitstream“ – wenn nur an den Child-Implementierungen Änderungen vorgenommen wurden – antwortet: „Bitstream generation has already completed and is up-to-date. Re-run anyway?“. Das ist etwas verwirrend, aber ein Klick auf „Yes“ führt die Child-Implementierungen ordnungsgemäß aus. Diese ganze Sache mit der Child-Implementierung ist ein kleines Add-on zu Vivado, weshalb in der Statuszeile während der Implementierung auch so etwas wie „write_bitstream complete. Child running“ steht.
Die Ergebnisse überprüfen
Da es bei der partiellen Rekonfiguration stark um Platzierung geht, ist es eine gute Idee, die implementierten Designs zu überprüfen. Sie können eine bestimmte Implementierung öffnen, indem Sie mit der rechten Maustaste auf „Open Implemented Design“ klicken und dann mit der Maus über den Menüpunkt „Open Implemented Design“ (erneut) fahren. Wählen Sie dann aus der Liste die zu öffnende Implementierung aus. Wenn eine Implementierung in der Liste fehlt, ist sie vermutlich bereits geöffnet.
Versuchen Sie, im Bereich Netlist der Implemented-Design-Ansicht mit der rechten Maustaste auf die oberste Zeile der rekonfigurierbaren Logik zu klicken und „Highlight Leaf cells“ zu wählen. Machen Sie dasselbe dann mit der statischen Logik, in einer anderen Farbe.
Mit demselben Rechtsklick gibt es auch „Show Connectivity“. Damit werden gerade weiße Linien zwischen verbundenen Logikelementen gezeichnet. Die tatsächlichen Routing-Pfade auf dem FPGA sind natürlich anders, daher hat es keine Bedeutung, welche Floorplanning-Bereiche diese Linien kreuzen. Die Betrachtung der Verbindungen kann aber trotzdem helfen zu erkennen, wenn die Gesamtorganisation eines Floorplans den Tools das Leben schwer macht.
Es ist völlig normal und in Ordnung, dass einige Zellen, die offenbar zur statischen Logik gehören, innerhalb des rekonfigurierbaren Bereichs platziert sind – und umgekehrt. Worauf man achten sollte, ist, ob es irgendwo eine Überlastung zu geben scheint, also ob die Logik allgemein oder in einer bestimmten Region zu dicht gepackt ist. Falls möglich, können Änderungen am Floorplanning das verbessern.
Ein weiterer Punkt sind die Positionen der Partition Pins. Sie erscheinen als weiße horizontale Balken in der Device-Ansicht, etwa so (Bild zum Vergrößern anklicken):
Wie bereits im vorherigen Beitrag erwähnt, können sich Partition Pins überall innerhalb der rekonfigurierbaren Partition befinden. Wenn die Partition Pins jedoch weit von den Rändern der Partition entfernt liegen, kann das darauf hindeuten, dass der Router während der Parent-Implementierung mit dem Timing zu kämpfen hatte.
Eine Textliste mit den Koordinaten der Partition Pins erhalten Sie mit diesem Tcl-Befehl (ändern Sie pr_block_ins in den Namen der rekonfigurierbaren Logikzelle):
foreach s [get_pins -of [get_cells pr_block_ins]] { set partpin [get_pplocs -quiet -pins [get_pins $s]] ; puts "$s => $partpin"; }
Die Koordinaten der Partition Pins entsprechen dem Raster der CLBs (und nicht dem der Slices). In der angezeigten Zeichnung werden diese Pins als „Cell pins“ bezeichnet.
Einige Pins der Zelle haben möglicherweise keinen Partition Pin zugewiesen. Das passiert, wenn die Portliste des rekonfigurierbaren Moduls (und/oder die Breiten von Vektoren) nicht zu seiner Instanziierung durch die statische Logik passt. Eine solche Diskrepanz ist in Verilog völlig legal, aber das Ergebnis kann unerwünscht sein. Mit diesem Tcl-Befehl lassen sich solche unerreichbaren Ports erkennen, insbesondere wenn das nicht beabsichtigt ist.
Damit endet der technische Teil zum Einrichten des Vivado-Projekts. Der nächste Beitrag behandelt jedoch einen wichtigen Aspekt des FPGA-Designs: Wie man sicherstellt, dass der Austausch von Logik zuverlässig und reibungslos abläuft.
