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.
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.
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.
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.
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.
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
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 ( 2.5).
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" ( 5.1).
- Segmento de código CS ("Code segment"). Señala la dirección del segmento de código del programa que se está ejecutando ( E1.3.2).
- Segmento de datos DS ("Data segment"). Señala la dirección del segmento de datos del programa en ejecución (E1.3.2).
- Segmento de pila SS ("Stack segment"). Señala la dirección del segmento donde está la pila del programa ( E1.3.2).
- 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 (ver figura 5.1 Fig.2)
- 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.
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:
Bit
|
Indicador de:
|
Uso
|
CF
| Acarreo ("Carry Flag") | Indicador de arrastre del bit de mayor orden, que puede ocurrir en las operaciones aritméticas suma y resta. |
PF
| Paridad ("Parity Flag") | Si está activo Indica un número par de bits activos (bits cuyo contenido es 1). Esta información es útil cuando el procesador controla transmisiones de datos. |
AF
| Acarreo auxiliar | Indicador de ajuste en operaciones aritméticas con cantidades BCD ( E0.1w1). |
ZF
| Cero ("Zero Flag") | Está activo si el resultado de operación es cero o resultado de comparación igual. |
SF
| Signo ("Sign Flag") | Si está activo indica que el resultado de operación o de comparación son negativos [5]. |
TF
| Detención ("Trap Flag") | Si está activo, el procesador genera automáticamente una interrupción después de la ejecución de cada instrucción, lo que permite controlar paso a paso la ejecución del programa. Este bit debe estar normalmente inactivo (a 0). |
IF
| Interrupción ("Interrupt Flag") | Este bit controla el estado del sistema de interrupciones enmascarables ( 2.4). Cuando está activo (1) permite las interrupciones; el estado inactivo (0) las deshabilita. |
DF
| Dirección ("Direction Flag") | Indica la dirección de las operaciones. |
OF
| Desbordamiento (Overflow Flag") | Señala desbordamiento aritmético |
Nota: Los usuarios de MS-DOS o Windows puede usar el programa DEBUG ( 1.7.1) 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
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:
Bit
|
Indicador de:
|
Indicativo si bit 1
|
Indicativo si bit 0
|
CF
| Acarreo | CY ("Carry yes") | NC ("No Carry") |
PF
| Paridad | PE ("Parity Even") paridad par | PO ("Parity Odd") paridad impar |
AF
| Acarreo auxiliar | AC ("Auxiliar Carry") | NA ("No Auxiliar") |
ZF
| Cero | ZR ("Zero") | NZ ("No Zero") |
SF
| Signo | NG ("Negative") negativo | PL ("Plus") positivo |
IF
| Interrupción | EI ("Enabled Interrupt") activa | DI ("Disabled Interrupt") desactivada |
DF
| Dirección | DN ("Down") decremento | UP incremento |
OF
| Desbordamiento | OV ("Overflow") | NV ("No overflow") |
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.
§3.1.5 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).
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 ( 3) 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 denominadoscoprocesadores 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 ( E4.9.1), las operaciones trascendentes están implementadas mediante funciones de la Librería Estándar ( 5), 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 ( E4.9.8).
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 comomicrocódigo. Es un programa de actuación cableado en silicio (firmware) o en una memoria interna especial del procesadorCROM ("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 decodificador de 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 mem