Technische Artikel

Model-Based Design von Kommunikationsprotokollen zur Implementierung auf FPGAs

Von Hung Nguyen, Sandia National Laboratories; William Marchetto, Sandia National Laboratories; Roger Theyyunni, MathWorks; and Babak Soheili, MathWorks


Um die Entwicklungskosten für Embedded Systems zu senken und zugleich die Entwicklung zu beschleunigen sowie die Zuverlässigkeit zu wahren, geht die Branche zu rekonfigurierbaren Architekturen über. Diese können an zukünftige Systemanforderungen angepasst werden und Systemausfälle abfedern. Diese rekonfigurierbaren Subsysteme basieren im Allgemeinen auf FPGA-Hardware mit beschränkten Ressourcen oder auf vollwertigen Mehrprozessorsystemen mit speziellen DSPs.

Für den Einsatz auf FPGAs ist eine Entwicklung in Verilog® oder VHDL® erforderlich, während für den Einsatz auf einem Prozessor in C/C++ entwickelt werden muss. Viele Algorithmen und Komponenten, vor allem kommunikationsbezogene, müssen sowohl auf prozessorbasierten als auch auf FPGA-basierten Subsystemen einsetzbar sein.

Sandia National Laboratories hat ein Projekt mit Consultants von MathWorks initiiert, um Model-Based Design für derartige Anwendungen zu evaluieren. Mit Model-Based Design können sie Code in C/C++ oder HDL aus Blockdiagrammen generieren und dieselben Algorithmen auf prozessorbasierten und auf FPGA-basierten Subsystemen einsetzen. Im Rahmen des Projekts wurden zwei standardisierte Kommunikationsprotokolle auf einem FPGA implementiert: JPP (Joint Architecture Standard Packet Protocol) und JRDDP (Joint Architecture Standard Reliable Data Delivery Protocol). JPP und JRDDP sind Protokolle auf höherer Schicht, die auf SpaceWire aufsetzen, einer häufig verwendeten Bitübertragungsschicht für die Kommunikation zwischen Modulen in Embedded Systems. Sandia National Laboratories verwendete eine manuell programmierte Version dieser Protokolle, um die mit Model-Based Design entwickelte Implementierung zu evaluieren.

In diesem Artikel wird das Projekt beschrieben. Der Schwerpunkt liegt dabei auf der Modellarchitektur und auf den verwendeten Verifikationstechniken. Es wird gezeigt, dass Model-Based Design sehr gut für die Protokollimplementierung geeignet ist.

Designanforderungen

Mit den Kommunikationsprotokollen JPP und JRDDP wird angegeben, wie Daten von einem Quell- zu einem Zielknoten übertragen werden sollen. Angegeben werden das Paketformat und die Reihenfolge, in der Pakete übertragen und erneut übertragen werden sollen.

Da die zur Implementierung dieser Protokolle erforderlichen Aktionen vordefiniert und sequenziell sind, lag es nahe, Zustandsautomaten zu wählen. Für die Implementierung der Zustandsautomaten, mit denen der C- und HDL-Code für diese Protokolle modelliert und generiert wird, fiel unsere Wahl auf Simulink® und Stateflow.

Modellarchitektur

Im Rahmen des Projekts entwickelten wir JPP- und JRDDP-Modelle mit Simulink und Stateflow. Als Best-Effort-Protokoll erforderte JPP lediglich einen Senderblock und einen Empfängerblock. JRDDP war komplizierter. Als zuverlässiges Paketübertragungsprotokoll, das für die garantierte Datenübertragung zwischen Anwendungen verwendet wird, erforderte es Sende- und Empfangsblöcke, sowohl für Datenpakete als auch für Steuerpakete.

Die für dieses Projekt entwickelten Blöcke wurden für die Implementierung auf Hardware (einem FPGA) optimiert. Die Benutzeranwendung muss Datenbytes mit der Systemtaktfrequenz zu und von den Blöcken streamen. Der Senderblock stellt einen Dual-Port RAM-Block bereit, in den die Benutzeranwendung Daten streamt, bevor ein Übertragungsstartsignal ausgelöst wird.

