Die Definition eines Echtzeitsystems in seiner einfachsten Form ist, dass es periodisch deterministisch ausgeführt wird. Determinismus ist eine Anforderung erster Ordnung für Echtzeitsysteme, da sie im Allgemeinen Maschinen steuern. Niemand möchte, dass sich eine numerisch gesteuerte Standbohrmaschine am Dienstag in 10 ms von Punkt A nach Punkt B bewegt und am Mittwoch denselben Vorgang in 20 ms abarbeitet.. Ebenso sollte das Flugsteuerungssystem eines Piloten die Tragflächen jedes Mal unter allen Bedingungen exakt gleich steuern.
Bild 1 veranschaulicht ein deterministisches System. Es treten periodische Interrupts auf und die Interrupt-Service-Routine (ISR) behandelt zeitkritischen Code. Die Ausführungszeit dieses Codes muss deterministisch sein, damit kein System vorliegt, das sich wie in Bild 2 verhält, in dem die Aktualisierung der Hardware zeitlich zufällig erfolgt.
Ursachen für Ausführungsjitter
Gefordert ist auch, die Vorteile von Linux und der dazugehörigen Middleware auf hardwaregesteuerte Systeme zu übertragen. Linux benötigt eine MMU (Memory Management Unit), um den physischen Speicher für den Anwendungsentwickler zu virtualisieren. Prozessoren, die eine MMU einbetten, enthalten mindestens einen L1-Cache und in den meisten Fällen einen L2-Cache. Caches und Determinismus sind orthogonal zueinander angeordnet (Bild 3). Hier zeigt sich, dass ein L1- oder L2-Cache-Miss zu Ausführungsjitter führen, da die Ausführungspipeline angehalten wird, während das Füllen der Cache-Zeilen erfolgt. Größere Caches können die Häufigkeit eines Cache-Miss verringern, ihn jedoch nicht vollständig entfernen.
Auf Prozessoren, die Linux ausführen, ist die Sprungvorhersage eine zusätzliche Quelle für Ausführungsjitter. Prozessor-Cores enthalten diese, um die Leistungsfähigkeit auf Anwendungsebene zu erhöhen. Unabhängig von der Implementierung werden Sprünge vorhergesagt und manchmal verpasst. Tritt ein Cache-Miss auf, wird die Pipeline bereinigt. Cache-Misses führen zu einem nicht deterministischen Ausführungsverhalten. Während einer ISR enthalten die im Vorhersage-Indikator verwendeten Sprungverlaufstabellen ein Protokoll von Verzweigungen, die für das Ausführungsprotokoll des Hauptanwendungscodes relevant sind – nicht für das Ausführungsprotokoll der ISR. Dies führt zu Pipeline-Bereinigungen innerhalb der ISR, was zu einer variablen Ausführungszeit von ISR zu ISR führt. Durch einen Prozessor, bei dem der Nutzer die Sprungvorhersage deaktivieren kann, erhält der Anwendungsentwickler die Kontrolle darüber, wo und wie Determinismus im System angewendet wird. Für einen anwendungsweiten Determinismus lässt sich die Sprungvorhersage vollständig deaktivieren. Selbstverständig kommen Sprungvorhersagen zum Einsatz, um die Leistungsfähigkeit zu erhöhen, weshalb sich bei ihrer Deaktivierung die Leistungsfähigkeit verringert.
Die RISC-V-FPGA-Architektur der Polarfire-SoCs
Es gibt Prozessoren, die Linux ausführen, aber Code nicht deterministisch ausführen können – und es gibt Prozessoren, die Code deterministisch ausführen, aber Linux nicht ausführen können. Wäre es nicht schön, eine Architektur in einem Embedded-Toolkit zu haben, die beides unterstützt? Die RISC-V-basierte SoC-FPGA-Architektur für Polarfire-SoCs von Microchip bietet genau das.
Bild 4 beschreibt vier 64-Bit-RV64GC-RISC-V-Cores, die Linux ausführen können, und einen Core (RV64IMAC), der Linux nicht ausführen kann. Anders gesagt: der RV64IMAC enthält keine MMU, und die vier RV64GC-Cores enthalten eine MMU. Die Unterschiede der Befehlssätze zwischen dem RV64IMAC und dem RV64GC sind einfach: der RV64GC enthält eine Gleitkommaeinheit mit doppelter Genauigkeit. Um den Determinismus innerhalb der Architektur zu erhöhen, kann der Nutzer die Sprungvorhersage in jedem Core entweder nach dem Einschalten oder während einer ISR deaktivieren. Darüber hinaus wurden für alle fünf Cores Pipelines in der richtigen Reihenfolge ausgewählt, um den Determinismus zu erhöhen und Spectre- und Meltdown-Angriffe auf nicht ordnungsgemäß laufenden Maschinen zu vermeiden.
Bisher kam nur der Determinismus in Bezug auf CPU-Cores zur Sprache. Die Ausführung von Code muss jedoch aus dem Speicher heraus erfolgen, weshalb nun ein Augenmerk auf das Speicher-Subsystem der Polarfire-SoCs gelegt wird. Der gesamte Speicherbereich in den SoCs ist zusammenhängend (kohärent). Kohärenz wird so definiert: Alle Speicher, die mehrere Kopien von Daten enthalten, werden vom Kohärenzmanager verwaltet, und alle Speicher, die nur eine einzige Kopie von Daten enthalten, sind von Natur aus kohärent, da keine anderen Kopien in der Speicherhierarchie existieren. Polarfire-SoCs verfügen über drei Speicher-Subsysteme: L1, L2 und L3. Letzterer enthält einen gehärteten LPDDR3/LPDDR4- und DDR3/DDR4-36-Bit-Controller. Die zusätzlichen 4 Bit dienen dazu, dem externen L3-Speicher-Subsystem SECDED (Single Error Correct Double Error Detect) hinzuzufügen.
Die L1- und L2-Speicher-Subsysteme
Die vier RV64GC-Anwendungs-Cores verfügen jeweils über einen 8-Wege-Satz-assoziativen I$TIM (Instruction Tightly Integrated Memory) mit 32 KByte und einen 8-Wege-Satz-assoziativen D$TIM (Data Tightly Integrated Memory) mit 32 KByte. I$TIM und D$TIM sind benutzerdefiniert, wobei für beide stets ein Cache-Weg vorhanden sein muss. Der RV64IMAC-Monitor-Core verfügt über einen 2-Wege-Satz-assoziativen I$TIM mit 16 KByte und 8 KByte D$TIM. Letzterer ist ein Daten-Scratchpad-Speicher, von dem aus sich Code ausführen lässt, während I$ für einen Befehls-Cache entspricht. Alle L1-TIM-Funktionen bieten deterministischen Zugriff mit niedriger Latenz und sind in der Lage, SECDED auszuführen.
Das L2-Speichersubsystem ist 2 MByte groß und SECDED-fähig. Es lässt sich in drei verschiedenen Modi konfigurieren: als 16-Wege-Satz-assoziativer Cache, als LIM (Loosely Integrated Memory) und als Scratchpad-Speicher. Das LIM lässt sich an einen Prozessor binden und im Cache dimensionieren. Das bedeutet, dass es sich in 128-KByte-Blöcken (Wegen) erstellen lässt und einem Prozessor exklusiver Zugang zuweisbar ist. Das als LIM konfigurierte L2-Speicher-Subsystem bietet deterministischen Zugriff auf den Core, an den es gebunden ist. Es ist kohärent, da keine weiteren Kopien mit dem L1- und L3-Speicher-Subsystem geteilt werden. LIM ist ideal für die deterministische Code-Ausführung sowohl in der Hauptanwendung als auch in ISRs. Bild 5 beschreibt ein deterministisches System, bei dem das L2-Speicher-Subsystem als LIM und die L1-Speicher als TIM konfiguriert sind.
Leider variiert die ISR-Ausführungszeit aufgrund falscher Prognosen der Sprungvorhersage immer noch – selbst dann, wenn L2 als LIM konfiguriert ist. Wie beim LIM lässt sich auch der Scratchpad-Speicher in 128-KByte-Blöcken (Wegen) konfigurieren und den CPU-Cores zuweisen. Scratchpad-Speicher ist ideal als gemeinsam genutzte Speicherressource zwischen dem Prozessor, der Code vom LIM ausführt, und Prozessoren, die Code vom L1/L2- und L3-Speicher-Subsystem (bei Linux) ausführen. Schreibt die RV64IMAC-Anwendung Daten in das Scratchpad und ist eine Kopie dieses Speicherorts an einer anderen Stelle im L1/L2/L3-Speicher-Subsystem vorhanden, garantiert der Kohärenzmanager die Kohärenz. Damit kann eine Echtzeitanwendung Daten kohärent mit einer Anwendung teilen, die im Benutzerbereich unter Linux läuft.
Eck-Daten
Polarfire SoCs stellen Anwendern ein innovatives SoC-FPGA zur Verfügung, das auf der RISC-V-Architektur basiert und es ihnen ermöglicht, harte Echtzeitanwendungen und Linux auf einem einzigen Chip zusammenzuführen, um stromsparende, sichere und zuverlässige Designs umzusetzen. Mit RISC-V lassen sich auf architektonischer Ebene kostenlos Neuerungen umsetzen. Auf diese Weise können Anwender die Mikroarchitektur so beeinflussen, wie sie es bisher nicht für möglich gehalten haben. Sie haben die Möglichkeit, Teile des L1-Speicher-Subsystems in einen TIM umzuwandeln, sie können die Sprungvorhersage für jeden Kern ausschalten und sie können das L2-Speicher-Subsystem in einen LIM partitionieren.
Bild 6 beschreibt eine mögliche Konfiguration des Polarfire-SoC-Mikroprozessor-Subsystems. Darin stellt der RV64IMAC die Echtzeitfunktion bereit, während der RV64GCs Linux ausführt. Benötigt die Echtzeitfunktion eine Gleitkomma-Verarbeitung, erfüllt der RV64GC diese Aufgabe, da die Sprungvorhersage deaktivierbar und das L1-Speicher-Subsystem als TIM konfigurierbar ist.
Warum RISC-V?
Bei Microchip kommt es nicht auf die Befehlssatzarchitektur (ISA; Instruction Set Architecture) oder den Chip an, sondern auf die Fähigkeit, die Datenverarbeitungsanforderungen einer breiten Anwenderbasis zu unterstützen, die sich über verschiedenste Anwendungen und Märkte erstreckt.
Für die FPGAs der nächsten Generation, die ein Prozessor-Subsystem als ASIC-Block enthalten, fiel die Wahl auf die RISC-V-ISA gegenüber anderen üblichen Architekturen – gerade weil diese die Endmärkte für Microchip und seine Anwender besser bedient. SoC-FPGAs haben unterschiedliche Anwendungsanforderungen, die von diesen Endmärkten bedient werden. Für die Polarfire-SoCs fiel die Entscheidung, ein stromsparendes SoC-FPGA für die Mittelklasse auf den Markt zu bringen, das ein Betriebssystem wie Linux ausführen kann. Sobald die Entscheidung für ein solches leistungsstarkes OS gefallen ist, wird die zugrundeliegende ISA und die Mikroarchitektur dem Anwendungssoftware-Entwickler effektiv entzogen. Es ist richtig, dass die ISA in Verbindung mit der Mikroarchitektur einer bestimmten Anwendung PPA-Größen (Power, Performance, Area) bereitstellt. Für den Entwickler von Anwendungssoftware verwalten sie jedoch hauptsächlich die Rechenleistung, I/Os und den Speicher. Dennoch werden einige sagen: „Was ist mit dem Ökosystem? Der Markt bietet so viel für bestimmte ISAs.“
Stimmt, dies wäre bei ausgereiften ISAs zu erwarten. Es ist jedoch zu bedenken, dass keine zwei SoCs auf dem Markt das gleiche Speicher-Mapping, dieselben I/Os, denselben Bus-Switch, Speichercontroller, Boot-Vorgang etc. haben. Jeder Anbieter entwickelt und fertigt Produkte, die den Bedürfnissen der Anwender entsprechen, und nicht alle Anwender haben die gleichen Bedürfnisse. Ökosysteme sind fragmentiert und daher muss auch innerhalb derselben ISA manchmal ein Wechsel von Lieferant A zu Lieferant B erfolgen. Das wird sich nie ändern. Dies ist ein Hauptgrund für OEMs, auf ein leistungsstarkes OS umzusteigen und auf die zugrundeliegende Halbleitertechnologie zu abstrahieren, da alle SoCs unterschiedlich sind. Wenn Softwareentwickler die Anzahl der Hardwareentwickler um 10:1 übersteigen, werden Unternehmen ihre Softwareentwicklung so weit wie möglich nutzen.
Mit der Entscheidung, ein leistungsstarkes OS zu unterstützen, war beurteilbar, welches Prozessor-IP am Markt verfügbar ist, und zwar anhand der Anwenderanforderungen, da das Betriebssystem am Ende alles außer die PPA-Größen abstrahiert. Aus diesem Grund fiel für Microchip die Wahl auf RISC-V.
Mit RISC-V lassen sich auf architektonischer Ebene kostenlos Neuerungen umsetzen. Auf diese Weise können Anwender die Mikroarchitektur so beeinflussen, wie sie es bisher nicht für möglich gehalten haben. Damit lassen sich maßgeschneiderte Designs für Anwendungen wie Bildgebung und maschinelles Lernen, sicherheitskritische Systeme, industrielles IoT, sichere Kommunikation und Verteidigungssysteme entwickeln. Im Polarfire-SoC hat Microchip zum Beispiel zusammen mit seinem IP-Partner Sifive ein Prozessor-Subsystem mit fünf Cores entwickelt, mit dem Echtzeitanwendungen und SMP-Linux mit einem kohärenten Nachrichtenübermittlungsschema auf demselben Prozessor-Subsystem unter Verwendung derselben ISA ausführbar sind.
(na)