Es ist normalerweise eine der ersten Entscheidungen in der Entwicklung von Embedded-Systemen: Soll man eine Funktion in Hard- oder Software realisieren? Klar, Software ist flexibler und deutlich leichter zu schreiben, aber in vielen Fällen reichen die Rechen-Ressourcen nicht. Also empfiehlt es sich, zumindest die zeitraubenden Routinen in Hardware auszulagern – oft heißt das, einen FPGA einzudesignen. Mit einem High-Level-Synthese-Tool wie Vivado HLS von Xilinx können Entwickler die Entscheidung auch nachträglich fällen: Sie setzen dazu auf das „All Programmable SoC“ Zynq-7000, das einen Dual-Core-ARM-Prozessor vom Typ Cortex-A9 mit FPGA-Logik kombiniert. Dann können sie ihre Routinen zunächst in C, C++ oder System-C entwickeln und bei Bedarf den Quellcode in gut abgestimmten RTL-Code für den FPGA übersetzen. Die Technologie wird von vielen Anbietern genutzt, und ihre Anwendung hat in den letzten Jahren stark zugenommen.

Auf einen Blick

Vivado HLS bringt lahme Software auf Trab: Der Entwickler lässt den Großteil seines Codes klassisch auf dem ARM-Core im Zync SoC laufen. Nur die laufzeitkritischen Teile verlagert er in einen Hardware-Beschleuniger. Das High-Level-Synthesewerkzeug Vivaldo HLS nimmt dabei den vorhandenen C- oder C++-Code und erzeugt daraus einen IP-Block. Über User-I/O kann der Entwickler diesen Beschleuniger sehr einfach aus der Linux-Umgebung aufrufen, ohne einen Gerätetreiber entwickeln zu müssen.

Fragt sich, wie kompliziert es ist, die laufzeitkritischen Teile des Codes in Hardware zu verlagern, und ob dies auch für anspruchsvollere Berechnungen möglich ist. Embedded-Programmierer arbeiten heute meist mit C oder C++; praktischerweise akzeptiert Vivado HLS beides als Eingabe. Durch den ARM-Core kann man den größten Teil der Software in konventionellen Umgebungen laufen lassen. Xilinx bietet hierfür zum Beispiel ein Software-Entwicklungskit (SDK) und Peta-Linux als Betriebssystem.

Architekturfragen

Aus der Software-Perspektive gibt es einiges zu bedenken, speziell die benötigte Software-Schnittstelle. Denn HLS erstellt Hardware, die auf die Verarbeitung von Hardware-Schnittstellen ausgerichtet ist. Jeder wünscht sich Systeme, die einen einfachen Zugang bieten, etwa einen Coprozessor oder Hardware-Accelerator, um die Ausführung der Software zu beschleunigen. Auch das Schreiben eines neuen Compilers möchte man tunlichst vermeiden. Und um den Datenaustausch mit der übrigen Software einfach zu halten, sollte die Schnittstelle wie eine einfache Speicherstelle aussehen, auf der man die Eingaben platzieren und anschließend die Ergebnisse abruft.

Bild 1: Matrix-Berechnungen lassen sich gut parallelisieren und eignen sich daher für einen Hardware-Beschleuniger. Beim Aufruf gibt der Entwickler die gewünschte Operation und die Operanden an.

Bild 1: Matrix-Berechnungen lassen sich gut parallelisieren und eignen sich daher für einen Hardware-Beschleuniger. Beim Aufruf gibt der Entwickler die gewünschte Operation und die Operanden an.Xilinx

Vivado HLS kann mit relativ geringem Aufwand einen AXI-Slave erzeugen, den der Entwickler dann als Hardware-Beschleuniger in seinen Code einbindet. Ein einfaches Beispiel soll dieses Verfahren zeigen: Es dreht sich um die Modellierung eines Satzes von einfachen Matrixoperationen wie Addieren und Multiplizieren. Diese sollen nicht durch feste Größenbedingungen eingeschränkt sein. Das heißt, man gibt die Arrays und deren jeweilige Größe im Eingang vor. Eine ideale Schnittstelle würde alle Werte als einfache Argumente einer Funktion anschreiben, wie im Code-Beispiel nach Bild 1 aufgeführt.

Datenübergabe

Bild 2: Speicher-Layout für die Übergabe der Matrizen und der gewünschten Berechnung an die Register des Hardware-Moduls.

Bild 2: Speicher-Layout für die Übergabe der Matrizen und der gewünschten Berechnung an die Register des Hardware-Moduls.Xilinx

Die Hardware-Schnittstelle benötigt nun eine einfache Methode für das Mapping der Argumente der Funktionen auf die zugehörigen Speicherplätze. Bild 2 zeigt ein Speicher-Layout, das dieses Mapping unterstützt. Die Register halten Informationen über die Auslegung der Matrizen, und was die gewünschten Operationen sein sollen. Das Befehlsregister zeigt an, welche Operation auszuführen ist. Das erlaubt die Kombination mehrerer einfacher Operationen auf einem einzigen Hardware-System. Das Statusregister fungiert als Anzeige, welche Operation gerade läuft, oder ob sie bereits erfolgreich abgeschlossen wurde. Idealerweise würde dieses Layout auch die Behandlung von Interrupts ermöglichen.

Bild 3: Einfaches API für einen Hardwarebeschleuniger.

