Arquitectura
del Procesador
Sinopsis
El procesador es todo un mundo en
sí mismo; aunque los primeros eran comparativamente simples, actualmente
han alcanzado una notable complejidad. En el presente capítulo
dedicaremos algunos comentarios a su estructura lógica, mencionando de pasada
que su tecnología física ha avanzado paralelamente con la de construcción de
circuitos integrados,IC's, lo que a la postre ha significado unas
dimensiones físicas cada vez más pequeñas y un menor consumo.
La evolución de ambos parámetros
no solo ha permitido incrementar la densidad de integración, también la
velocidad (frecuencia de funcionamiento). Si nos referimos a la familia
Intel, de los 2.100 transistores del 4004 en
1970, que con solo 46 instrucciones funcionaba a unos 800 KHz, se pasó a los
29.000 transistores del 8086 en
1979 a 14 MHz; y en 1999 a los 8.200.000 transistores del Pentium III a 2 GHz.
Nota: acabo de leer (Noviembre
2001) que Intel anuncia la nueva tecnología de 0.13 micras para su serie Pentium 4(hasta ahora era de 0.18 micras), con
la que se espera que a fines de 2002 se alcancen los 3 GHz. en estos
procesadores. Un poco después (Enero 2002) leo que Intel espera alcanzar
1.2 THz en sus procesadores para el 2005 (escribo esto en un Pentium II a 200
MHz no demasiado antiguo).
En Abril del 2002 Intel anuncia el procesador Pentium 4 con tecnología CMOS de 0,16 micras a 2.4 GHz y mejoras en el proceso de fabricación que permiten su fabricación en obleas de 300 mm. Esta tecnología permite al fabricante proporcionar más de cinco veces el volumen de productos en una sola oblea en comparación con la del procesador Pentium 4 inicial.
En Junio del mismo año Intel desvela su nueva tecnología de fabricación de transistores "Tera-Herz", con la que pretende que en el 2005 pueda alcanzar los 10 GHz. Craig Barret, CEO [7] de la compañía, afirma que en un futuro no lejano esperan conseguir 2.000 millones de transistores en un procesador a 30 GHz.
En Abril del 2002 Intel anuncia el procesador Pentium 4 con tecnología CMOS de 0,16 micras a 2.4 GHz y mejoras en el proceso de fabricación que permiten su fabricación en obleas de 300 mm. Esta tecnología permite al fabricante proporcionar más de cinco veces el volumen de productos en una sola oblea en comparación con la del procesador Pentium 4 inicial.
En Junio del mismo año Intel desvela su nueva tecnología de fabricación de transistores "Tera-Herz", con la que pretende que en el 2005 pueda alcanzar los 10 GHz. Craig Barret, CEO [7] de la compañía, afirma que en un futuro no lejano esperan conseguir 2.000 millones de transistores en un procesador a 30 GHz.
Actualmente se trabaja en el
límite de la resolución óptica de los dispositivos utilizados en su
construcción (se usan técnicas fotográficas con longitudes de onda cada vez
menores para la luz utilizada), y debido a la altísima frecuencia de
funcionamiento, los conductores internos funcionan más como guías de onda que
como conductores eléctricos convencionales. Además, las dimensiones
físicas del propio dispositivo están teóricamente limitadas si se desea que
todos sus elementos funcionen según un mismo patrón de tiempo (cosa que es
imprescindible). Para dar una idea de las formidables dificultades
técnicas que han debido resolver los diseños actuales, considere que a la
velocidad del Pentium III, las señales eléctricas solo recorren 15 centímetros
en cada ciclo de reloj.
Tipos de arquitectura
Una de las primeras decisiones a
la hora de diseñar un procesador es decidir cual será su juego de
instrucciones. Este conjunto de instrucciones (órdenes) es el lenguaje
que realmente entiende el procesador, y constituye lo que se conoce como lenguaje ensamblador o lenguaje-máquina [1].
La decisión es trascendente, por
dos razones. Primero: el juego de instrucciones decide el diseño físico
del conjunto. Segundo: cualquier operación que deba ejecutarse con el
procesador deberá poder ser descrita en términos de este "lenguaje"
elemental (recuerde que los compiladores e intérpretes son en realidad
traductores desde el lenguaje de alto nivel (fuente) a este lenguaje-máquina.
Sin entrar en detalles, podemos
decir que frente a esta cuestión caben dos filosofías de diseño. La
primera conduce a máquinas denominadas CISC ("Complex
Instruction Set Computer"); las máquinas construidas según el otro
criterio se denominan RISC ("Reduced Instruction Set
Computer").
Como puede deducirse de sus
propios nombres, las máquinas CISC utilizan instrucciones muy
complejas, diríamos que muy descriptivas y específicas, lo que necesariamente
se traduce en varias consecuencias:
- El lenguaje debe contener un amplio surtido de
ellas (una para cada circunstancia distinta).
- Son instrucciones complejas, por tanto de
ejecución lenta. La circuitería del procesador también es compleja.
- Para un trabajo específico se requieren pocas
instrucciones (siempre hay una que resuelve el problema).
Las máquinas RISC representan
el enfoque opuesto. Utilizan instrucciones muy simples, que deben ser
cuidadosamente escogidas, porque cualquier operación debe ser expresada como
una secuencia de estas pocas instrucciones. Las consecuencias son
justamente opuestas a las anteriores:
- El lenguaje contiene un conjunto pequeño de
instrucciones.
- Las instrucciones son muy simples, por tanto
de ejecución rápida. La circuitería es más simple que en los
procesadores CISC.
- Para cualquier operación se requieren varias
instrucciones elementales.
Naturalmente cada criterio tiene
sus pros y su contra en lo que a rendimiento se refiere. En las máquinas CISC,
lentitud de cada instrucción frente a poca cantidad de ellas; en las RISC,
rapidez individual aunque hay que ejecutar un mayor número [2].
Componentes principales.
De forma esquemática podemos
suponer que un procesador se compone de cinco elementos:
- Memoria
- Unidad Artimético-Lógica ALU ("Arithmetic
and Logic Unit" )
- Unidad de Control CU ("Control
Unit" )
- Bus interno
- Conexiones con el exterior ( 3.2.1)
Puesto que su conocimiento es
esencial para la programación en ensamblador, nos detendremos brevemente la
descripción de la arquitectura del 8088;
además de ser el motor del primer PC, es uno de los primeros ejemplares de una
prolífica saga que ha tenido una gran influencia en la informática
actual. Además recordemos que incluso los modernos Pentium pueden emular
el funcionamiento en modo real de sus ancestros.
En le figura
1 se muestran sus elementos.
El procesador necesita para su
funcionamiento de ciertas áreas de almacenamiento, que aquí se llaman registros,
y que son de dimensiones mínimas [3];
sin embargo, tienen la ventaja de su rapidez. Comparados con los accesos
a RAM, los de registro son como mínimo 10 veces más veloces.
El 8088 dispone de catorce registros de 16 bits que se agrupan
en cuatro grupos y que reciben nombres especiales (precisamente los que se
utilizan para designarlos en lenguaje ensamblador).
Existen 4 registros denominados AX, BX, CX y DX que
en realidad tienen asignados usos característicos, aunque pueden ser utilizados
a discreción para cualquier cosa que necesitemos.
- AX es denominado acumulador;
suele contener uno de los operandos que intervienen en las operaciones
aritméticas y lógicas, y después de esta, el resultado de la
operación. En general las instrucciones que trabajan con este
registro (o su mitad inferior) tienen un microcódigo más simple que la misma
instrucción ejecutada con otro registro.
- BX es el registro base, suele
contener la dirección de inicio de una tabla de valores.
- CX es denominado contador.
Las instrucciones de bucle (LOOP) utilizan este registro como contador.
- DX es un registro de datos,
multiuso. Se utiliza en operaciones de multiplicación y división
junto con AX. En operaciones de entrada/salida de
puertos IN/OUT, su mitad inferior DL, contiene el número de
puerto
- Aunque estos cuatro
registros son de 16 bits (como los 10 restantes) [6],
en caso necesario pueden ser utilizados en dos mitades (nibbles), "High"
y "Low", de 8 bits, con lo que puede considerarse que
existen 12 registros de uso general (no simultáneos), los anteriores y sus
mitades: AH; AL; BH; BL; CH; CL; DH y DL.
Se dispone de cuatro registros
que sirven para contener las direcciones de otros tantos segmentos (zonas de 64
KB de memoria). Utilizándolos en conjunción con otros registros que
señalan las direcciones concretas dentro de estos segmentos (los desplazamientos), permiten manejar la totalidad de
la memoria direccionable (el bus de direcciones es de 20 bits). Ver al
respecto el epígrafe "Direccionamiento segmentado" .
- Segmento de código CS ("Code
segment"). Señala la dirección del segmento de código del programa
que se está ejecutando
- Segmento de datos DS ("Data
segment"). Señala la dirección del segmento de datos del
programa en ejecución
- Segmento de pila SS ("Stack
segment"). Señala la dirección del segmento donde está la pila
del programa
- Segmento extra ES ("Extra
segment"). Es un segmento auxiliar a los anteriores, se utiliza
para señalar espacio extra en alguno de los segmentos o para almacenar
momentáneamente direcciones intermedias.
Nota: Puede ocurrir que
programas pequeños utilicen el mismo segmento para el código, los datos y la
pila.
Son 5 registros destinados a
contener direcciones; estas direcciones son desplazamientos dentro de los
segmentos indicados por los registros de segmento
El primero, denominado
indistintamente puntero de instrucción IP ("Instrucción
pointer") y contador de programa PC("Program
counter"), indica el desplazamiento (dentro del segmento de código CS)
de la próxima instrucción a ejecutar.
- El puntero de pila SP ("Stack
Pointer"), señala el desplazamiento del final de la pila dentro del
segmento de pila SS. En caso necesario la pila puede
crecer a partir de este punto, de forma que por ejemplo, una nueva
invocación de función creará un nuevo registro de activación que comenzará
en este punto.
- El puntero base BP ("Base
pointer") señala el desplazamiento (dentro del segmento de pila SS)
donde se encuentra el origen de la zona ocupada por las variables
dinámicas.
- Existen dos registros denominados "de
índice", en razón de su utilización muy particular; el índice
fuente SI ("Source index") y el índice destino
DI ("Destination index"). Generalmente estos dos
registros se utilizan con alguno de los registros de uso general y con
ciertas instrucciones específicamente pensadas para transferir datos
(dentro de un rango de posiciones de memoria), desde un punto inicial de
un segmento de datos, a otro.
Registro de estado
Existe un registro especial, el registro
de estado (FLAGS), en el que 9 de los 18 bits actúan como
semáforos (indicadores del estado del procesador y del resultado de
determinadas operaciones). Por ejemplo, si después de una suma aritmética
hay o no desbordamiento del bit más significativo.
Los nombres y situación de cada
uno, dentro de la palabra de 16 bits, se muestran en la figura 2.
Cada bits individual puede estar
"activo" (1) o "inactivo" (0), y tiene un identificador que
termina en F("Flag"). Son los siguientes:
Nota: Los usuarios
de MS-DOS o Windows puede usar el programa DEBUG para inspeccionar y modificar
el contenido de los registros de la siguiente forma:
·
Invocar
DEBUG desde una ventana DOS (suponemos que estamos en Windows; el
"prompt" es un guión "-")
·
introducir
el comando R
(pedimos que nos muestre el contenido de los registros).
·
Salir
de Debug con Q
En
mi PC la respuesta al comando tiene el siguiente aspecto:
AX=0000 BX=0000 CX=0000
DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1779 ES=1779 SS=1779 CS=1779 IP=0100 NV UP EI PL NZ NA PO NC
DS=1779 ES=1779 SS=1779 CS=1779 IP=0100 NV UP EI PL NZ NA PO NC
Los
valores están expresados en hexadecimal. La última secuencia de
caracteres (
NV
UP EI PL NZ NA PO NC
) muestra el contenido del registro de estado (el bit TF de detención no se muestra), el
significado de la notación utilizada es el siguiente:
También es posible
inspeccionar el contenido de un solo registro, añadiendo al comando R el nombre del registro. Por
ejemplo, el comando R IP muestra el contenido del contador de
programa. Los nombres que pueden utilizarse para los registros son los
siguientes: AX; BX; CX; DX; SP; BP;
SI; DI; DS; ES; SS; CS; IP y F (este último
para el registro de estado).
Después
de un comando de este tipo, DEBUG responde con un "prompt" distinto
del habitual ":", para
indicar que debe introducir el nuevo valor que desea para el registro.
Pulsando INTRO se vuelve al modo normal.
Comentario
Observe
que tanto el registro contador de programa IP,
como el de base BP,
siempre contienen direcciones de memoria (los otros pueden contener direcciones
o datos). Ni los registros de segmento ni los de puntero se pueden
dividir en mitades (como los de uso general).
Unidad Aritmético-lógica
Como
su propio nombre indica, la unidad Aritmético-Lógica ALU ("Arithmetic and Logic
Unit"), es responsable de realizar ciertas operaciones aritméticas y
lógicas.
En
cuanto a las primeras, ya hemos indicado que los primeros procesadores solo
eran capaces de realizar operaciones de aritmética básica con números enteros,
y que las operaciones con números fraccionarios debían hacerse mediante
artificios software. Esto había motivado la aparición de procesadores
específicos para estas operaciones, los denominados coprocesadores
matemáticos. A partir de la introducción del Intel 80486 el
coprocesador matemático fue incluido en el procesador.
La unidad aritmética de los procesadores actuales no
solo puede realizar las operaciones aritméticas básicas con números enteros o
fraccionarios, también ejecuta operaciones como raíz cuadrada y funciones
trascendentes, como cálculo del seno, coseno, tangente, arcotangente, logaritmos
y exponenciación.
Nota: En C++ los
operadores aritméticos están incluidos en el lenguaje , las operaciones
trascendentes están implementadas mediante funciones de la Librería Estándar ,
en la que existe toda una sección dedicada a estas operaciones <math.h>.
Por
su parte, la unidad lógica es la responsable de realizar
operaciones lógicas como AND, OR, XOR, etc…
Unidad de Control
La
Unidad de Control CU ("Control Unit") funciona
como árbitro del funcionamiento del procesador. Se encarga de coordinar
que todos los elementos funcionen de forma armónica.
Para
la ejecución de una instrucción de lenguaje máquina se requieren una serie de
operaciones elementales y de sucesos físicos en los diversos componentes del
procesador. Podríamos poner un ejemplo: El procesador es un
submarino en inmersión y el comandante da la orden de emerger. Esto
requiere una serie de operaciones; los tripulantes deben abrir unas válvulas,
cerrar otras; orientar el timón de profundidad; ajustar la velocidad, etc.
etc. En el procesador, la operación MOV AX, BX (mover el contenido del
registro BX a AX), requiere también la operación de una serie de válvulas (aquí
se llaman puertas lógicas) en un orden determinado. El conjunto de
operaciones necesarias para que se complete cada instrucción de
lenguaje-máquina se conoce como microcódigo.
Es un programa de actuación cableado en silicio (firmware) o en una memoria
interna especial del procesador CROM ("Control Read Only Memory), y
suele comenzar con las maniobras necesarias para traer ("Fetch") la
próxima instrucción (señalada por el contador de programa IP), a un módulo de la CU denominado decodificadorde
instrucciones. La Unidad
de Control, responsable de que todas estas operaciones se ejecuten
correctamente, es en realidad el poder ejecutivo de la UCP (siguiendo con
nuestro símil, en las máquinas de von Neumann [4],
el "Poder legislativo" sería el programa grabado en memoria).
Nota: Algunos
microprocesadores modernos (por ejemplo los Pentium de Intel), permiten
modificar el contenido de la CROM, alterando así el microcódigo. Esto no
solo permite actualizarlo, también corregir ocasionalmente algunos errores
("Bugs"); estas actualizaciones se realizan a través de la secuencia
POST del BIOS. En la terminología utilizada por los fabricantes de
procesadores, las versiones del microcódigo se denominan escalamientos. Al
referirse al microcódigo, el número de escalamiento es equivalente al número de
versión en el caso del software.
Como
todo lo demás que ocurre en el ordenador estas operaciones se ejecutan según el
compás de las señales de reloj que llegan desde la placa-base. En
ocasiones se trata de un microcódigo complicado, para el que se necesitan
varios ciclos de reloj. Por ejemplo, en el 8080 (un antepasado del 8088 montado en los primeros PC's), el
microcódigo de las instrucciones más complejas necesitaba nada menos que 18
ciclos de reloj (CLK) para su ejecución, frente a los 4 ciclos de las
instrucciones más rápidas.
Aunque
el microcódigo se mejora constantemente, su simplificación tiene un límite, que
marca el rendimiento del procesador. Las únicas formas de acelerarlo es
aumentar la frecuencia del reloj y el procesamiento paralelo y simultaneo de
varias instrucciones. Esta última capacidad requiere una arquitectura
especial (súper escalar) de los procesadores, a la que ya nos hemos referido.
El
bus interno
Los
diversos elementos de un microprocesador están interconectadas de forma muy
compleja (el propio micro lo és), de forma que la imagen de la figura 1 es solo una simplificación
conceptual. En realidad existen varios buses principales, cuya anchura
que es dos a cuatro veces la del bus externo ( H2)
de los PC's, y muchos más secundarios.
En
la figura adjunta se muestra un esquema de la arquitectura interna de un
procesador de la familia Pentium de Intel ( Arq. Pentium)
en la que puede apreciarse su complejidad.
El lenguaje del procesador
Hemos
señalado que el lenguaje que entiende el procesador es lenguaje-máquina, pero
ráramente se emplea como tal, se utiliza un lenguaje de un poco más alto nivel, ensamblador o macro-ensamblador.
Cada modelo de procesador tiene su propio lenguaje-máquina y necesita su propio
ensamblador, pero todos los miembros de la saga Intel x86 (incluídos los
actuales Pentium) comparten un núcleo que proviene de su ancestro el 8086.
Desde
luego este tutorial "Tecnología del PC", no trata sobre programación
en assembler (que además no es mi especialidad), pero como algunos me han
escrito solicitando información al respecto, incluyo algunas referencias donde
puede encontrarse información acerca de la programación en ensamblador y donde
conseguir macroensambladores.