Die Kriege zwischen RISC und CISC Ende der neunziger Jahre sind längst ausgestorben, und heute wird angenommen, dass der Unterschied zwischen RISC und CISC völlig irrelevant ist. Viele Leute behaupten, dass Befehlssätze irrelevant sind.
Die Befehlssätze sind jedoch tatsächlich wichtig. Sie beschränken die Arten von Optimierungen, die dem Mikroprozessor leicht hinzugefügt werden können.
Ich habe mir kürzlich die Informationen zur RISC-V-Befehlssatzarchitektur (ISA) genauer angesehen, und hier sind einige Aspekte, die mich an der RISC-V-ISA wirklich beeindruckt haben:
- Dies ist ein kleiner und leicht zu erlernender RISC-Befehlssatz. Sehr vorzuziehen für diejenigen, die sich für Mikroprozessoren interessieren.
- , , .
- CPU ISA RISC-V.
- , , RISC-V.
RISC
Als ich begann, RISC-V besser zu verstehen, wurde mir klar, dass sich RISC-V als radikale Rückkehr zu einer vergangenen Ära des Computing herausstellte. Vom Standpunkt des Designs, der RISC-V auf einer Maschine ähnlich der Bewegungszeit zu einem klassischen R educed I nstruction S et C omputer (RISC, «Computer mit einer Reihe von kurzen Kommandos") Anfang der 80er und 90er Jahre.
In den letzten Jahren haben viele argumentiert, dass die Unterteilung in RISC und CISC nicht mehr sinnvoll ist, da RISC-Prozessoren wie ARM so viele Anweisungen hinzugefügt wurden und viele davon recht komplex sind, dass es sich derzeit eher um einen Hybrid als um einen reinen RISC-Prozessor handelt. Ähnliche Überlegungen wurden bei anderen RISC-Prozessoren wie dem PowerPC angewendet.
RISC-V hingegen ist ein wahrer "Hardcore" -Vertreter von RISC-Prozessoren. Wenn Sie über RISC-V-Diskussionen im Internet lesen, werden Sie Leute finden, die behaupten, dass RISC-V von einigen RISC-Radikalen der alten Schule entwickelt wurde, die sich weigern, mit der Zeit zu gehen.
Die frühere ARM-Ingenieurin Erin Shepherd hat vor einigen Jahren eine interessante Kritik an RISC-V geschrieben :
ISA RISC-V . , .. (, , ) , .
Lassen Sie mich kurz einen kleinen Kontext geben. Die geringe Codegröße hat einen Leistungsvorteil, da es einfacher ist, ausführbaren Code im Hochgeschwindigkeits-Cache des Prozessors zu speichern.
Die Kritik hier ist, dass sich die RISC-V-Designer zu sehr darauf konzentriert haben, einen kleinen Befehlssatz bereitzustellen. Immerhin ist dies eines der ursprünglichen Ziele von RISC.
Laut Erin war die Folge davon, dass ein echtes Programm viel mehr Anweisungen benötigen würde, um Aufgaben zu erledigen, das heißt, es würde mehr Speicherplatz beanspruchen.
Traditionell wurde viele Jahre lang angenommen, dass dem RISC-Prozessor mehr Anweisungen hinzugefügt werden sollten, um ihn CISC ähnlicher zu machen. Die Idee ist, dass spezialisiertere Befehle die Verwendung mehrerer allgemeiner Befehle ersetzen können.
Befehlskomprimierung und Fusion von Makrooperationen
Es gibt jedoch zwei Neuerungen in der Prozessorarchitektur, die diese Strategie des Hinzufügens komplexerer Anweisungen in vielerlei Hinsicht überflüssig machen:
- Komprimierte Anweisungen - Anweisungen werden im Speicher komprimiert und in der ersten Stufe des Prozessors dekomprimiert.
- Makrooperation Fusion - Zwei oder mehr einfache Anweisungen werden vom Prozessor gelesen und zu einer komplexeren Anweisung zusammengeführt.
Tatsächlich verwendet ARM bereits beide Strategien, und x86-Prozessoren verwenden letztere, sodass RISC-V hier keine neuen Tricks ausführt.
Hier gibt es jedoch eine Feinheit: RISC-V profitiert aus zwei wichtigen Gründen viel mehr von diesen beiden Strategien:
- Anfangs wurden komprimierte Befehle hinzugefügt. Andere Architekturen wie ARM haben später darüber nachgedacht und sie ziemlich voreilig angeschraubt.
- Hier rechtfertigt sich die Besessenheit von RISC mit einer kleinen Anzahl einzigartiger Teams. Es bleibt einfach mehr Platz, um komprimierte Befehle hinzuzufügen.
Der zweite Punkt bedarf einiger Klarstellung. In RISC-Architekturen sind Befehle normalerweise 32 Bit breit. Diese Bits müssen verwendet werden, um verschiedene Informationen zu codieren. Nehmen wir an, wir haben einen Befehl wie diesen (es gibt Kommentare nach dem Semikolon):
ADD x1, x4, x8 ; x1 ← x4 + x8
Es fügt den Inhalt der Register hinzu
x4
und
x8
speichert das Ergebnis in
x1
. Die Anzahl der zum Codieren dieses Befehls erforderlichen Bits hängt von der Anzahl der verfügbaren Register ab. RISC-V und ARM haben 32 Register. Die Zahl 32 kann in 5 Bits ausgedrückt werden:
2⁵ = 32
Da der Befehl drei verschiedene Register angeben muss, sind insgesamt 15 Bits (3 × 5) erforderlich, um die Operanden (Eingabedaten für die Additionsoperation) zu codieren.
Je mehr Funktionen wir im Befehlssatz unterstützen möchten, desto mehr Bits werden aus den 32 verfügbaren Bits entfernt. Natürlich können wir zu 64-Bit-Befehlen übergehen, aber dies verbraucht zu viel Speicher, was bedeutet, dass die Leistung beeinträchtigt wird.
In einem aggressiven Versuch, die Anzahl der Anweisungen klein zu halten, lässt RISC-V mehr Raum zum Hinzufügen von Bits, um anzuzeigen, dass wir komprimierte Anweisungen verwenden. Wenn der Prozessor sieht, dass bestimmte Bits im Befehl gesetzt sind, versteht er, dass er als komprimiert interpretiert werden muss.
Dies bedeutet, dass wir anstelle von 32 Bits eines Befehls zwei Befehle mit einer Breite von jeweils 16 Bit einfügen können. Natürlich können nicht alle RISC-V-Befehle im 16-Bit-Format ausgedrückt werden. Daher wird eine Teilmenge von 32-Bit-Befehlen basierend auf ihrer Nützlichkeit und Verwendungshäufigkeit ausgewählt. Wenn unkomprimierte Anweisungen 3 Operanden (Eingabedaten) empfangen können, können komprimierte Anweisungen nur 2 Operanden empfangen. Das heißt, der komprimierte Befehl
ADD
sieht folgendermaßen aus:
C.ADD x4, x8 ; x4 ← x4 + x8
Der RISC-V-Assemblycode verwendet ein Präfix,
C.
um anzugeben, dass der Befehl zu einem komprimierten Befehl zusammengesetzt werden muss.
Im Wesentlichen reduzieren komprimierte Anweisungen die Anzahl der Operanden. Drei Operandenregister würden 15 Bit benötigen und nur 1 Bit übrig lassen, um die Operation anzuzeigen! Wenn also zwei Operanden zur Anzeige des Opcodes (der auszuführenden Operation) verwendet werden, bleiben 6 Bits übrig.
Dies entspricht in etwa der Funktionsweise des x86-Assemblers, wenn nicht genügend Bits für die Verwendung der drei Operandenregister reserviert sind. Der x86-Prozessor verschwendet Bits, um beispielsweise den Befehl zum
ADD
Lesen eingehender Daten sowohl aus dem Speicher als auch aus den Registern zu ermöglichen.
Allerdings ist das wahrWir profitieren von der Kombination der Befehlskomprimierung mit der Makrooperationsfusion. Wenn der Prozessor ein 32-Bit-Wort empfängt, das zwei komprimierte 16-Bit-Befehle enthält, kann er diese zu einem komplexeren Befehl zusammenführen.
Klingt nach Unsinn - sind wir wieder da, wo wir angefangen haben?
Nein, da wir die Notwendigkeit umgehen, die ISA-Spezifikation mit einer Reihe komplexer Anweisungen zu füllen (d. H. Die Strategie, der ARM folgt). Stattdessen drücken wir im Wesentlichen eine ganze Reihe komplexer Befehle indirekt durch verschiedene Kombinationen einfacher Befehle aus.
Unter normalen Umständen würde die Makrofusion ein Problem verursachen: Obwohl zwei Anweisungen durch eine ersetzt werden, belegen sie immer noch doppelt so viel Speicher. Beim Komprimieren von Befehlen belegen wir jedoch keinen zusätzlichen Speicherplatz. Wir nutzen beide Architekturen.
Schauen wir uns eines der Beispiele von Erin Shepherd an. In ihrem kritischen Artikel über ISA RISC-V zeigt sie eine einfache Funktion in C. Um es klarer zu machen, habe ich mir erlaubt, sie neu zu schreiben:
int get_index(int *array, int i) {
return array[i];
}
Unter x86 wird dies mit dem folgenden Assemblycode kompiliert:
mov eax, [rdi+rsi*4]
ret
Wenn eine Funktion in einer Programmiersprache aufgerufen wird, werden Argumente normalerweise in einem Register in einer festgelegten Reihenfolge an die Funktion übergeben, die vom verwendeten Befehlssatz abhängt. Auf x86 wird das erste Argument in ein Register gestellt
rdi
, das zweite in
rsi
. Standardmäßig sollten Rückgabewerte in ein Register eingetragen werden
eax
.
Der erste Befehl multipliziert den Inhalt
rsi
mit 4. Er enthält eine Variable
i
. Warum vermehrt es sich? Weil es
array
aus ganzzahligen Elementen besteht, die durch 4 Bytes getrennt sind. Daher hat das dritte Element des Arrays einen Versatz von 3 × 4 = 12 Bytes.
Als nächstes fügen wir diese hinzu,
rdi
die die Basisadresse enthält
array
... Dies gibt uns die endgültige Adresse des
i
th-Elements
array
. Wir lesen den Inhalt der Speicherzelle unter dieser Adresse und speichern ihn in
eax
: Aufgabe abgeschlossen.
Bei ARM geschieht alles auf ähnliche Weise:
LDR r0, [r0, r1, lsl #2]
BX lr ;return
Hier multiplizieren wir nicht mit 4, sondern verschieben das Register um
r1
2 Bits nach links, was einer Multiplikation mit 4 entspricht. Dies ist wahrscheinlich eine genauere Beschreibung dessen, was auf x86 passiert. Ich bezweifle, dass es möglich ist, mit etwas zu multiplizieren, das kein Vielfaches von 2 ist, da die Multiplikation eine ziemlich komplizierte Operation ist und das Schalten kostengünstig und einfach ist.
Nach meiner Beschreibung von x86 ist der Rest jedermanns Vermutung. Nun kommen wir zu RISC-V, wo der wahre Spaß beginnt! (Kommentare beginnen mit Semikolon)
SLLI a1, a1, 2 ; a1 ← a1 << 2
ADD a0, a0, a1 ; a0 ← a0 + a1
LW a0, a0, 0 ; a0 ← [a0 + 0]
RET
Registriert sich in RISC-V
a0
und
a1
ist einfach ein Aliase für
x10
und
x11
. Hier werden das erste und das zweite Argument des Funktionsaufrufs platziert.
RET
Ist ein Pseudobefehl (Kurzschrift):
JALR x0, 0(ra) ; sp ← 0 + ra
; x0 ← sp + 4 ignoring result
JALR
Navigiert zu der darin gespeicherten Adresse
ra
, die sich auf die Absenderadresse bezieht.
ra
Ist ein Pseudonym
x1
.
Und alles sieht absolut schrecklich aus, oder? Doppelt so viele Befehle für eine einfache und häufig verwendete Operation, z. B. eine Indexsuche für eine Tabelle durchführen und ein Ergebnis zurückgeben.
Es sieht wirklich schlecht aus. Aus diesem Grund stand Erin Shepherd den Designentscheidungen der RISC-V-Entwickler äußerst kritisch gegenüber. Sie schreibt:
RISC-V-Vereinfachungen vereinfachen den Decoder (d. H. Den Front-End-Prozessor), gehen jedoch zu Lasten weiterer Anweisungen. Das Skalieren der Pipelinebreite ist jedoch eine schwierige Aufgabe, während das Decodieren einiger (oder sehr) ungewöhnlicher Befehle gut untersucht ist (die Hauptschwierigkeiten bei der Bestimmung der Befehlslänge sind nicht trivial - aufgrund seiner unendlichen Präfixe ist x86 ein besonders vernachlässigter Fall).
Dank der Befehlskomprimierung und der Makro-Op-Fusion kann die Situation jedoch zum Besseren verändert werden.
C.SLLI a1, 2 ; a1 ← a1 << 2
C.ADD a0, a1 ; a0 ← a0 + a1
C.LW a0, a0, 0 ; a0 ← [a0 + 0]
C.JR ra
Anweisungen belegen jetzt genau so viel Speicherplatz wie im Beispiel für ARM.
Okay, jetzt machen wir die Macro-Op-Fusion !
Eine der Bedingungen für RISC-V, um Zusammenführungsvorgänge zu einem zu ermöglichen, ist, dass das Zielregister übereinstimmt . Diese Bedingung ist für Befehle
ADD
und
LW
(Wort laden, "Wort laden") erfüllt . Daher wird der Prozessor sie in eine Anweisung umwandeln.
Wenn diese Bedingung für SLLI erfüllt ist, können wir alle drei Befehle zu einem zusammenführen . Das heißt, der Prozessor würde etwas sehen, das einer komplexeren ARM-Anweisung ähnelt:
LDR r0, [r0, r1, lsl #2]
Aber warum konnten wir diese komplexe Makrooperation nicht direkt in den Code schreiben?
Weil ISA eine solche Makrooperation nicht unterstützt! Denken Sie daran, dass wir eine begrenzte Anzahl von Bits haben. Dann verlängern wir die Befehle! Nein, dies nimmt zu viel Speicher in Anspruch und überläuft den wertvollen Prozessor-Cache schneller.
Wenn wir stattdessen diese langen, halbkomplexen Anweisungen im Prozessor ausgeben, treten keine Probleme auf. Ein Prozessor hat nie mehr als ein paar hundert Anweisungen gleichzeitig. Wenn wir also für jeden Befehl beispielsweise 128 Bit ausgeben, führt dies nicht zu Schwierigkeiten. Es wird immer noch genug Silizium für alles geben.
Wenn ein Decoder einen normalen Befehl empfängt, wandelt er ihn normalerweise in eine oder mehrere Mikrooperationen um. Diese Mikrooperationen sind die Anweisungen, mit denen der Prozessor tatsächlich arbeitet. Sie können sehr breit sein und viele zusätzliche nützliche Informationen enthalten. Das Präfix "micro" klingt ironisch, weil sie breiter sind. In der Realität bedeutet "Mikro" jedoch, dass sie eine begrenzte Anzahl von Aufgaben haben.
Durch das Zusammenführen von Makrooperationen wird die Arbeit des Decoders ein wenig auf den Kopf gestellt: Anstatt einen Befehl in mehrere Mikrooperationen umzuwandeln, nehmen wir viele Operationen und verwandeln sie in eine Mikrooperation.
Das heißt, was in einem modernen Prozessor passiert, kann ziemlich seltsam aussehen:
- Zunächst werden die beiden Befehle mithilfe der Komprimierung zu einem Befehl kombiniert .
- Dann teilt er sie beim Auspacken in zwei Teile .
- Anschließend werden sie mithilfe der Makro-Op-Fusion wieder zu einer Operation zusammengefasst .
Andere Befehle können in mehrere Mikrooperationen aufgeteilt und nicht zusammengeführt werden. Warum verschmelzen einige Teams, während andere sich trennen? Gibt es ein System in diesem Wahnsinn?
Ein wesentlicher Aspekt beim Übergang zu Mikrooperationen ist die erforderliche Komplexität:
- Nicht zu komplex, da sie sonst nicht in der Lage sind, eine feste Anzahl von Taktzyklen abzuschließen, die jedem Befehl zugeordnet sind.
- Nicht allzu einfach, da wir sonst nur die Prozessorressourcen verschwenden. Das Durchführen von zwei Mikrooperationen dauert doppelt so lange wie das Ausführen von nur einer.
Alles begann mit CISC-Prozessoren. Intel begann, seine komplexen CISC-Anweisungen in Mikrooperationen aufzuteilen, damit sie leichter in Prozessor-Pipelines wie RISC-Anweisungen passen. In nachfolgenden Konstrukten erkannten die Entwickler jedoch, dass viele CISC-Teams zu einem mäßig komplexen Team zusammengeführt werden konnten. Wenn weniger Befehle ausgeführt werden müssen, wird die Arbeit schneller abgeschlossen.
Vorteile erhalten
Wir haben viele Details besprochen, daher muss es für Sie jetzt schwierig sein zu verstehen, was die Bedeutung all dieser Arbeit ist. Wofür ist all diese Komprimierung und Zusammenführung? Sie scheinen viel unnötige Arbeit zu leisten.
Erstens ist die Befehlskomprimierung überhaupt nicht mit der Zip-Komprimierung vergleichbar. Das Wort "Komprimierung" ist etwas irreführend, da die sofortige Komprimierung oder Dekomprimierung eines Befehls völlig einfach ist. Hierfür wird keine Zeit verschwendet.
Gleiches gilt für die Makrooperationsfusion. Obwohl der Prozess kompliziert erscheinen mag, werden ähnliche Systeme bereits in modernen Mikroprozessoren verwendet. Daher wurden die Kosten, die all diese Komplexität mit sich bringt, bereits bezahlt.
Im Gegensatz zu den Designern von ARM, MIPS und x86 wussten die Entwickler von RISC-V jedoch zu Beginn der Entwicklung ihrer ISA über Befehlskomprimierung und Makrooperationsfusion Bescheid. Durch verschiedene Tests mit dem ersten minimalen Befehlssatz machten sie zwei wichtige Entdeckungen:
- RISC-V-Programme belegen normalerweise ungefähr den gleichen oder weniger Speicherplatz als jede andere Prozessorarchitektur. Einschließlich x86, das den Speicher effizient nutzen sollte, da es sich um ISA CISC handelt.
- Es muss weniger Mikrooperationen ausführen als andere ISAs.
Durch das Entwerfen des Basisbefehlssatzes unter Berücksichtigung der Fusion konnten sie genügend Befehle zusammenführen, so dass der Prozessor für jedes Programm weniger Mikrooperationen ausführen musste als konkurrierende Prozessoren.
Dies veranlasste das RISC-V-Entwicklungsteam, die Anstrengungen zur Implementierung der Makrooperationsfusion als grundlegende RISC-V-Strategie zu verdoppeln. Das RISC-V-Handbuch enthält viele Hinweise dazu, mit welchen Vorgängen Sie zusammenführen können. Es enthält auch einige Korrekturen, um das Zusammenführen von Befehlen in gängigen Mustern zu vereinfachen.
Kleine ISA erleichtern den Schülern das Lernen. Dies bedeutet, dass es für einen Studenten der Prozessorarchitektur einfacher ist, einen eigenen Prozessor zu entwerfen, der mit RISC-V-Anweisungen ausgeführt wird. Es ist zu beachten, dass sowohl die Befehlskomprimierung als auch die Makro-Op-Fusion optional sind.
RISC-V verfügt über einen kleinen grundlegenden Befehlssatz, der implementiert werden muss. Alle anderen Befehle werden jedoch als Teil der Erweiterungen implementiert. Die komprimierten Befehle sind nur eine optionale Erweiterung.
Makro-Op-Fusion ist nur Optimierung. Es ändert das Verhalten im Allgemeinen nicht und muss daher nicht in Ihrem eigenen RISC-V-Prozessor implementiert werden.
RISC-V-Entwurfsstrategie
RISC-V hat alles, was wir heute über moderne Prozessoren wissen, genutzt, um ISA-Prozessoren zu entwerfen. Zum Beispiel wissen wir, dass:
- Die heutigen Prozessorkerne verfügen über ein ausgeklügeltes Verzweigungsvorhersagesystem.
- Prozessorkerne sind superskalar, dh sie führen viele Anweisungen parallel aus.
- Um Superskalarität sicherzustellen, wird die Ausführung von Befehlen mit einer Änderung der Reihenfolge (Ausführung außerhalb der Reihenfolge) verwendet.
- Sie haben Förderer.
Dies bedeutet, dass Funktionen wie die von ARM unterstützte bedingte Ausführung nicht mehr erforderlich sind. Die Unterstützung von ARM für diese Funktion verbraucht Bits aus dem Befehlsformat. RISC-V kann diese Bits speichern.
Die bedingte Ausführung wurde ursprünglich entwickelt, um Gabeln zu vermeiden, da sie sich negativ auf Pipelines auswirken. Um die Arbeit des Prozessors zu beschleunigen, empfängt er normalerweise die folgenden Befehle im Voraus, so dass er unmittelbar nachdem der vorherige in der ersten Stufe des Prozessors ausgeführt wurde, den nächsten abholen kann.
Bei der bedingten Verzweigung können wir nicht im Voraus wissen, wo der nächste Befehl sein wird, wenn wir mit dem Befüllen der Pipeline beginnen. Ein superskalarer Prozessor kann jedoch einfach beide Zweige parallel ausführen.
Aus diesem Grund verfügt RISV-C auch nicht über Statusregister, da sie Abhängigkeiten zwischen Befehlen erzeugen. Je unabhängiger jeder Befehl ist, desto einfacher ist es, ihn parallel zu einem anderen Befehl auszuführen.
Grundsätzlich besteht die RISC-V-Strategie darin, ISA so einfach wie möglich und die minimale Implementierung des RISC-V-Prozessors so einfach wie möglich zu gestalten, ohne dass Entwurfsentscheidungen erforderlich sind, die es unmöglich machen würden, einen Hochleistungsprozessor zu erstellen.
Werbung
Unser Unternehmen bietet Server nicht nur mit Intel-CPUs an, sondern auch Server mit AMD EPYC-Prozessoren. Wie bei anderen Servertypen gibt es eine große Auswahl an Betriebssystemen für die automatische Installation. Es ist möglich, jedes Betriebssystem von Ihrem eigenen Image aus zu installieren. Versuchen Sie es jetzt!