Der Empfängerblock verwaltet zwei Dual-Port RAM-Bänke, in die die empfangenen Daten bei ihrem Eintreffen gestreamt werden. Wenn ein vollständiges Paket in der entsprechenden Bank verfügbar ist, wird ein Signal gepulst, um die Benutzeranwendung hierüber zu informieren.

Abbildung 1 zeigt die Schnittstelle zwischen der Benutzeranwendung und der JPP-Schnittstelle.

Abbildung 1 zeigt die Schnittstelle zwischen der Benutzeranwendung und der JPP-Schnittstelle.

Alle Senderblöcke haben ähnliche Strukturen. Abbildung 2 zeigt die Architektur der obersten Ebene für den JPP-Senderblock.

Abbildung 2: JPP-Sender

Abbildung 2: JPP-Sender

Der Senderblock stellt eine Verbindung mit der Benutzeranwendung einerseits und einer SpaceWire-Schnittstelle andererseits her.

Empfängerblöcke haben eine ähnliche Struktur (Abbildung 3).

Abbildung 3. JPP-Empfänger

Abbildung 3. JPP-Empfänger

Abbildung 4 zeigt eine vollständige Anwendung, die mithilfe des JPP-Protokolls Daten sendet und empfängt.

Abbildung 4: Vollständige JPP-basierte Anwendung. Eine Senderanwendung (oben links) generiert Daten, die dann mithilfe von JPP an eine Empfängeranwendung übertragen werden (oben rechts). Der JPP-Sender und -Empfänger (Mitte) sind mit der SpaceWire-Schnittstelle verdrahtet.

Abbildung 4: Vollständige JPP-basierte Anwendung. Eine Senderanwendung (oben links) generiert Daten, die dann mithilfe von JPP an eine Empfängeranwendung übertragen werden (oben rechts). Der JPP-Sender und -Empfänger (Mitte) sind mit der SpaceWire-Schnittstelle verdrahtet.

Implementieren des JRDDP-Protokolls auf höherer Schicht

Als Protokoll auf höherer Schicht ist JRDDP schwieriger zu modellieren als JPP. Mit JRDDP wird die Kommunikation zwischen einem sendenden und einem empfangenden Endpunkt definiert, die während der Initialisierungsphase miteinander verbunden werden. Ein Knoten kann mehrere sendende und empfangende Endpunkte besitzen. Für einen vollständigen JRDDP-Endpunkt müssen die grundlegenden JRDDP-Blöcke miteinander verbunden und mit einem Zeitablauf versehen werden.

Um den Prozess zu veranschaulichen, haben wir einen Beispielsender mit zwei Sendeendpunkten und einen Beispielempfänger mit zwei Empfangsendpunkten entwickelt.

Mit JRDDP werden die unterschiedlichen Zustände definiert, die ein Endpunkt durchlaufen muss. Der Anfangszustand eines Endpunkts ist „geschlossen“. Wenn die Benutzeranwendung das Öffnen des Endpunkts anfordert, geht dieser in den Zustand „aktiviert“ über, in dem er eine Öffnungsanforderung an einen Remote-Endpunkt sendet. Bei Erhalt der Bestätigung geht der Endpunkt in den Zustand „geöffnet“ über. Im Zustand „geöffnet“ kann die Benutzeranwendung Daten an den Remote-Knoten übertragen.

Mit Model-Based Design können wir diesen komplexen Prozess in einem Stateflow-Diagramm erfassen (Abbildung 5).

Abbildung 5: JRDDP-Zustandsdiagramm

Abbildung 5: JRDDP-Zustandsdiagramm

Für eine vollständige JRDDP-Implementierung müssen JRDDP-Zustandsautomaten für die einzelnen Endpunkte verwaltet werden, und es müssen JRDDP-Bausteine verwendet werden: ein JRDDP-Senderblock, ein JRDDP-Empfängerblock und ein JRDDP-Block für Steuer- und Bestätigungspakete. Wir mussten Simulink- und Stateflow-Blöcke erstellen, um Daten von der SpaceWire-Schnittstelle zum Zustandsautomaten für den entsprechenden Endpunkt und zurück zu leiten.

