Frage

Ich habe das gelesen Intel-Bedienungsanleitung und bemerkte, dass es einen „NOP“-Befehl gibt, der nichts auf der Haupt-CPU tut, und einen „FNOP“-Befehl, der nichts auf der FPU tut.Warum gibt es zwei separate Anweisungen zum Nichtstun?

Der einzige Unterschied, den ich gesehen habe, war, dass sie unterschiedliche Ausnahmen auslösen. Sie können also auf eine Ausnahme von FNOP achten, um festzustellen, ob eine FPU verfügbar ist.Aber gibt es nicht auch andere Mechanismen wie CPUID, um dies zu erkennen?Welchen praktischen Grund gibt es für zwei separate NOP-Anweisungen?

War es hilfreich?

Lösung

Ergänzend zu den Kommentaren von Raymond Chen und Hans Passant gibt es historische Gründe dafür, dass es zwei separate Anweisungen gibt und warum sie nicht ganz die gleiche Wirkung haben.

Keine der beiden Anweisungen, NOP Und FNOP, wurden ursprünglich als explizite Anweisung ohne Bedienung konzipiert.Der NOP Anweisung ist eigentlich nur ein Alias ​​für die Anweisung XCHG AX,AX.(Oder im 32-Bit-Modus XCHG EAX, EAX.) Bei frühen Intel-Prozessoren hat es eigentlich nichts bewirkt.Während es äußerlich keine sichtbare Wirkung hatte, wurde es innerlich genauso ausgeführt XCHG Anweisung, deren Ausführung ebenso viele Zyklen benötigt.Der '486 war die erste Intel-CPU, die ihn speziell behandelte, er konnte a ausführen NOP in einem Zyklus, während die Ausführung jedes anderen Register-zu-Register-Vorgangs 3 Zyklen dauerte XCHG Anweisung.

Behandeln XCHG AX,AX Insbesondere bei modernen Intel-Prozessoren kommt der Anleitung eine große Bedeutung zu.Wenn es tatsächlich immer noch dasselbe Register mit sich selbst austauscht, könnte es zu Pipeline-Störungen kommen, wenn ein nahegelegener Befehl ebenfalls das verwendet AX registrieren.Durch die besondere Behandlung denkt die CPU nicht darüber nach NOP muss auf eine vorherige Anweisung warten, die festgelegt wird AX oder dass eine folgende Anweisung auf die warten muss NOP.

Dies bringt jedoch die Tatsache zum Ausdruck, dass es viele verschiedene Anweisungen gibt, die nichts bewirken XCHG AX,AX ist das einzige, das ein einzelnes Byte ist (als Sonderfall des Austauschregister-mit-Akkumulator-Einzelbyte XCHG Kodierungen).Oft werden diese Anweisungen als Einzelanweisungsersatz für aufeinanderfolgende Anweisungen verwendet NOP Anweisungen, z. B. beim Ausrichten des Schleifenanfangs aus Leistungsgründen.Wenn Sie beispielsweise ein 6-Byte-NOP wünschen, können Sie es verwenden LEA EAX,[EAX + 00000000].Intel fügte schließlich einen expliziten Mehrbyte-NOP-Befehl hinzu.(Nun ja, eine Anweisung, die seit dem Pentium Pro vorhanden war, wurde nicht so sehr hinzugefügt, sondern offiziell dokumentiert.) Es wird jedoch nur die Einzelbyte-Form speziell behandelt;Die Mehrbyte-NOPs erzeugen Verzögerungen, wenn benachbarte Befehle dieselben Register verwenden.

Als AMD seinen CPUs 64-Bit-Unterstützung hinzufügte, ging man sogar noch einen Schritt weiter. NOP ist nicht mehr das Äquivalent von XCHG EAX,EAX im 64-Bit-Modus.Eines der Probleme mit dem Intel-Befehlssatz besteht darin, dass es viele Befehle gibt, die nur einen Teil des Registers ändern.Zum Beispiel MOV BX,AX Modifiziert nur die unteren 16 Bits von EBX Die oberen 16 Bit bleiben unverändert.Diese teilweisen Modifikationen erschweren es der CPU, Blockierungen zu vermeiden, weshalb AMD beschließt, dies zu verhindern, wenn 32-Bit-Anweisungen im 64-Bit-Modus verwendet werden.Immer wenn das Ergebnis einer 32-Bit-Operation in einem (64-Bit-)Register gespeichert wird, Der Wert ist Null, erweitert auf 64 Bit, sodass das gesamte Register geändert wird.Das heisst XCHG EAX,EAX ist kein NOP mehr, da es die oberen 32 Bits löscht EAX (und somit, wenn Sie explizit schreiben XCHG EAX,EAX, es kann nicht auf 0x90 assembliert werden und muss das verwenden 87 C0 Codierung).Im 64-Bit-Modus NOP ist jetzt ein explizites NOP ohne andere Interpretation.


