x87
El x87 es un subconjunto de coma flotante del conjunto de instrucciones de la arquitectura x86. Se originó como una extensión del conjunto de instrucciones del 8086 en la forma de un coprocesador opcional de coma flotante que trabajó en paralelo con el correspondiente CPU x86. Estos microchips tenían nombres que terminaban en "87" (8087, 80287, 80387).
Como otras extensiones al conjunto de instrucciones básico, las instrucciones x87 no son estrictamente necesarias para construir programas funcionales, pero proporcionan implementaciones de hardware y microcódigo de tareas numéricas comunes, permitiendo a estas tareas desempeñarse mucho más rápido que las rutinas correspondientes en código de máquina. El conjunto de instrucciones x87 incluye instrucciones para operaciones de coma flotante básicas tales como adición, sustracción y comparación, como también para operaciones numéricas más complejas, como el cálculo de la función tangente y su inversa, por ejemplo.
Desde el Intel 80486, la mayoría de los procesadores x86 han tenido estas instrucciones x87 implementadas en el propio CPU, pero el término a veces es todavía usado para referirse a esa parte del conjunto de instrucciones. Antes de que las instrucciones x87 fueron estándar en los PC, los compiladores o programadores tenían que usar llamadas bastante lentas a bibliotecas, para realizar operaciones de coma flotante, un método que aún es común en sistemas empotrados (de bajo costo).
Descripción
[editar]Los registros del x87 forman una estructura de stack de 8 niveles de profundidad que van desde el registro ST(0) hasta el ST(7) con registros que pueden ser accesados directamente por cualquiera de los operandos, usando un desplazamiento relativo al tope del stack, así como también apilados y desapilados del stack. (Este esquema puede ser comparado con como un stack frame puede ser tanto apilado y desapilado como también indexado).
Existen instrucciones para apilar (push), desapilar (pop), y calcular valores en el stack; operaciones monádicas (FSQRT, FPTAN, etc.), que implícitamente direccionan el tope del stack ST(0) y operaciones diádicas (FADD, FMUL, FCOM, etc.) que implícitamente direccionan a los dos elementos del tope ST(0) y ST(1). El modelo de pila no estricto también permite operaciones diádicas que usan ST(0) junto con un operando de memoria directo o con un registro de stack ST(x) explícitamente especificado, en un rol similar a un acumulador tradicional (un operando de destino combinado con un operando de la izquierda). Esto también puede invertirse instrucción por instrucción con ST(0) como el operando sin modificar y ST(x) como el destino. Además, el contenido en ST(0) puede intercambiarse con otro registro del stack mediante una instrucción llamada FXCH ST(x) (intercambia ST(0) con ST(X)).
Estas propiedades hace el stack x87 usable como siete registros libremente direccionables más un acumulador dedicado (o como siete acumuladores independientes). Esto es especialmente aplicable en procesadores x86 superescalares (como el Pentium de 1993 y posteriores) donde sus instrucciones de intercambio (códigos D9C8..D9CFh) están optimizadas a cero ciclos de reloj usando uno de los caminos de enteros para FXCH ST(x) en paralelo con la instrucción del FPU. A pesar de ser natural y conveniente para los programadores humanos de lenguaje ensamblador, algunos desarrolladores de compiladores han encontrado complicado construir generadores de código automáticos que programen el código x87 efectivamente. Tal interfaz basada en stack potencialmente puede minimizar la necesidad de guardar variables temporales en llamadas a funciones en comparación con una interfaz basada en registros[1] (a pesar de que, históricamente, los problemas de diseño en la implementación original limitaron ese potencial).[2][3]
Los x87 proporciona aritmética de coma flotante binaria de simple precisión, doble precisión, y precisión extendida de 80 bits según el estándar IEEE 754-1985. Por defecto, todos los procesadores x87 usan internamente la precisión extendida de 80 bits (para permitir mantener la precisión sobre muchos cálculos, ver fundamentos de diseño del IEEE 754). Así, una determinada secuencia de operaciones aritméticas puede comportarse de forma ligeramente diferente en comparación con una FPU IEEE 754 de estricta simple precisión o doble precisión.[4] Esto a veces puede ser problemático para algunos cálculos seminuméricos escritos asumiendo doble precisión para el correcto funcionamiento: para evitar esos problemas, el x87 puede configurarse a través de un registro especial de estado/configuración para redondear automáticamente a simple o doble precisión después de cada operación. Desde la introducción del SSE2, las instrucciones de x87 no son tan esenciales como lo fueron una vez, pero siguen siendo importantes como una unidad escalar para cálculos numéricos sensibles a errores de redondeo y que requieren la parte significativa de 64 bits de precisión disponible en el formato de 80 bits.
Desempeño
[editar]Ciclos de reloj de típicas instrucciones del FPU x87 (solamente versiones de registro a registro son mostradas a continuación).[5]
La notación A~B (mínimo a máximo) cubre las variaciones de tiempo dependientes del estado de la tubería (pipeline) transciente, así como de la precisión aritmética elegida (32, 64 u 80 bits); también incluye variaciones debido a casos numéricos (por ejemplo, el número de bits encendidos, cero, etc.). Notación B→A muestra los valores correspondientes a las frecuencias de reloj más bajas (B) y más altas (A) que estaban disponibles.
Implementación x87 | FADD | FMUL | FDIV | FXCH | FCOM | FSQRT | FPTAN | FPATAN | Máx Reloj | FMUL/sec pico | Relativo al FMUL del 8087 de 5 MHz§ |
---|---|---|---|---|---|---|---|---|---|---|---|
8087 | 70~100 | 90~145 | 193~203 | 10~15 | 40~50 | 180~186 | 30~540 | 250~800 | 5→10 MHz | 34~55K → 100~111K | 1,0 → 2,0 veces más rápido |
80287 (original) | 70~100 | 90~145 | 193~203 | 10~15 | 40~50 | 180~186 | 30~540 | 250~800 | 6→12 MHz | 41~66K → 83~133K | 1,2 → 2,4 veces más rápido |
80387 (y posteriores modelos 287) | 23~34 | 29~57 | 88~91 | 18 | 24 | 122~129 | 191~497 | 314~487 | 16→33 MHz | 280~552K → 579~1100K | approx 10 → 20 × más rápido |
80486 (o el 80487) | 8~20 | 16 | 73 | 4 | 4 | 83~87 | 200~273 | 218~303 | 16→50 MHz | 1,0M → 3,1M | approx 18 → 56 × más rápido |
Cyrix 6x86, Cyrix MII | 4~7 | 4~6 | 24~34 | 2 | 4 | 59~60 | 117~129 | 97~161 | 66→300 MHz | 11~16M → 50~75M | approx 320 → 1400 × |
AMD K6 (incluyendo el K6 II/III) | 2 | 2 | ? | 2 | ? | ? | ? | ? | 166→550 MHz | 83M → 275M | approx 1500 → 5000 × |
Pentium / Pentium MMX | 1~3 | 1~3 | 39 | 1 (0*) | 1~4 | 70 | 17~173 | 19~134 | 60→300 MHz | 20~60M → 100~300M | approx 1100 → 5400 × |
Pentium Pro | 1~3 | 2~5 | 16~56 | 1 (0*) | 1 | 28~68 | ? | ? | 150→200 MHz | 30~75M → 40~100M | approx 1400 → 1800 × |
Pentium II / III | 1~3 | 2~5 | 17~38 | 1 (0*) | 1 | 27~50 | ? | ? | 233→1400 MHz | 47~116M → 280~700M | approx 2100 → 13000 × |
Athlon (K7) | 1~4 | 1~4 | 13~24 | 1 (0*) | 1~2 | 16~35 | ? | ? | 500→2330 MHz | 125~500M → 0,580~2,33G | approx 9000 → 42000 × |
Pentium 4 | 1~5 | 2~7 | 20~43 | 1 (0*) | ? | 20~43 | ? | ? | 1,3→3,8 GHz | 186~650M → 0,543~1,90G | approx 11000 → 34000 × |
Athlon 64 (K8) | 1~4 | 1~4 | 13~24 | 1 (0*) | 1~2 | 16~35 | ? | ? | 1,0→3,2 GHz | 250~1000M → 0,800~3,2G | approx 18000 → 58000 × |
* Es frecuentemente posible un retardo de reloj de cero, a través de la ejecución superescalar.
§ El 8087 de 5 MHz fue el procesador x87 original. Comparado con las típicas las rutinas de coma flotante implementadas por software en un 8086 (sin un 8087), los factores serían aún más grandes, tal vez por otro factor de 10 (es decir, una correcta adición de coma flotante en lenguaje ensamblador puede bien consumir más de 1000 ciclos).
Generaciones de la arquitectura
[editar]8087
[editar]El 8087 fue el primer coprocesador matemático para los procesadores de 16 bits diseñados por Intel (el i8231 era más antiguo, pero estaba diseñado para Intel 8080 de 8 bits); fue construido para ser emparejarse con los microprocesadores Intel 8086 o el Intel 8088.
80187
[editar]El 80187 (80C187)[6] fue el coprocesador matemático para el CPU Intel 80186. Era incapaz de operar con el 80188, debido a que el 80188 tenía un bus de datos de 8 bits; el 80188 solamente podía usar al 8087. El 80187 no apareció al mismo tiempo que el 80186 y el 80188, de hecho fue lanzado después del 80287 y el 80387. Aunque la interfaz para el procesador principal era la misma que la del 8087, su núcleo fue el del 80387 y por lo tanto era completamente compatible con el estándar IEEE 754 como también capaz de ejecutar las instrucciones extra del 80387.[7]
80287
[editar]El 80287 (287) fue el coprocesador matemático para la serie de microprocesadores Intel 80286. Los modelos de Intel incluyen variantes con límites superiores de frecuencia que van desde 6 hasta 12 MHz. Más tarde siguió el i80287XL con la microarquitectura 387 y el i80287XLT, una versión especial para portátiles, así como otras variantes.
El 80287XL fue realmente un 80387SX con un pinout de 287. Contenía un multiplicador de frecuencia interno de 3/2 para que las tarjetas madres que corrían el coprocesador a la velocidad de 2/3 la del CPU pudieran correr la FPU a la misma velocidad que el CPU. Otros modelos 287 con desempeño como el del 387 fueron el Intel 80C287, construido usando CHMOS III y el AMD 80EC287 fabricado con el proceso CMOS de AMD, usando solo puertas completamente estáticas.
El 80287 y el 80287XL trabajaron con el microprocesador 80386 y fueron inicialmente los únicos coprocesadores disponibles para el 80386 hasta la introducción del 80387 en 1987. Por último, eran capaces de trabajar con el Cyrix Cx486SLC. Sin embargo, el 80387 fue fuertemente preferido por su mayor rendimiento y la mayor capacidad de su conjunto de instrucciones.
80387
[editar]El 80387 (387 o i387) fue el primer coprocesador de Intel en ser totalmente compatible con el estándar IEEE 754. Lanzado en 1987, dos años completos después del chip 386, el i387 incluía mucho mayor velocidad que los coprocesadores anteriores de Intel 8087/80287 y mejoradas características de las funciones trigonométricas. (El 80287 limitaba el rango del argumento a más o menos 45 grados).
Sin un coprocesador, el 386 normalmente realizaba la aritmética de coma flotante a través de lentas rutinas de software, implementadas en tiempo de ejecución a través de un manejador de excepciones de software. Cuando un coprocesador está emparejado con el 386, el coprocesador realiza el coma flotante aritmético en hardware, retornando los resultados mucho más rápido que una llamada de biblioteca de software (emulando al coprocesador).
El 80387 fue compatible solamente con el chip i386 estándar, que tenía un bus de datos de 32 bits. El posterior i386SX de costo reducido, que tenía un más estrecho bus de datos de 16 bits, no podía conectarse con el bus de 32 bits del i387. El i386SX requería su propio coprocesador, el 80387SX, que era compatible con el más estrecho bus de datos de 16 bits del SX.
-
i387
-
i387SX
-
i387DX
-
Microarquitectura i387 con un Barrel shifter de 16 bits y una unidad CORDIC
80487
[editar]El i487SX fue comercializado como un coprocesador de coma flotante para máquinas con el Intel i486SX. En realidad contenía una implementación completa del i486DX. Cuando es instalado en un sistema 486SX, el i487 deshabilitaba a la CPU principal y tomaba control sobre todas las operaciones del CPU. El i487 tomaba medidas para detectar la presencia de un i486SX y no funcionaría sin el CPU original instalado.[8]
80587
[editar]El Nx587 fue el última FPU para el x86 en ser fabricado por separado del CPU, en este caso un NexGen Nx586.
Fabricantes
[editar]Las empresas que han diseñado y fabricado unidades de coma flotante compatibles con el Intel 8087 o modelos posteriores incluyen:
- AMD. 287, 387, 486DX, 5 x86, K5, K6, K7, K8
- Chips and Technologies. Los coprocesadores Super MATH
- Cyrix. FasMath, Cx87SLC, Cx87DLC, etc, 6x86, Cyrix MII
- Fujitsu. Primeros Pentium Mobile etc.
- Harris Semiconductor. Procesadores fabricados 80387 y 486DX
- IBM. Varios diseños 387 y 486
- IDT. WinChip, C3, C7, Nano, etc.
- IIT. 2C87, 3C87, etc.
- LC Technology. Los coprocesadoes Green MATH
- National Semiconductor, Geode GX1, Geode GXm, etc.
- NexGen. Nx587
- Rise Technology. El mP6
- ST Microelectronics. 486DX, 5x86, etc.
- Texas Instruments. Procesadores 486DX etc.
- Transmeta. TM5600 y TM5800
- ULSI. El coprocesador Math·Co
- VIA. El C3, C7 y Nano, etc.
- Xtend. El 83S87SX-25 y otros coprocesadores
Véase también
[editar]Referencias
[editar]- ↑ William Kahan (2 de noviembre de 1990). «On the advantages of 8087's stack. Unpublished course notes, Computer Science Division, University of California at Berkeley.». Archivado desde el original el 12 de junio de 2013. Consultado el 8 de junio de 2012.
- ↑ William Kahan (8 de julio de 1989). «How Intel 8087 stack overflow/underflow should have been handled."». Archivado desde el original el 12 de junio de 2013. Consultado el 8 de junio de 2012.
- ↑ Jack Woehr (1 de noviembre de 1997). «A conversation with William Kahan."».
- ↑ David Monniaux, The pitfalls of verifying floating-point computations, to appear in ACM TOPLAS
- ↑ Numbers are taken from respective processors' data sheets, programming manuals, and/or optimization manuals.
- ↑ CPU Collection - Model 80187 Archivado el 23 de julio de 2011 en Wayback Machine.
- ↑ http://www.datasheetcatalog.org/datasheet/Intel/mXryvuw.pdf
- ↑ Dictionary.com (ed.). «Intel 487SX». Consultado el 17 de octubre de 2010.