Abbildung 6 zeigt eine JRDDP-Endpunktimplementierung für zwei Sendeendpunkte. Oben befinden sich zwei JRDDP-Zustandsautomaten: einer pro Endpunkt. Das zentrale Stateflow-Diagramm ist ein Paketrouter, der Steuer- und Datenpakete von jedem Zustandsautomaten zum Steuer- oder Datensenderblock leitet. Das Diagramm umfasst einen Datenempfänger, der das erhaltene Paket an den entsprechenden Endpunkt-Zustandsautomaten leitet.

Abbildung 6: JRDDP-Sendeendpunkt mit zwei Kanälen

Abbildung 6: JRDDP-Sendeendpunkt mit zwei Kanälen

Integrieren von Sandia IP für eine SpaceWire-Schnittstelle

Sandia hat ein eigenes IP (Intellectual Property) in VHDL entwickelt, um Sende- und Empfangsendpunkte zu SpaceWire zu erstellen. Es war Sandia wichtig zu evaluieren, wie leicht dieses IP, das mehrere Jahre lang in der Produktion verwendet wurde, in den HDL-Code integriert werden konnte, der mit HDL Coder™ aus dem Simulink-Modell generiert wurde.

Simulink ermöglicht das Blackboxing: die Erstellung von Subsystemen, die nur Schnittstellen-Ports für die Instanziierung manuell geschriebener Entities enthalten. Der Entwickler kann das leere Subsystem mit einer externen VHDL-Entity oder einem Verilog Module verknüpfen. Wir verwendeten Blackboxing, um eine Schnittstelle zwischen dem SpaceWire IP von Sandia und unserem Simulink-Modell zu erstellen und so vollständige JPP- und JRDDP-Protokollschnittstellen zu entwickeln. Außerdem verwendeten wir Blackboxing, um die mit Simulink generierte JPP-Schnittstelle gegenüber der manuell codierten JPP-Protokollimplementierung von Sandia zu testen.

Verifikation und Tests

Die Entwicklung von Protokollen in Simulink bietet mehrere Vorteile, insbesondere die Möglichkeit, das Protokoll auf sehr hoher Ebene zu testen. Auf dieser Ebene ist das Debugging kostengünstiger, leichter und schneller als auf Hardware oder in Hardwaresimulatoren. Wir haben unsere Verifikation in fünf Schritten durchgeführt:

  1. Wir haben die Übertragung und den Empfang von Nachrichten in Simulink simuliert. Hierfür erstellten wir ein funktionelles Modell der SpaceWire-Schnittstelle in Stateflow. Simulink ermöglicht ein Debugging auf hoher Ebene, indem der Anwender Haltepunkte auf Blockebene, in Stateflow-Zuständen und während Zustandsübergängen festlegen kann. Außerdem ermöglicht Simulink eine Animation der Zustandsübergänge und somit eine optische Verifikation des gewünschten Modellverhaltens.
  2. Wir verwendeten HDL Verifier™, um den generierten VHDL-Code mit dem Simulink-Modell zu kosimulieren und so zu beweisen, dass der aus Simulink generierte VHDL-Code dieselben Ergebnisse erzeugt, wie das ursprüngliche Simulink-Modell. Hierfür vergleicht HDL Verifier™ automatisch die Ergebnisse und stellt die Fehler dar. In diesem Schritt verwendeten wir Stateflow, um die SpaceWire-Schnittstelle zu emulieren; wir verwendeten nicht das tatsächliche IP von SpaceWire.
  3. Wir verwendeten wiederum Kosimulation und ersetzten unser funktionelles Modell für SpaceWire durch das Sandia IP für die SpaceWire-Schnittstelle. Wir verwendeten das Kosimulationsmodell, um Testsignale in ModelSim einzuspeisen, und erfassten die Ergebnisse in Simulink.
  4. Wir ersetzten den Empfänger durch die manuell codierte Implementierung des JPP-Empfängers von Sandia.
  5. Wir ersetzten den in Simulink und Stateflow entwickelten JPP-Empfänger durch den JPP-Empfänger von Sandia in VHDL und führten einen weiteren Kosimulationstest aus. Der Test bestätigte, dass die beiden JPP-Empfänger austauschbar sind.

Schlussfolgerungen

