Pregunta

estaba leyendo el manual de instrucciones intel y noté que hay una instrucción 'NOP' que no hace nada en la CPU principal y una instrucción 'FNOP' que no hace nada en la FPU.¿Por qué hay dos instrucciones separadas para no hacer nada?

La única diferencia que vi fue que arrojaron excepciones diferentes, por lo que puedes estar atento a una excepción de FNOP para detectar si hay una FPU disponible.¿Pero no existen otros mecanismos como CPUID para detectar esto?¿Qué razón práctica existe para tener dos instrucciones NOP separadas?

¿Fue útil?

Solución

Ampliando los comentarios de Raymond Chen y Hans Passant, hay razones históricas para que haya dos instrucciones separadas y por qué no tienen el mismo efecto.

Ninguna de las dos instrucciones, NOP y FNOP, fueron diseñados originalmente como una instrucción explícita de no operación.El NOP La instrucción es en realidad solo un alias de la instrucción. XCHG AX,AX.(O en modo de 32 bits XCHG EAX, EAX.) En los primeros procesadores Intel, en realidad no hacía nada.Si bien no tuvo ningún efecto visible externamente, internamente se ejecutó como un XCHG instrucción, tomando tantos ciclos para ejecutarse.El '486 fue la primera CPU Intel en tratarlo de manera especial, podía ejecutar un NOP en 1 ciclo, mientras que se necesitaron 3 ciclos para ejecutar cualquier otro registro a registro XCHG instrucción.

Tratando XCHG AX,AX La instrucción se vuelve especialmente importante en los procesadores Intel modernos.Si todavía estuviera intercambiando el mismo registro consigo mismo, podría introducir paradas en la tubería si una instrucción cercana también usara el AX registro.Al tratarlo de manera especial la CPU no termina pensando en el NOP necesita esperar una instrucción previa que establezca AX o que una siguiente instrucción necesita esperar a que NOP.

Esto trae a colación el hecho de que hay muchas instrucciones diferentes que no hacen nada, aunque XCHG AX,AX es el único que es de un solo byte (como un caso especial del registro de intercambio con acumulador de un solo byte XCHG codificaciones).A menudo estas instrucciones se utilizan como sustituto de una única instrucción para instrucciones consecutivas. NOP instrucciones, como cuando se alinea el inicio del bucle por razones de rendimiento.Por ejemplo, si quisiera un NOP de 6 bytes, podría usar LEA EAX,[EAX + 00000000].Intel finalmente agregó una instrucción NOP explícita de múltiples bytes.(Bueno, no tanto una instrucción añadida sino documentada oficialmente que había estado allí desde el Pentium Pro). Sin embargo, sólo la forma de un solo byte se trata de manera especial;los NOP de múltiples bytes generarán paradas si las instrucciones cercanas usan los mismos registros.

Cuando AMD añadió soporte de 64 bits a sus CPU, fue aún más lejos. NOP ya no es el equivalente a XCHG EAX,EAX en modo de 64 bits.Uno de los problemas con el conjunto de instrucciones de Intel es que hay muchas instrucciones que modifican sólo una parte del registro.Por ejemplo MOV BX,AX sólo modifica los 16 bits inferiores de EBX dejando los 16 bits superiores sin modificar.Estas modificaciones parciales dificultan que la CPU evite paradas, por lo que AMD decide evitarlo cuando utiliza instrucciones de 32 bits en modo de 64 bits.Siempre que el resultado de una operación de 32 bits se almacene en un registro (64 bits), el valor es cero extendido a 64 bits para que se modifique todo el registro.Esto significa XCHG EAX,EAX ya no es un NOP, ya que borra los 32 bits superiores de EAX (y por lo tanto, si escribes explícitamente XCHG EAX,EAX, no puede ensamblar a 0x90 y tiene que usar el 87 C0 codificación).En modo de 64 bits NOP ahora es un NOP explícito sin otra interpretación.


En cuanto a FNOP instrucción, en el 8087 original no está del todo claro cómo la FPU trató esta instrucción, pero estoy bastante seguro de que tampoco se manejó como una no operación explícita.Al menos un antiguo manual de Intel, el Manual de referencia del idioma ASM86 documenta que se está haciendo algo sin efecto ("almacena la parte superior de la pila en la parte superior de la pila").Desde su posición en el mapa de código de operación, parece que podría ser un alias para cualquiera de los dos. FST ST o FLD ST, los cuales copiarían la parte superior de la pila a la parte superior de la pila.Sin embargo, recibió un tratamiento especial: se ejecutó en un promedio de 13 ciclos en lugar del promedio de 18 o 20 ciclos de una pila a otra. FST o FLD instrucción respectivamente.Si se tratara como una instrucción sin operación, esperaría que fuera incluso más rápido, ya que hay varias instrucciones 8087 que se pueden ejecutar en la mitad del tiempo.

Más importante aún el FNOP La instrucción se comporta de manera diferente que NOP debido a cómo solían implementarse las instrucciones FPU en los procesadores Intel.La CPU en sí no admitía aritmética de punto flotante; en cambio, estas tareas se descargaron en un coprocesador de punto flotante opcional, originalmente el 8087.Una de las cosas buenas del coprocesador era que ejecutaba instrucciones en paralelo con la CPU.Sin embargo, esto significa que la CPU a veces necesita esperar a que la FPU finalice una operación.La CPU espera automáticamente a que termine de ejecutar la instrucción anterior antes de darle otra instrucción, pero un programa necesitaría esperar explícitamente (usando un WAIT instrucción) antes de que pudiera leer un resultado que el coprocesador escribió en la memoria.

Debido a que el coprocesador trabajaba en paralelo, esto también significaba que si una instrucción de la FPU generaba una excepción de punto flotante, cuando la detectaba la CPU ya habría pasado a ejecutar la siguiente instrucción.Normalmente, cuando una instrucción genera una excepción en la CPU, se maneja mientras esa instrucción aún se está ejecutando, pero cuando una instrucción de FPU genera una excepción, la CPU ya completó la ejecución de esa instrucción entregándola a la FPU.En lugar de interrumpir la CPU y entregar la excepción de punto flotante de forma asincrónica, la CPU solo recibe una notificación cuando espera al coprocesador, ya sea explícita o implícitamente.

En los procesadores modernos, la FPU ya no es un coprocesador, es una parte integral de la CPU.Esto significa que los programas ya no tienen que esperar a que la FPU escriba valores en la memoria.Sin embargo, la forma en que se manejan las excepciones de FPU no ha cambiado.(Resulta que entregar excepciones inmediatamente es difícil de implementar en las CPU modernas, por lo que aprovecharon el único caso en el que no tenían que hacerlo). Entonces, si una instrucción FPU anterior generó una excepción de punto flotante no entregada, se NOP dejar la excepción sin entregar, mientras FNOP, debido a que es una instrucción FPU, hará una "espera" implícita que resulta en la entrega de la excepción de punto flotante.

Este ejemplo demuestra la diferencia:

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top