Hier gibt es ein paar verschiedene Kompromisse.
Zunächst möchten wir, dass die Befehle eine feste Breite (32 Bit) haben. Dies garantiert, dass die Anweisungen auf Cache-Block und Seite ausgerichtet sind, was das Vorhandensein von Cache und Seite sowie die Berechtigungsprüfungen vereinfacht.
Zweitens möchten wir, dass die verschiedenen Anweisungsfelder ( opcode
/ source regs
/ immediates
) eine feste Breite und eine feste Position haben. Dies macht sie schneller / weniger logisch zu dekodieren und sie werden in den frühen Phasen der Pipeline benötigt. (Das destination
Register wird erst am Ende der Pipeline benötigt, es kann sich also an verschiedenen Stellen in R
und an I
Anweisungen befinden.) Die Position und Breite des function
Feldes sind etwas weniger wichtig, da dies die Funktion der ALU steuern muss, aber das ist es In der dritten Phase der Pipeline haben Sie also etwas Zeit, um bei Bedarf damit zu arbeiten.
I
J
J
228228I
Anweisungen sind auch für Compiler / Linker-Autoren nützlich. (Auf dem SPARC, wo das unmittelbare Feld nur 12 Bits umfasste, mussten sie eine ganze spezielle load-high
Anweisungsklasse mit einem unmittelbaren 20-Bit-Wert hinzufügen .)
26= 64J
R
I
Aber das lässt ein wenig Spielraum mit den R
Anweisungen. Abgesehen von dem 6-Bit-Opcode benötigen diese nur 15 zusätzliche Bits für die Registerspezifikation, was 11 Bits für den erweiterten Opcode und / oder den Verschiebebetrag übrig lässt.
Sie sollten sich das function
Feld als erweiterten Opcode für die R
Anweisung vorstellen . Es gibt nur einen R
Befehls-Opcode, aber es gibt 64 verschiedene Befehle functions
, die der R
Befehl ausführen kann.
Okay. Wir haben 60 verschiedene I
Anweisungen und 64 verschiedene R
Anweisungen. Wo sollen wir also die Anweisungen für die Schicht sofort platzieren?
Nun, es gibt nicht nur weniger I
Anweisungen, sondern auch viel mehr Dinge, die wir mit I
Anweisungen tun möchten . Denken Sie daran, dass alle Verzweigungsanweisungen Anweisungen sein müssen, I
da sie einen relativen (unmittelbaren) Versatz haben. Auch alle Lade- und Speicheranweisungen sind I
in MIPS formatiert. Und schließlich brauchen wir die Anweisung Laden-Oben-Sofort, um eine I
Anweisung zu sein. Nicht nur das, sondern die R
Befehle enthalten noch 5 zusätzliche nicht verwendete Bits (was wir für das unmittelbare Verschieben eines Sofortbefehls in dieser Architektur benötigen), sodass dies einen weiteren Anreiz darstellt, die Verschiebungsbefehle in spezielle (seltsame) R
Befehle umzuwandeln .
Viele dieser Entscheidungen sind mehr Kunst als Wissenschaft, aber es gibt eine zugrunde liegende Logik, die erkannt werden kann. Das Hauptziel ist nicht die Anzahl der Anweisungen so klein wie möglich zu machen, ist es ein machen HochleistungsPipeline passt auf einen einzigen Chip (so dass winzige Unternehmen wie MIPS und Sun in den 1980er Jahren mit IBM und DEC konkurrieren konnten). (Der von David Patterson erfundene Name RISC ist etwas unglücklich. Er hat sich durchgesetzt, weil er niedlich war, und nicht, weil "reduzierte Anweisungen" eine genaue Beschreibung dessen sind, was die MIPS- und SPARC-Architekturen wirklich versucht haben.) Anweisungen mit fester Breite (und relativ klein, damit Sie ein besseres I-Cache-Verhalten erzielen), um das Abrufen, Blättern und Dekodieren einfacher und schneller zu machen. Sie möchten die Teile der Anweisung, die vorzeitig dekodiert werden müssen (opcode
, die beiden Quellregister und das Vorzeichen sofort erweitert), um eine feste Breite und eine feste Position zu haben. Sie möchten, dass die Anweisungen so lang wie möglich sind, und Sie möchten so viele verschiedene Arten von Anweisungen, wie dies angesichts all dieser anderen Einschränkungen möglich ist.
Um die MIPS I-Befehlsformate zu verstehen, müssen Sie die MIPS-Pipeline verstehen und auch auf die CPU-Implementierungstechnologie von 1985 zurückblicken ID-Phase direkt nach IF.
Für den Zweck einer Anweisung vom Typ R muss die ID-Stufe die folgenden Aufgaben ausführen:
Für den Zweck dieser Diskussion ist es die erste Aufgabe, über die Sie nachdenken müssen. Wenn Sie viele Anweisungen dekodieren müssen, um zu ermitteln, ob Werte aus den Registern benötigt werden, verlängert sich die Verzögerung, bevor Sie mit dem Lesen der Register beginnen können. Dies erhöht auch die Komplexität der ID-Stufe. Indem Sie einen einzigen Operationscode für alle Anweisungen vom Typ R reservieren, reduzieren Sie die Komplexität auf ein Minimum.
Es scheint ein wenig seltsam, dass Sie fünf Bits nur für das Verschieben verwenden. Ich kann mir ein paar mögliche Erklärungen vorstellen. Zum einen wird das Routing vereinfacht (diese fünf Bits werden IMMER direkt in die Registerdatei eingespeist, diese fünf Bits werden IMMER in den Barrel-Shifter eingespeist, diese sechs Bits werden IMMER an die ALU weitergeleitet, um zu bestimmen, welche Funktion auszuführen ist).
Sie haben möglicherweise darüber nachgedacht, in Zukunft kombinierte Anweisungen zum Verschieben nach links und zum Hinzufügen einzuführen. Dies hätte vermutlich die Form:
Heutzutage würden wir wahrscheinlich nicht zweimal über eine komplexere Dekodierungsphase nachdenken, zumal Register-Dateizugriffe in der Pipeline einer typischen superskalaren CPU eher später erfolgen. Viele moderne CPUs führen sogar eine grobe Befehlsdecodierung durch, wenn ein Befehl in den L1-Cache eingefügt wird . Sie verbreitern die I-Cache-Zeilen ein paar Bits, um die zusätzlichen Informationen zu speichern (dank Moore's Law müssen Sie viele Transistoren verschwenden), damit die "richtige" Befehlsdecodierung einfacher und schneller wird.
Ein Grund, warum sie das Opcode-Feld wahrscheinlich so klein wie möglich halten wollten, ist, dass es J-Typ-Befehle nicht übermäßig bestraft. Wie Sie wahrscheinlich wissen, verwenden Befehle vom Typ J eine pseudo-direkte Adressierung. Zum Wohle aller, die zu Hause mitspielen, erkläre ich es kurz.
Das Adressfeld eines Befehls vom J-Typ ist 26 Bit. Da Befehle immer 4-Byte-ausgerichtet sind, müssen Sie nicht die niedrigstwertigen zwei Bits speichern, was bedeutet, dass Sie effektiv 28 Adressbits haben. Der Adressraum in MIPS I beträgt jedoch 32 Bit. Die oberen vier Bits der Sprungstelle werden also vom Programmzähler übernommen.
Dies bedeutet, dass Sie nicht direkt zu einem Ort springen können, an dem sich die vier höchstwertigen Bits des PC-Standorts unterscheiden. Sie müssten stattdessen einen teureren Drei-Anweisungen-Sprung durch ein Scratch-Register durchführen:
Das ist heute nicht schlecht, aber 1985 sind es viele Taktzyklen.
Wenn Sie ein wenig aus dem Adressfeld stehlen, würde sich die effektive Reichweite eines Direktsprungs noch weiter verringern. Sie können sehen, dass dieser Preis möglicherweise zu hoch ist.
quelle