Mit diesem Projekt wurde bestätigt, dass Model-Based Design verwendet werden kann, um Protokolle höherer Kommunikationschichten zu modellieren und in Software und Hardware zu implementieren. Die Modellierung von Protokollen in Simulink und Stateflow hat mehrere Vorteile. Erstens bietet das Modell eine eindeutige, ausführbare Spezifikation für die Protokolle. Zweitens erleichtert die automatische Codegenerierung in C/C++ und HDL eine schnelle Entwicklung von Referenzimplementierungen.

Ein weiterer wesentlicher Vorteil von Model-Based Design ist die Möglichkeit, die Implementierung in einer Softwareumgebung auf hoher Ebene zu debuggen und zu verifizieren. Simulink und Stateflow ermöglichen das Festlegen von Haltepunkten in Zuständen und Zustandsübergängen auf Block- und Signalebene. Stateflow erleichtert außerdem das Debuggen hierarchischer Zustandsautomaten, indem die Zustandsübergänge animiert werden. Nach dem Debugging auf hoher Ebene ermöglichen Kosimulation und FPGA-in-the-Loop-Simulation Debugging und Verifikation des Designs.

Für die JPP-Implementierung betrug die HDL-Ressourcennutzung auf der ML507 (einer auf Virtex® 5 basierenden Platine) etwa 1 %. Für das JRDDP-Protokoll betrug die Ressourcennutzung bei einer Implementierung mit zwei Endpunkten etwa 10 %. Durch weitere Optimierung wird die Ressourcennutzung weiter gesenkt. Ein direkter Vergleich mit der manuell codierten Version war nicht möglich, da sie nicht für die Xilinx®-Plattform implementiert wurde, die Ressourcennutzung für den HDL-Code, der aus dem Simulink- und Stateflow-Modell generiert wurde, war für Sandia jedoch akzeptabel.

Im Model-Based Design kann ein und derselbe Simulinkmodell-Code sowohl in C/C++ zur Implementierung auf einem Prozessor, als auch in HDL zur Implementierung in Hardware (FPGA oder ASIC) generiert werden. Code in HDL und C/C++ kann aus demselben Modell generiert werden, das Simulink-Modell muss jedoch für jede Implementierung separat optimiert werden; hierfür werden Simulink-Funktionen wie Variant Subsystems verwendet. Für eine prozessorbasierte Implementierung erstellt die Benutzeranwendung meist einen Daten-Frame und übergibt ihn an die Protokollschicht. Diese verarbeitet den Frame als Ganzes, nicht als Bytestrom. Eine hardwarebasierte Implementierung empfängt Daten von der Benutzeranwendung Byte für Byte mit der Taktfrequenz der Hardware.

Die Modellierung in einer höheren Programmiersprache wie Simulink und Stateflow ermöglicht auch Personen, die keine Hardwarespezialisten sind, die Erstellung einer Hardwareimplementierung. Wir empfehlen jedoch die Heranziehung eines Hardwarespezialisten für die Optimierung des Designs und die abschließende Integration auf der Zielhardware.

Über die Autorin

Hung Nguyen ist Research and Development Manager bei Sandia National Laboratories für Anwendungen in der Fernerkundung und Verifikation. Sein Schwerpunktbereich ist die Entwicklung fortschrittlicher, intelligenter Erkundungs-Computersysteme für Anwendungen in der nationalen Sicherheit.

William Marchetto ist Computeringenieur bei den Sandia National Laboratories in der Forschung und Entwicklung für Embedded Systems. Zu seiner Arbeit gehören Digital-Design, Embedded Software und HDL-Entwicklung sowie Big-Data-Speicherung und -Analysen für Bodenstationen.

Roger Theyyunni ist Senior Consultant bei MathWorks. Zu seinen Spezialgebieten gehören HDL/FPGA, Hardware-/Software-Kodesign, die Generierung von Produktionscode, Embedded Systems und Echtzeitsysteme. Er arbeitet seit über 25 Jahren in der Entwicklung von Echtzeitsystemen und Embedded Systems.

Babak Soheili ist Senior Pilot Engineer mit 16 Jahren Erfahrung in der Implementierung von Designs auf FPGAs sowie für Anwendungen in der Avionik, Luft- und Raumfahrt. Sein Schwerpunkt bei MathWorks ist Model-Based Design mit HDL Coder und verwandten Tools für Designs, die für FPGAs bestimmt sind.

Veröffentlicht 2016 - 92990v00