Wie für die FNOP Beim ursprünglichen 8087 ist nicht ganz klar, wie die FPU diese Anweisung behandelt hat, aber ich bin mir ziemlich sicher, dass sie auch nicht als explizite No-Operation behandelt wurde.Zumindest ein altes Intel-Handbuch, das ASM86-Sprachreferenzhandbuch dokumentiert, als ob etwas ohne Wirkung ausgeführt wird („Speichert die Stapeloberseite auf der Stapeloberseite“).Aufgrund seiner Position in der Opcode-Karte sieht es so aus, als wäre es ein Alias ​​für beides FST ST oder FLD ST, die beide den oberen Rand des Stapels an den oberen Rand des Stapels kopieren würden.Allerdings erhielt es eine Sonderbehandlung: Die Ausführung dauerte durchschnittlich 13 Zyklen statt der durchschnittlichen 18 oder 20 Zyklen, die ein Stapel zum Stapeln benötigte FST oder FLD Anleitung bzw.Wenn es als operationsfreie Anweisung behandelt würde, erwarte ich, dass es sogar noch schneller wäre, da es eine Reihe von 8087-Anweisungen gibt, die in der Hälfte der Zeit ausgeführt werden können.

Noch wichtiger ist die FNOP Anweisung verhält sich anders als NOP aufgrund der Art und Weise, wie FPU-Anweisungen früher auf Intel-Prozessoren implementiert wurden.Die CPU selbst unterstützte keine Gleitkomma-Arithmetik, stattdessen wurden diese Aufgaben auf einen optionalen Gleitkomma-Coprozessor, ursprünglich den 8087, verlagert.Eines der schönen Dinge am Coprozessor war, dass er Anweisungen parallel zur CPU ausführte.Dies bedeutet jedoch, dass die CPU manchmal warten muss, bis die FPU einen Vorgang beendet.Die CPU wartet automatisch, bis die Ausführung des vorherigen Befehls abgeschlossen ist, bevor sie ihr einen weiteren Befehl erteilt. Ein Programm müsste jedoch explizit warten (mithilfe von a WAIT Anweisung), bevor er ein Ergebnis lesen konnte, das der Coprozessor in den Speicher geschrieben hat.

Da der Coprozessor parallel arbeitete, bedeutete dies auch, dass, wenn ein FPU-Befehl eine Gleitkomma-Ausnahme generierte, die CPU zum Zeitpunkt der Erkennung dieser Ausnahme bereits mit der Ausführung des nächsten Befehls fortgefahren wäre.Normalerweise wird eine Anweisung, die eine Ausnahme auf der CPU generiert, verarbeitet, während die Anweisung noch ausgeführt wird. Wenn jedoch eine FPU-Anweisung eine Ausnahme generiert, hat die CPU die Ausführung dieser Anweisung bereits abgeschlossen, indem sie sie an die FPU übergeben hat.Anstatt die CPU zu unterbrechen und die Gleitkommaausnahme asynchron auszuliefern, wird die CPU nur dann benachrichtigt, wenn sie explizit oder implizit auf den Coprozessor wartet.

In modernen Prozessoren ist die FPU kein Coprozessor mehr, sondern ein integraler Bestandteil der CPU.Das bedeutet, dass Programme nicht mehr darauf warten müssen, dass die FPU Werte in den Speicher schreibt.Die Art und Weise, wie FPU-Ausnahmen behandelt werden, hat sich jedoch nicht geändert.(Es stellte sich heraus, dass die sofortige Übermittlung von Ausnahmen auf modernen CPUs schwierig zu implementieren ist, sodass sie den einen Fall ausnutzten, in dem dies nicht erforderlich war.) Wenn also ein vorheriger FPU-Befehl eine nicht zugestellte Gleitkomma-Ausnahme generierte, a NOP Lassen Sie die Ausnahme nicht zugestellt, while FNOP, Da es sich um eine FPU-Anweisung handelt, führt sie eine implizite „Wartezeit“ durch, die dazu führt, dass die Gleitkomma-Ausnahme übermittelt wird.

Dieses Beispiel zeigt den Unterschied:

FLD1       ; push 1.0 onto the FPU stack
FLDZ       ; push 0.0
FDIV       ; divide 1.0 by 0.0
NOP        ; does nothing
NOP        ; does nothing
FNOP       ; signals a FP zero-divide exception and then does nothing
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top