Der Prozessor des Typs Cortex A8 ist das ausgefeilteste Low-Power-Design, das ARM je hervorgebracht hat. Um das hier verwirklichte hohe Rechenleistungs-Niveau zu erzielen, wurden neue Mikroarchitektur-Elemente hinzugefügt, die es in der ARM-Architektur bislang nicht gab. Dazu gehören eine „Dual In-Order Issue ARM Integer Pipeline“, ein integrierter L2-Cache und eine 13-stufige Pipeline.
Superskalare-Pipeline
Möglicherweise die entscheidendste neue Eigenschaft ist die Dual-Issue In-Order ARM Integer Pipeline mit statischem Scheduling. Durch die Fähigkeit zur gleichzeitigen Ausgabe zweier Datenverarbeitungs-Instruktionen können in einem Taktzyklus erheblich mehr Befehle verarbeitet werden. Mit der Entscheidung, das „In-Order-Issue“-Verfahren beizubehalten, verfolgte man die Absicht, die zusätzlich abfallende Verlustleistung auf ein Minimum zu reduzieren. Das „Out-of-Order-Issue- und Retire“-Konzept könnte dagegen zu einem deutlich höheren Logikaufwand führen, was die Leistungsaufnahme entsprechend erhöhen würde. Die Wahl der In-Order-Issue-Technik ermöglicht zudem ein Instruction-Issuing nach dem „Fire-and-Forget“-Prinzip, was kritische Signalwege aus dem Design entfernt und den Aufwand an speziell entwickelter Logik in der Pipeline verringert. Das statische Scheduling wiederum schafft die Voraussetzungen für umfangreiches „Clock-Gating“ (Transistoren zur Abschaltung von Chipfunktionen) zur Senkung der Leistungsaufnahme während der Verarbeitung.
Die beiden symmetrischen ALU-Pipelines (Arithmetic Logic Unit) ALU 0 und ALU 1 können den Großteil der arithmetischen Befehle verarbeiten. In der ALU Pipe 0 befindet sich stets der ältere von zwei ausgegebenen Befehlen. Zwar besitzt der Prozessor Cortex-A8 auch Multiplizierer- und Load-Store-Pipelines, doch führen diese den beiden ALU-Pipelines keine zusätzlichen Befehle zu, sondern man kann sie als „abhängige“ Pipelines betrachten, da sie stets im Verbund mit einer der beiden ALU-Pipelines verwendet werden müssen. Während die Multiplizierer-Pipeline nur mit Befehlen in der ALU-0-Pipeline kombiniert werden kann, lässt sich die Load-Store-Pipeline mit Instruktionen in beiden Pipelines koppeln.
Verzweigungs-Vorhersage
Mit der Entscheidung zugunsten einer 13-stufigen Pipeline wollte man die Voraussetzungen für wesentlich höhere Taktfrequenzen schaffen, als sie mit den bisherigen Generationen von ARM-Mikroarchitekturen möglich waren. Die mit F0 bezeichnete Stufe wird übrigens nicht mitgezählt, da sie lediglich der Adressgenerierung dient. Um den Mehraufwand zu minimieren, der durch eine derart tiefe Pipeline bei Verzweigungen entsteht, bedient sich der Cortex-A8-Prozessor einer Funktion zur Vorhersage von Verzweigungen. Diese Stufe beruht auf einer zweistufigen, globalen Verarbeitungs-Historie und enthält zwei verschiedene Strukturen, nämlich den „Branch Target Buffer“ (BTB) und den „Global History Buffer“ (GHB). Auf beide wird bei „Instruction Fetches“ (Befehl holen) parallel zugegriffen.
Erst während der Konfiguration des Projekts wird festgelegt, auf welchem FPGA das Design getestet wird. Diese Konfiguration kann automatisiert erstellt werden, das heißt, die Design-Software erkennt die angeschlossene Hardware auf dem Nano-Board und fügt die benötigten Constraints zum Projekt hinzu (welche Pins sind mit dem SPI-Controller verbunden, welche mit dem TFT etc.). Dadurch ergibt sich ein weiterer Vorteil: Soll z.B. die endgültige Applikation auf einem sichereren und nach dem Einschalten sofort verfügbaren flash-basierten FPGA implementiert werden, so ist dies während der Entwicklung der langen Programmierzeiten wegen von Nachteil. Während dieser Phase, die durch ständiges Testen, Ändern und Ausprobieren geprägt ist, kann deshalb ein SRAM-basiertes FPGA benutzt werden, das sich wesentlich schneller programmieren lässt. Die Portierung des Designs auf Flash-Technologie ist dann ohne Änderungen des Designs gewährleistet. Lediglich die Konfiguration muss noch hinzugefügt werden.
Der BTB signalisiert, ob sich an der aktuellen Fetch-Adresse ein Verzweigungsbefehl befindet und welche Zieladresse die Verzweigung hat. Dieser Puffer enthält 512 Einträge. Bei einem Hit im BTB wird eine Verzweigung prognostiziert und ein Zugriff auf den GHB ausgeführt. Der GHB enthält insgesamt 4096 sättigende 2-bit-Zähler, die die Stärke und Richtungsinformation von Verzweigungen codieren. Der GHB wird durch eine 10 bit umfassende Historie der Richtung der letzten zehn ausgeführten Verzweigungen sowie durch 4 bit des Programmzählers indiziert.
Ergänzend zu diesem dynamischen Branch Predictor dient ein Return Stack zur Vorhersage der Rücksprungadresse von Unterprogrammen. In den 32-bit-Einträgen des „Return Stack“ wird jeweils der Wert des Link-Registers in Register 14 (r14) sowie der ARM- oder Thumb-Status der aufrufenden Funktion abgelegt. Wird die Ausführung einer Instruktion vom Typ Return prognostiziert, stellt der Return Stack die zuletzt per „Push“ gespeicherte Adress- und Statusinformation zur Verfügung. Bei einer falsch vorhergesagten Verzweigung verliert man 13 Taktzyklen (Bild 2).
Schnittstellen zwischen Prozessor, Speicher und Peripherie
Ein weiterer Befreiungsschlag erleichtert Betrachtungen zur Low-Level-Architektur des Systems. Und zwar durch eine weitere Abstraktionsebene, die in die Hardware-IP integriert ist. Unterstützt die IP den Wishbone-OpenBus-Standard, so werden dadurch die Schnittstellen zwischen Prozessor, Speicher und Peripherie „genormt“. Die Low-Level-Architektur und die Busverbindungen der Applikation werden dann vom System abgewickelt und nicht vom Entwickler. Dieser Ansatz erlaubt auch die Einbindung von Wishbone-Wrappern, die als Entkopplung zwischen bestehenden Schnittstellen und dem Hardware-Bus wirken. Dies ermöglicht z.B. einen Prozessorwechsel, ohne dass die Hardware der Peripherie geändert werden muss. Mit dem passenden Compiler kann dann auch die Software weiterverwendet werden. Damit lassen sich z.B. Performancetests mit verschiedenen Prozessoren durchführen. Dies ist vor dem Hintergrund interessant, dass von der Innovation-Station mit den auf der Tasking-Viper-Technologie basierenden Compilern nicht nur reine Softcores unterstützt werden (TSK3000, Xilinx MicroBlaze, Altera NIOS II, Actel CoreMP7, PowerPC 405), sondern auch diskrete Prozessoren wie ARM und Power-PC. Das heißt, dass in einer Applikation zur Optimierung ein Wechsel vom Softcore auf einen diskreten Prozessor erfolgen kann, während die Peripherie weiter im FPGA arbeitet.
Device Software Framework
Level-1-Cache
Im Cortex A8 entsteht durch schnelle Schreib- und Lesezugriffe auf die Level-1-Caches ein Mehraufwand von einem Zyklus. Daten- und Befehls-Caches können auf 16 oder 32 Kbyte konfiguriert werden. Jeder Cache ist nach dem „4-Way Set Associative“-Prinzip (4-fach satzassoziativ) organisiert und verwendet ein als „Hash Virtual Address Buffer (HVAB) Way-Prediction“ bezeichnetes Verfahren, um das Timing zu verbessern und die Leistungsaufnahme zu senken. Die Cache-Speicher werden physikalisch adressiert (virtueller Index, physikalischer Tag) und verfügen über Hardwareunterstützung zur Vermeidung von „Aliased Entries“. Die Parität wird mit einem Paritätsbit pro Byte unterstützt.
Der Austausch von Einträgen im Daten-Cache erfolgt nach dem „Write-Back“-Verfahren ohne „Write Allocates“. Ebenfalls enthalten ist ein „Store Buffer“ zum Zusammenführen von Daten vor dem Überschreiben an den Hauptspeicher. Die HVAB-Technik ist ein neuartiges Verfahren zur Verringerung des mit Cache-Zugriffen einhergehenden Energiebedarfs. Mit Hilfe eines besonderen Vorhersageverfahrens wird erst unmittelbar vor einem Zugriff die jeweilige Cache-Zeile der vier pro Satz aktiviert („4-way set associative“ bedeutet, dass ein Satz von vier Cachezeilen vorgehalten wird).
Level-2-Cache
Die Cortex-A8-Architektur sieht einen integrierten Level-2-Cache vor, der sich durch eine breitbandige Schnittstelle zum Level-1-Cache mit geringer Latenzzeit auszeichnet. Dies minimiert die Latenzzeit von „Linefills“ des Level-1-Cache und vermeidet Konflikte mit dem Datenverkehr auf dem Haupt-Systembus. Der Level-2-Cache lässt sich für Kapazitäten von 64 Kbyte bis 2 Mbyte konfigurieren.
Der Level-2-Cache wird physikalisch adressiert und ist nach dem „8-Way Set Associative“-Prinzip organisiert. Der für Befehle und Daten genutzte Cache bietet optional Unterstützung für ECC (Fehlerkorrektur) und Parität. Abhängig von den „Page-Table“-Einstellungen wird nach dem „Write-Back“-, „Write-Through“- oder „Write-Allocate“-Verfahren gearbeitet und es kommt ein pseudo-zufälliges Zuordnungs-Verfahren zur Anwendung. Während sich der Inhalt des Level-1-Daten-Cache und der Inhalt des Level-2-Cache gegenseitig ausschließen, ist der Inhalt des Level-1-Befehls-Cache stets eine Teilmenge des Level-2-Cache. Zur Senkung der Leistungsaufnahme wird auf die Tag- und Daten-RAMs des Level-2-Cache seriell zugegriffen.
NEON Media Engine
Die „NEON Media Processing Engine Pipeline“ des Cortex-A8-Prozessors beginnt im Anschluss an die Haupt-Integer-Pipeline (Bild 3). Jegliche „Exceptions“ (Ausnahmen) und fehlge-schlagenen Verzweigungs-Prognosen sind somit aufgelöst, bevor Befehle bis zu ihr gelangen. Wichtiger noch ist die Tatsache, dass für den Zugriff auf Daten im Level-1-Cache kein Mehraufwand entsteht, denn die Integer-Einheit erzeugt die Adressen für NEON-Load- und Store-Operationen bereits beim Durchlaufen der Pipeline. Die Daten können somit aus dem Level-1-Cache geholt werden, noch bevor sie von einer Datenverarbeitungs-Operation in der NEON Engine benötigt werden. Tiefe Puffer für Befehle und geladene Daten zwischen der NEON Engine, der Integer-Einheit und dem Speichersystem sorgen dafür, dass die Latenzzeit von Level-2-Zugriffen bei Daten-Streaming nicht zutage tritt. Ein Store-Puffer verhindert außerdem, dass NEON-Stores die Pipeline blockieren und erkennt Adresskonflikte zwischen Zugriffen der Integer-Einheit und NEON-Ladeoperationen.
Portierbarer Code setzt mehr voraus als einen cleveren Compiler: Um die zuvor beschriebene Flexibilität zu erhalten, ist ein ganzes System notwendig, das die Schnittstellen zwischen der Applikation und der Hardware verwaltet. Bild 2 zeigt die Realisierung im „Device Software Framework“ (DSF), in dem durch ein „Low Level Peripheral Interface“ (LLPI) die Applikation vom physikalischen Layer getrennt wird. Dennoch bleibt der Zugriff auf die Hardware, z.B. bei der Implementierung von Interrupts, weiterhin erhalten. Der „Processor Abstraction Layer“ (PAL) und das LLPI werden durch Header Files über das DSF in das Projekt eingebunden. Daneben stellt das DSF auch Software, Treiber etc. zur Verfügung, so dass bei der Entwicklung der Software eine Menge Zeit eingespart werden kann. Die Innovation-Station erlaubt mit diesem innovativen Konzept aus flexibel konfigurierbarer Hardware in Verbindung mit dem DSF auch das Experimentieren mit unterschiedlichsten Systemarchitekturen bis hin zu Multiprozessor-Architekturen. Das ermöglicht im Projekt wesentlich verkürzte Zeiträume für wichtige Entscheidungen: Beispielsweise für die Frage, welche Anteile des Gesamtfunktionsumfangs eines Embedded-Systems ein Entwickler in Software und welche Anteile er in Hardware implementieren soll.
Die NEON-Engine wird durch die „NEON Instruction Queue“ (NIQ) von der Integer-Pipeline entkoppelt. Die „Instruction Execute Unit“ kann in jedem Taktzyklus bis zu zwei gültige Instruktionen an die NEON-Engine übergeben. Von der NEON-Einheit führen 128 bit breite Load- und Store-Pfade zum Level-1- und zum Level-2-Cache, und auch das Daten-Streaming aus beiden Caches wird unterstützt.
Die NEON Media Engine besitzt eine eigene 10-stufige Pipeline, die am Ende der Integer-Pipeline beginnt. Da wie erwähnt alle fehlgeschlagenen Verzweigungs-Vorhersagen und Exceptions in der Integer-Einheit aufgelöst wurden, muss eine an die NEON Media Engine übergebene Instruktion stets ausgeführt werden, denn Exceptions können von ihr nicht mehr erzeugt werden. Die NEON Engine enthält drei SIMD-Integer-Pipelines, ei-ne Load-Store/Permute-Pipeline, zwei SIMD-Single-Precision Floating-Point-Pipelines und eine Vektor-Gleitkomma-Einheit (Vector Floating-Point Unit – VFPLite) ohne Pipeline.