Bild 3: Einfaches API für einen Hardwarebeschleuniger.Xilinx

In Bezug auf das Hardware-Design ist vorteilhaft, dass Vivado HLS auch Array-Argumente zur Spezifizierung kleiner Speicherbereiche erlaubt. Deren Funktionalität lässt sich anhand einer Funktion nach Bild 3 beschreiben. Unter der Annahme, dass die Synthetisierung des AXI-Slaves möglich ist, stellt sich die Frage, wie dies mit der Software zusammengeht. Eine normale Codier-Umgebung geht davon aus, dass Linux vorliegt, zum Beispiel Peta-Linux von Xilinx. Dieses bietet einen Mechanismus, der als User-I/O-Device bekannt ist. UIO bietet ein einfaches Verfahren, das das Mapping der neuen Hardware in den Speicherbereich des Users erlaubt. Es bietet außerdem die Möglichkeit, einen Interrupt abzuwarten. Der Entwickler muss also nicht erst einen eigenen Gerätetreiber schreiben. Bild 4 beschreibt das System.

Bild 4: Wenn der Entwickler Teile seines Codes in Hardware auslagert, kann er diese Beschleuniger über Linux-Treiber ansprechen und so in die restliche Software einbinden.

Bild 4: Wenn der Entwickler Teile seines Codes in Hardware auslagert, kann er diese Beschleuniger über Linux-Treiber ansprechen und so in die restliche Software einbinden.Xilinx

Allerdings hat dieses Vorgehen auch einige Nachteile. So kann man das UIO-Device nicht mit DMA (Direct Memory Access) kombinieren. Also muss man im Gerätespeicher Matrizen anlegen und diese anschließend manuell auskopieren. In Zukunft könnte ein kundenspezifischer Gerätetreiber diesen Vorgang, falls gewünscht, übernehmen.

Hardware-Synthese mit Vivaldo HLS

Zurück zur Synthese des AXI-Slaves. Das sollte keine Schwierigkeiten bereiten, denn die Code-Restriktionen sind recht akzeptabel ausgelegt. Der größte Teil der C++-Sprache lässt sich einsetzen, ausgenommen dynamische Speicherbelegung. Die Hardware erzeugt sich schließlich nicht selbst während des Betriebs. Leider ist damit auch der Einsatz der Standard Template Library (STL) eingeschränkt, denn diese macht stark Gebrauch von der dynamischen Speicherallokation. Doch solange die Daten statisch sind, kann man auf die meisten Features frei zugreifen. Auch wenn dieser Vorgang zunächst etwas umständlich wirkt, stellt sich schnell heraus, dass dies keine große Einschränkung ist. Auch erlaubt Vivado HLS den Einsatz von C++-Klassen, Templates und Funktionen, sowie das Überladen von Methoden und Operatoren. Die so erstellten Matrix-Operationen lassen sich anstandslos in eine kundenspezifische Matrixklasse einbauen.

Das Hinzufügen der I/O-Bedingungen zum Erstellen eines AXI-Slaves ist ebenfalls sehr einfach. Dazu setzt man einige Compiler-Pragmas ein, die anzeigen, welche Ports involviert sind, und welches Protokoll sie verwenden.

Bild 5: Die Einzelschritte im Designfluss.

Bild 5: Die Einzelschritte im Designfluss.Xilinx

Auch der Betrieb des Synthese-Tools stellt sich als ziemlich einfach heraus – so lange man nicht an allen Knöpfen gleichzeitig dreht. Bild 5 gibt einen Überblick der erforderlichen Schritte, die hier nicht in allen Details abgehandelt werden sollen. Man behält die Reports im Auge, die Abweichungen vom Prozess dokumentieren, und verfolgt den Analyse-Report, um sicher zu gehen, dass Vivado HLS das tut, was man von ihm erwartet. Die Anwender des Tools sollten natürlich etwas über dessen Hardware-Aspekte wissen, doch es gibt Technologie-Kurse, die das effizient erledigen. Auch eine Simulation vor und nach der Synthese erfordert die Aufmerksamkeit des Anwenders, um die vorgesehene Funktion zu verifizieren.

Der Vivado-IP-Integrator macht den Anschluss des AXI-Slaves an die Zynq-SoC-Hardware zum sprichwörtlichen Kinderspiel. Der Anwender läuft nicht Gefahr, Signalpfade falsch zu verbinden. Xilinx bietet sogar ein Profil für das Entwicklungssystem, Zed-Board genannt, und der IP-Integrator exportiert die Daten für das Software-Entwicklungskit.

Engpässe beseitigen

Die Ergebnisse der Arbeit mit dem High-Level-Synthese-Tool haben den Autor dieses Beitrags rundum zufriedengestellt. Die Werkzeuge laden zu weiterer intensiver Beschäftigung mit dieser Chip- und Toolset-Kombination ein. Es braucht etwas Zeit, um alle Möglichkeiten auszureizen. So unterstützt Vivado HLS auch ein AXI-Master-Interface. Mit AXI kann der Accelerator die Matrizen vom externen Speicher kopieren (obwohl in dieser Frage individuelle Sicherheitsvorschriften gelten können). Nichtsdestotrotz ist dieses Toolset zu empfehlen, wenn man mit Code-Engpässen in der Entwicklung zu kämpfen hat.