Compuesto por 29.000 transistores, 4 veces más que su antecesor directo, el 8080. El Intel 8086 fue lanzado en 1978 y no solo fue el primer microprocesador de 16 bits de la compañía, sino que años más tarde sería adoptado por IBM para empezar un legado que dura hasta el día de hoy. No obstante, en esta entrada nos centraremos única y exclusivamente en la CPU.
El 8086, una CPU con un destino inesperado
El 8086 fue lanzado inicialmente por Intel en 1978, tres años antes de que IBM lo escogiera (bueno, su versión recortada, el 8088) para la creación de su modelo 5150, el cual fue el primer PC basado en el set de instrucciones x86. Por lo que al contrario de lo que muchos piensan, este microprocesador de Intel no nació para dicho estándar, sino que le precede, es más, Intel no lo diseño jamás como una CPU que fuera a tener una larga vida.
Por aquel entonces, el mayor proyecto de Intel era el 8800, un chip que con el tiempo se convertiría en el iAPX 432, una CPU que fue un fiasco enorme y si no fuese por el contrato por el PC a día de hoy ni tan siquiera hubiésemos sabido del 80286. Sin embargo, el proyecto se retrasaba más y más y decidieron crear una solución intermedia, un microprocesador que se situase entre el 8080 y su próximo proyecto, y así nació el Intel 8086.
La arquitectura del Intel 8086
A finales de los 70, la memoria empezaba a ser mucho más lenta que los microprocesadores y la diferencia no parecía que fuese a acortarse, es más, décadas después podemos decir que esta ha aumentado, lo que ha llevado a la implementación de técnicas para paliar este problema. La forma de hacerlo en el 8086 fue dividir la CPU en dos mitades:
- La bus interface unit incluía los 6 bytes de precaptación (prefetch) así como el mecanismo para manejar la memoria segmentada.
- La Execution Unit incluía el decodificador (microcódigo) y la ALU.
Instrucciones en el Intel 8086
Pese a ser una evolución del 8080, al contrario que el Z80, el Intel 8086 no es binariamente compatible hacia atrás, por lo que los programas no se ejecutarán sin volver a ser recompilados, no obstante, el 8086 dispone de un set de instrucciones 1:1 con su antecesor, pero al mismo tiempo añade un conjunto de instrucciones nuevas ampliando el total hasta 133. No obstante, la evolución en el set de instrucciones es diferente al chip de Zilog, ya que Intel tomo un camino distinto para construir el set de instrucciones de su primera CPU de 16 bits.
Entre las nuevas instrucciones que Intel añadió a su 8086 respecto al 8080 podemos encontrar:
- Instrucciones para mover, cargar, almacenar, comparar y escanear cadenas de bytes o palabras.
- Aquellas que sirven para manejar segmentos de memoria.
- Instrucciones aritméticas de multiplicación y división de forma directa, con o sin signo. Sin tener que usar combinaciones de sumas y restas.
- Saltos condicionales (cero, igual, mayor o menor (con y sin signo))
- Operaciones para probar, establecer, restablecer, y buscar bits en los registros.
- Rotaciones de bits a la izquierda/derecha, con y sin acarreo.
- Instrucciones adicionales para manipular la pila.
- Llamadas a subrutinas, retornos y control de bucles, así como manejo de interrupciones
- Transferencia de datos desde/hacia puertos de E/S, además de operaciones en cadena para entradas/salidas masivas.
- Instrucciones para manipular los flags (de acarreo, dirección e interrupción), así como habilitar o deshabilitar interrupciones.
A medida que ha pasado el tiempo y con cada nueva CPU, el set de instrucciones conocido como x86 ha ido aumentando. Claro está, que hay que aclarar que el microprocesador que se toma de base a día de hoy no es el 8086 original que lanzó Intel en 1978, sino el 80386, que fue el primero de 32 bits.
Registros en el 8086
Pese a ser compatible hacia atrás con el 8080, al menos a nivel del código escrito en lenguaje ensamblador. A nivel interno se trata de un microprocesador totalmente distinto y eso se puede ver con el set de registros del Intel 8086, el cual es totalmente distinto al del 8080.
Registro | Función |
---|---|
AX | Acumulador, usado en operaciones aritméticas y de E/S. Dividido en AH (alta) y AL (baja). |
BX | Base, usado a menudo en operaciones de direccionamiento. Dividido en BH (alta) y BL (baja). |
CX | Contador, usado en bucles y operaciones de cadena. Dividido en CH (alta) y CL (baja) |
DX | Registro de datos, usado en operaciones de multiplicación y división. Dividido en DH (alta) y DL (baja) |
CS | Almacena la dirección base del segmento de código. |
DS | Almacena la dirección base del segmento de datos |
SS | Almacena la dirección base del segmento de pila. |
ES | Usado para almacenar direcciones adicionales (por ejemplo, en operaciones con cadenas). |
SP | Puntero de pila (Stack Pointer). Apunta a la parte superior de la pila (relativo al segmento SS). |
BP | Puntero base (Base Pointer). Usado para acceder a los datos en la pila (relativo al segmento SS). |
SI | Índice de origen (Source Index). Usado para acceder a datos en operaciones de cadena (relativo al segmento DS). |
DI | Índice de destino (Destination Index). Usado en operaciones de cadena, apuntando a la memoria destino (relativo al segmento ES). |
IP | Puntero de instrucción (Instruction Pointer). Apunta a la siguiente instrucción a ejecutar (relativo al segmento CS). |
FLAGS | Controla el flujo de las instrucciones en base a sus valores (carry, zero, overflow, etc.). |
Todos y cada uno de los registros mencionados en la tabla de arriba tienen un tamaño de 16 bits. Cómo se puede ver, los registros del 8086, al contrario de las instrucciones, no tienen una correlación 1:1 con los de su antecesor.
La ventaja de ello es que permitía tener una especie de pipeline primitivo donde mientras la EU estaba decodificando y ejecutando una instrucción, la BIU se encontraba captando la siguiente. No obstante, no es una segmentación completa de las etapas de una CPU, ya que en este caso solo el FETCH se encuentra separado del resto.
La primera CPU de 16 bits de Intel
El 8086, al contrario que el 8080, se trata de la primera CPU de 16 bits de la empresa cofundada por Gordon Moore, esto significa que el tamaño de sus registros, la capacidad de procesamiento de su unidad de ejecución, el bus de datos y el de direcciones de dicho tamaño. La única diferencia se encuentra en el 8088, que dispone de un bus de datos de 8 bits.
La otra gran novedad fue el direccionamiento de 20 bits, lo que significa tener acceso de hasta 1 MB de memoria RAM sin hardware adicional como es el uso de mecanismos multibanco. Recordemos que otros microprocesadores contemporáneos como el Z80 o el 6502 solo podían direccionar 64 KB de memoria. Lo cual permite trabajar con cantidades de datos más grandes y programas más complejos. Y es que en los primeros días de la informática personal, era habitual superar el límite de 64 KB, sobre todo en el mercado empresarial.
No obstante, el problema es que debido a que el bus de datos y los registros es de 16 bits, no se pueden transmitir los 20 bits de la dirección en un solo acceso al bus. Es por ello que la organización de memoria en el 8086 se encuentra segmentada.
¿Qué significa que la memoria esté segmentada?
En el caso del Intel 8086, este no accede de forma tradicional a la memoria RAM, sino que la tiene organizada por segmentos, donde cada uno de ellos es de 64 KB de tamaño. Por lo que utiliza la siguiente fórmula:
- Dirección física = (Valor del segmento × 16) + Desplazamiento
El valor de segmento se almacena en el registro CS y el desplazamiento en el registro IP. Sin embargo, dicho método trae consigo problemas adicionales. Dado que los segmentos pueden empezar en cualquier valor de 16 bits, hay veces en que los segmentos pueden superponerse en memoria. Lo que hace que el manejo del direccionamiento en el Intel 8086 se complique.
En todo caso, hablamos de un microprocesador diseñado en una época donde los ordenadores no ejecutaban más de una aplicación al mismo tiempo. Dado que el tener varios programas ejecutándose a la vez se convierte en un problema bajo este mismo planteamiento.
Bus de datos y direccionamiento multiplexado
El empaquetado del Intel 8086 es el clásico de 40 pines de la época, esto nos lleva a que necesitaríamos 20 pines para direcciones y otros 16 para datos, dejándonos sin pines para el resto de funciones del microprocesador. Esto le obligo a Intel a multiplexar los 16 primeros pines del bus de direcciones también para datos, 8 en el caso del 8088. Lo cual es uno de los mayores cuellos de botella para el chip.
¿Cómo sabe la CPU si ha de transportar datos o direcciones? Pues a través del pin 25, el cual si se encuentra activo transportará direcciones, en cambio, si no lo está el 8086/8088 transportará datos. No obstante, esta solución, pese a ahorrar en el número de pines, trae consigo un recorte en el rendimiento. Dado que las líneas tienen que cambiar de un tipo de información a otra (de direcciones a datos), los ciclos de bus son más largos en comparación con un bus no multiplexado, lo que puede reducir el rendimiento general del sistema.
Hay que tener en cuenta que el 8086/8088, al igual que el 8080, recordemos que es una evolución del mismo, por lo que tarda un mínimo de 4 ciclos para realizar un Fetch. A todo esto, hemos de añadirle el hecho que el modelo de memoria segmentada introduce una sobrecarga adicional, ya que cada acceso a memoria implica calcular la dirección física combinando un segmento y un desplazamiento, lo que requiere tiempo de procesamiento.
La unidad de Prefetch
Otra de las novedades del Intel 8086 respecto a otras CPU de la época es la unidad de Prefetch, básicamente funciona como una especie de caché primitiva de muy pequeño tamaño, ya que solo almacena los 6 bytes siguientes a la instrucción a la que apunta el contador de programa. De esta manera, y a no ser que la instrucción sea un salto o un bucle, el microprocesador ya tiene cargado el contenido de las siguientes direcciones de memoria.
En el caso de que se ejecute una instrucción de salto, sea del tipo que sea, entonces el contenido de toda la unidad de Prefetch se descarta, al quedar totalmente obsoleto y se llena de nuevo relativo a la nueva dirección de memoria. Si hablamos del Intel 8088, su unidad de prefetch se encuentra recortada a 4 bytes.
Acceso a memoria en el Intel 8086
Pese a que el bus se encuentra multiplexado, la cantidad de ciclos necesarios para realizar una operación a memoria, tengo lectura como escritura, se mantiene en 4. Por lo que pese a que el bus se encuentra multiplexado, no se traduce en un recorte del tiempo de acceso a la RAM.
En todo caso, hemos de tener en cuenta que esto afecta a la BIU que es la que accede a memoria, ya que la EU leerá, en teoría, desde la unidad de Prefetch. Lo cual ayuda a recortar el tiempo por instrucción. ¿El problema? Que los 6 bytes del Prefetch en muchos casos no se llegan a llenar a la suficiente velocidad y eso obliga a la Execution Unit a leer directamente de memoria a través de la BIU. Por lo que al final, el rendimiento variará dependiendo de donde se encuentre el dato, por eso se considera esto una versión primitiva y preliminar a la memoria caché
Adopción del microcódigo
Para entender mejor lo que es el microcódigo en una CPU tomemos la instrucción de sumar dos números. Si desglosamos su funcionamiento veremos que esta requiere de varios pasos para completarse:
- Calcular la dirección de memoria donde se encuentra el dato.
- Acceder al valor en memoria.
- Mover el valor desde la memoria RAM al registro acumulador de la ALU.
- Computar la suma.
- Almacenar el resultado en un registro.
La principal diferencia entre el Intel 8086 y el resto de CPU contemporáneas el uso de microcódigo interno para formar las diferentes instrucciones. Antes de eso, cada una de ellas estaba microcableada y los procesos en común que tenían las diferentes instrucciones repetidas se incluían en dicho diseño. Sin embargo, la idea del microcódigo no se la debemos a Intel, sino que fue una invención de Maurice Wilkes y data de 1951, solo que nuestro protagonista fue el primer microprocesador en implementarlo.
¿Su funcionamiento? Pues es sencillo, se almacena el microcódigo en una memoria especial llamada control store y lo único que se necesita para ejecutar una instrucción, es decir, las microinstrucciones que la componen. Por lo que la unidad de decodificación es mucho más compleja, ya que ha de convertir cada instrucción en microcódigo interno.
El coprocesador matemático: el 8087
El Intel 8086 estuvo disponible en versiones a 5 MHz, 8 MHz y 10 MHz, aunque se sabe que IBM adopto el 8088 a 4.77 MHz. No obstante, con las mejoras se sabe que un 8086 a 10 MHZ alcanza un rendimiento 10 veces superior a un 8080 a 2 MHz. Lo que se traduce en que el rendimiento del Intel 8086 es el doble por ciclo de reloj respecto al 8080.
Sin embargo, si hay algo que potenciaba aún más al 8086 fue el hecho de poder añadirle un coprocesador matemático, el llamado 8087, el cual fue presentado en 1980, dos años después del lanzamiento de la primera CPU de 16 bits de Intel. Se creó con el fin de acelerar cálculos aritméticos de coma flotante, lo cual era muy útil para aplicaciones de ingeniería, gráficos y ciencia que demandaban precisión matemática. Así pues, el 8087 añade versiones de las instrucciones aritméticas ya disponibles en el 8086, pero para los siguientes formatos de datos bajo el estándar del IEEE 754.
- 32 bits (coma flotante de precisión simple).
- 64 bits (coma flotante de doble precisión).
- 80 bits (coma flotante de precisión extendida).
Además, aparte de las instrucciones aritméticas simples: también añadió la capacidad de ejecutar aquellas que son más complejas:
- Raíces y potencias.
- Trigonométricas (senos, cosenos y tangentes)
En muchos menos ciclos que en el 8086 y lo mejor de todo es que el 8087 funcionaba en paralelo a la Execution Unit de la CPU principal, permitiendo ejecutar dichas instrucciones en paralelo, aumentando aún más su rendimiento.
La verdad del rendimiento del Intel 8086
El motivo por el cual hemos decidido separar a la CPU del IBM PC es por el hecho que buena parte de los problemas de rendimiento que se le achacan históricamente son más bien por un pésimo diseño de los PC de IBM que por deficiencias del microprocesador. Si bien está por debajo en rendimiento del 68000 de Motorola, lo cual es normal al tener la mitad de transistores, la realidad es que en los 80 se produjo una situación curiosa donde a finales de los 80 se seguían vendiendo ordenadores equipados con un 8086, incluso después del lanzamiento del 80386.
Tenemos casos como el Tandy 1000 de Radio Shack, la gama PC-98 de NEC en Japón. La cual uso chips licenciados a la Nippon Electric Company que eran algo más rápidos (entre un 5% y un 10%) e incluso llego a salir un modelo con la capacidad de ejecutar programas del 8080 de forma directa. Todos ellos proliferaron en la década de los 80 con buen rendimiento, es más, el problema para Intel era vender sus CPU más potentes por el hecho que el software se estancó en PC hasta la llegada de Windows 3.0.
Un Intel 8086 a 10 MHz es 10 veces más rápido que un 8080 a 2 MHz, esto significa que en comparación también frente al Z80 y sin cuellos de botella por el medio tiene el doble de potencia por ciclo de reloj.
Y con esto terminamos nuestro viaje por el 8086, ha sido más largo de lo que esperábamos, pero no queríamos dejarnos nada en el tintero.
Pingback: La crisis de Intel (I): ¿ha arruinado Pat Gelsinger su futuro?