In modernen Mikroarchitekturen mit Registerumbenennung sind die Implementierungskosten für Flags oder Nicht-Flags ziemlich ähnlich. Der Hauptunterschied, den ich mir vorstellen kann, besteht darin, dass einige Flags die Eigenschaften eines Werts anzeigen (Ist der Wert negativ? Ist der Wert Null? Hat der Wert eine gerade oder ungerade Parität?), Während einige ein Ereignis darstellen, das während einer vorherigen Operation aufgetreten ist (Hatte der Befehl add einen Übertrag oder einen Überlauf?) Dies führte auf dem MIPS zu einer nicht idealen Situation, als Sie eine 64-Bit-Addition auf der 32-Bit-Architektur (oder eine 128-Bit-Addition auf dem MIPS) simulieren wollten 64-Bit-Architektur.) Auf den meisten Architekturen mit Carry-Flag gibt es eine spezielleadd-with-carry
Befehl, der das Übertragsflag aus dem vorherigen Befehl add enthält. Dies macht das Simulieren von Arithmetik mit mehreren Genauigkeiten auf vielen Architekturen mit Flags-Registern relativ kostengünstig.
Auf der anderen Seite ist das Testen eines N-Bit-Registers auf Null oder Nicht-Null tatsächlich überraschend teuer. Um ein N-Bit-Register auf Null zu testen, müssen Sie eine N-Bit-NOR-Operation ausführen, für deren Berechnung Logikpegel erforderlich sind . Bei Architekturen mit Flags-Registern kann die zusätzliche Logik für die Null- / Nicht-Null-Berechnung am Ende der ALU-Stufe dazu führen, dass der Takt langsamer läuft (oder die ALU zu zwei Zyklusoperationen gezwungen wird). Aus diesem Grund, denke ich, einige Architekturen wie SPARC hatten zwei Versionen jeder arithmetischen Operation, eine, die Flags setzte, und eine, die keine hatte.O ( logN)
Aber MIPS speichert hier nichts. Sie haben das Problem einfach woanders hingelegt. Auf MIPS gibt es eine branch-on-equal
Anweisung. Dies bedeutet, dass der Verzweigungsbefehl tatsächlich eine ALU-Stufe haben muss (einschließlich einer bitweisen xor
Operation, gefolgt von einem nor
, um auf das einzelne gleiche / ungleiche Bit zu reduzieren), bevor bestimmt wird, in welche Richtung die Verzweigung geht.
Die DEC Alpha-Architektur hat versucht, den Unterschied mit einem Trick aufzuteilen. DEC Alpha hatte keine Flaggenregister, aber auch keine branch-on-equal
Anweisung. Stattdessen betrachten alle Verzweigungsbefehle den Zustand eines einzelnen Universalregisters. Es ist branch-on-zero
, branch-on-not-zero
, branch-on-less-than-zero
etc. Der Trick ist , dass Sie alle Universalregister ein zusätzliches 65. Bit , das Ihnen sagt , geben kann , ob die anderen 64 Bits alle Null ist oder nicht. Das macht es eher so, als hätte man ein Flagsregister: Alle Verzweigungsbefehle betrachten ein einziges Bit (das bereits berechnet wurde), um ihre Entscheidung zu treffen, aber jetzt müssen Sie wieder herausfinden, wie Sie dieses zusätzliche Null-Indikatorbit während einer normalen ALU berechnen Zyklus. (Und Sie können immer noch keine Multi-Präzisions-Arithmetik ausführen, indem Sie nur das Carry-Flag der vorherigen Operation betrachten.)
1 Aus ISA-Sicht
Testanweisungen, die nur die Flags setzen, sind nur eine Möglichkeit, den Registerdruck in Architekturen mit Registermangel zu verringern. Wenn Sie genug Register haben, ändern Sie einfach eines davon und ignorieren Sie das Ergebnis. Der Trick, ein Register 0 mit dem Eingabewert 0 zu haben, ist nur ein Codierungstrick, der praktisch ist, wenn Sie genug Register haben, um eines davon auf 0 zu setzen, anstatt die Anzahl der Befehle zu erhöhen. Es ist dann bequem, es auch als Ziel zu verwenden (es reduziert die Anzahl falscher Abhängigkeiten).
Nochmal codieren. Wenn Sie die Bedingung in Sprüngen codieren, haben Sie Sprünge mit 3 Operanden (die beiden zu vergleichenden und das Sprungziel), von denen zwei unmittelbare Werte sein sollen, einer so groß wie möglich (Sprünge haben oft ein eigenes Codierungsformat, damit das Ziel so viele Bits wie möglich verwenden kann). Oder du lässt Möglichkeiten fallen.
Die Verwendung von Flags bietet Ihnen mehr Möglichkeiten, diese zu setzen. Es sind nicht nur die Vergleichsoperationen, die die Flags setzen können, sondern was auch immer Sie wollen. (Mit der Einschränkung, dass je mehr Operationen Sie haben, die Flags setzen, desto sorgfältiger müssen Sie sicherstellen, dass die letzte Operation, die die Flags setzt, die gewünschte ist). Wenn Sie Flags haben, können Sie die Anzahl der Bedingungen (häufig 16) multiplizieren mit der Anzahl der Anweisungen, mit denen die Flags gesetzt werden können. Wenn Sie keine Flags verwenden, erhalten Sie ungefähr so viele bedingte Sprünge wie Sie Dinge zu testen haben oder es gibt Dinge, die Sie nicht so einfach testen können (zum Beispiel Übertragen oder Überlaufen).
2 Aus Sicht des Implementierers
Das Testen von Flags ist einfach und schnell erledigt. Je komplexer Ihr Test ist, desto mehr Auswirkungen hat er auf die Zykluszeit (oder auf die Pipeline-Struktur, wenn Sie eine Pipeline-Verbindung herstellen). Dies gilt insbesondere für einfachere Implementierungen. Wenn Sie mit allen Tricks des Buches zu einem High-End-Prozessor gelangen, ist der Effekt ziemlich gering.
Flags zu haben bedeutet, dass viele Anweisungen mehrere Ergebnisse haben (das natürliche Ergebnis und jedes der modifizierten Flags). Und bei einem POV mit Mikroarchitektur sind mehrere Ergebnisse schlecht (Sie müssen die Zuordnung nachverfolgen). Wenn Sie nur einen Satz von Flags haben, die Abhängigkeiten einführen (nicht erforderlich, wenn das Flag dann nicht verwendet wird), müssen Sie auf die eine oder andere Weise damit umgehen. Dies gilt insbesondere für einfachere Implementierungen. Wenn Sie mit allen Tricks des Buches zu einem High-End-Prozessor gelangen, werden die zusätzlichen Schwierigkeiten vom Rest des Prozessors in den Schatten gestellt.
quelle
Auf einer 32-Bit-Maschine muss ein "Add-with-Carry" -Befehl, der als Teil einer Additionssequenz mit Mehrfachgenauigkeit verwendet wird, Operanden im Wert von 65 Bit akzeptieren und eine 33-Bit-Summe berechnen. Die Quellregisterspezifikationen geben an, woher 64 Operandenbits kommen sollen, und die Zielregisterspezifikation gibt an, wohin die unteren 32 Bits des Ergebnisses gehen sollen, aber was mit dem Operanden "add one extra" oder dem oberen Bit zu tun ist des ergebnisses? Als Teil des Befehls angeben zu dürfen, woher der zusätzliche Operand kommen soll und wohin das zusätzliche Ergebnisbit gehen soll, wäre mäßig nützlich, aber es wäre im Allgemeinen nicht so nützlich, ein zusätzliches Feld im Opcode zu rechtfertigen. Einen festen "Ort" für die Handhabung des Übertrags-Flags zu haben, kann aus Sicht der Befehlsplanung etwas umständlich sein, aber es ist
Wenn man versuchen würde, einen Befehlssatz zu entwerfen, der Arithmetik mit Mehrfachgenauigkeit ermöglicht, aber jeder Befehl auf zwei 32-Bit-Operanden und einen 32-Bit-Zieloperanden beschränkt ist, könnte man ein 64-Bit-Add in vier Befehlen implementieren: set r5 auf 1, wenn r0 + r2 andernfalls den Wert 0 haben würde; berechne r4 = r1 + r3; berechne r5 = r4 + r5; berechne r4 = r0 + r2 ", aber darüber hinaus würde es drei Anweisungen für jedes zusätzliche Wort erfordern. Durch die Verfügbarkeit eines Carry-Flags als zusätzliche Quelle und Ziel werden die Kosten auf einen Befehl pro Wort reduziert.
Man beachte übrigens, dass eine Befehlsbitsteuerung, ob der Befehl das Flagregister aktualisiert, eine Ausführung außerhalb der Reihenfolge erleichtern kann, da Befehle, die die Flagbits verwenden oder modifizieren, ihre Reihenfolge relativ zueinander beibehalten müssen, Befehle, die dies jedoch nicht tun frei angeordnet werden. Angesichts der Reihenfolge:
Eine Ausführungseinheit könnte ziemlich leicht erkennen, dass der dritte Befehl ausgeführt werden könnte, ohne darauf warten zu müssen, dass Daten gelesen werden
[r1]
, aber wenn der zweite Befehl ausgeführt worden wäreadds r0,r0,r2
, wäre dies nur möglich, wenn die Ausführungseinheit sicherstellen könnte, dass zu dem Zeitpunkt etwas versucht wird, dies zu verwenden Bei den Flags würde das Null-Flag den in der dritten Anweisung festgelegten Wert enthalten, während das Übertrags-Flag den Wert in der zweiten Anweisung enthält.quelle
Einfache Antwort ... schnelle, kostengünstige Speicheroperation, die bis auf die Anweisung selbst absolut keine interne Busbenutzung erfordert. Es kann als Stack-Bool ohne Stack oder Prozessbit ohne Speicher verwendet werden.
quelle