Arquitectura CISC
En este artículo resumimos algunas de las características de la arquitectura CISC, así como los modos de direccionamiento y las instrucciones que se utilizan más frecuentemente.
Procesador
El procesador está formado por los registros, la unidad aritmética lógica (ALU) y la unidad de control (UC).
Registros del procesador
En la arquitectura CISC A tenemos 16 Registros para usos generales, desde R0 a R15 aunque el R15 se utiliza para realizar operaciones con la pila (PUSH, POP), para llamar funciones (CALL) o para devolver algún dato (RET).
Tenemos dos registros para acceder a las instrucciones son el contador del programa PC y el registro de la instrucción IR.
El registro PC se va autoincrementando, cuando se lee una instrucción el registro PC se incrementará en tantas unidades como byte, el valor de PCupdate apunta a la dirección siguiente de la secuencia.
Registro de acceso a memoria, el de datos MBR y el de direcciones MAR.
Con la ejecución de la mayoría de las instrucciones podemos modificar los bits de registro de estado:
Bit de cero: Z, se activa cuando el resultado es 0.
Bit de transporte o carry: C, se activa si el último bit produce transporte.
Bit de desbordamiento: V, se activa cuando se produce overflow.
Bit de signo: S, se activa si el resultado tiene signo negativo.
Bit para habilitar instrucciones: IE, activo permite interrupciones.
Bit de interrupción: IF, si activa cuando se solicita una interrupción.
Unidad aritmética lógica (ALU)
Se encarga de realizar las operaciones aritméticas y lógicas, utiliza los operandos X e Y del bus interno y devuelve los resultados en Z.
Unidad de control (UC)
Es la encargada de coordinar los componentes por medio de las señales de control.
Tenemos varios tipos de señales de control en dos grupos de entrada y de salida:
– Señales de entrada.
Temporización, registros de instrucción (IR), registro de estado, señales externas de la CPU.
– Señales de salida
Internas a la CPU, acceso a los buses internos, señales externas de la CPU.
Memoria Principal
Contamos con 2^32 posiciones de memoria de un byte (4GBytes). Para acceder a los datos lo haremos en palabras de 32 bits (4 bytes), están formateados en Little-Endian.
Para acceder a la posiciones de memoria, representaremos la posición con [],[posición de memoria].
Ejemplo
ADD [564645h],5
Añade 5 a la posición de memoria [564645h].
La pila
La pila tiene asignada una parte de la memoria principal (MP), exactamente desde la posición FFFF0000h a la posición FFFFFFFFh.
El registro SP -> R15 siempre apunta a la cima de la pila, cuando la pila crece (PUSH) aumentará hacia posiciones pequeñas. Si queremos incluir un dato en la pila, primero decreceremos el valor de SP que como hemos dicho antes siempre apunta a la cima y después incluiremos el dato en la pila. Si queremos sacar (POP) un dato de la pila lo haremos al revés, leeremos el dato que indica la cima de la pila y después incrementaremos el registro SP.
Si el valor de SP es 0 significará que no tenemos ningún dato almacenado en la pila, por lo tanto la pila estará vacía.
El primer dato se almacenará desde la posición FFFFFFFCh a la posición FFFFFFFFh y el registro SP apuntará a la dirección FFFFFFFCh, el segundo dato se almacenará desde la posición FFFFFFF8h a la posición FFFFFFFBh y SP apuntará a FFFFFFF8h, y así sucesivamente.
Instrucciones en la Arquitectura CISC
Las instrucciones en CISC pueden contener 0,1,2 operandos, aunque solo un operando de la instrucción podrá hacer referencia a la memoria.
Direccionamiento Inmediato
– Números decimal(10), número binario (1010b), numero hexadecimal (000Ah) , entre paréntesis.
– Etiquetas, variables “suma”
– Expresión aritmética.
Cuando utilizamos números en hexadecimal o binario se completa con ceros, en binario hasta 32 y en hexadecimal hasta 8, si queremos utilizar un número negativo tendremos que utilizar su valor en ca2, sin signo, extendiendo el número para que tenga signo negativo. Por ejemplo -10 seria FFFFFFF6h en hexadecimal en Complemento a 2.
Observación, cada 0000b en binario se pueden representar con un 0h en hexadecimal, puesto que el número máximo 1111b será 15 que en hexadecimal corresponde a F.
Direccionamiento a Registro
El operando se encuentra almacenado en un registro. Por ejemplo de R0 a R15.
Direccionamiento a memoria
Indicaremos utilizando corchetes [] que el dato se encuentra almacenado en una dirección de memoria. Le podemos pasar una dirección, una expresión o el nombre de una variable.
Cada posición de memoria es de 1 byte, sin embargo los Registros son de cuatro bytes, cuando direccionamos una posición de memoria a un Registro, enviará los 4 bytes, como si fuese la pila, es decir, MOV R1, [0000000Fh], moverá a R1 los valores almacenados desde 0000000Fh a 0000000Ch.
En el caso que sea una variable [variable], si utilizamos MOV R1, [variable] moverá los datos que contiene la variable a la posición R1.
Indirecto
Cargamos la dirección de memoria en la que está el operando, utilizamos los corchetes para indicar que el valor se encuentra en la posición de memoria que está entre corchetes.
Por ejemplo MOV R1, [nombrevariable] cargará el valor que tiene la variable en R1
“MOV R1, nombrevariable cargará la dirección y no el valor”
Direccionamiento Relativo.
El dato se encuentra almacenado en memoria y la pasaremos un expresión para hacer el dato relativo un registro + expresión, por ejemplo [R1+5], [R2+10], la última sería dirección de memoria R2+10 (xxxx+10= dirección de memoria xxxxxx).
Direccionamiento Indexado
El dato se encuentra almacenado en memoria y le pasaremos un Registro para hacer el dato indexado a la memoria + Registro, por ejemplo [000000AFh+R2], [variable+R1], cargaremos en el operando destino el valor del operando que se encuentra en la dirección de memoria indicada, por ejemplo [000000AFh+R2] o [variable+R1].
Direccionamiento Relativo a PC
Para utilizar este direccionamiento tenemos que hacerlo desde una instrucción de salto condicional (JE, JLE,…).
Direccionamiento a la pila
Para direccionar a la pila tenemos que utilizar las instrucciones PUSH o POP y lo hará como hemos explicado anteriormente en el apartado pila.
Instrucciones en la Arquitectura CISC
Mover datos:
mov destino, fuente
Introduce un dato en la cima de la pila:
push fuente:
Mueve el dato que hay encima de la pila al operador:
Pop destino:
Suma
add destino, fuente
Resta
sub destino, fuente
Incrementa
inc destino
Decrementa
dec destino
Multiplica sin tener en cuenta el signo
mul fuente
División entera sin signo
div fuente
Negación
neg destino
Comparación de dos operandos
cmp destino,fuente
Operaciones lógicas
and destino,fuente
or destino,fuente
xor destino,fuente
not destino (negación de cada bit)
Saltos
Salta a la etiqueta
jmp etiqueta
Salta a la etiqueta si el bit de cero está activo (jump equals)
je etiqueta
jne etiqueta (si no está activo)
Salta a la etiqueta si el bit de transporte está activo (jump carry)
jc etiqueta
jnc etiqueta (si no está activo)
Salta a la etiqueta si el bit de desbordamiento está activo (jump overflow)
jo etiqueta
Cambios de secuencia
Llamar a una subrutina
call etiqueta
Retorno de una subrutina
ret
Llamada al sistema operativo
int servicio
Codificar el código de la operación
Cuando codificamos las operaciones tenemos que poner el código de la instrucción en el byte x0-x1-xi, sucesivamente, utilizando los bytes que necesitemos. x0 será una dirección de memoria que ira aumentando dependiendo de los byte que necesitemos.
En las instrucciones con dos operandos solo un operando podrá hacer direccionamiento a memoria, para codificarlos pondremos el código de la operación y un operando seguido del otro.
El código de la instrucción estará representado por un número de 8 bits que se codifica en hexadecimal.
En el primer byte pondremos el código de la operación, se representara en hexadecimal de dos cifras, por ejemplo 0Ah.
Después codificaremos el modo de direccionamiento, si no está escrito directamente para esto necesitaremos 1,3 o 5 bytes dependiendo del modo de direccionamiento.
Inmediato 0h
Registro 1h
Memoria (directo) 2h
Indirecto 3h
Relativo 4h
Indexado 5h
Relativo a PC 6h
Ejemplos de algunas instrucciones en código máquina.
PUSH R12 se codificaría como: 11 1C
El primer 11 sería la instrucción PUSH, 1 correspondería al direccionamiento y C sería el número de Registro.
ADD [223344F7h + R1], -2 se codificará como: 20 51 F7 44 33 22 00 FE FF FF FF
El 20 corresponde a la instrucción ADD, 5 al modo de direccionamiento 1 al registro, desde F7 a 22 corresponde a la posición de memoria. Ahora el otro operando, -2 empezaría con 0 el modo de direccionamiento y el número de registro o cero si no utiliza ningún registro, como -2 no utiliza ningún registro pondremos otro 0, es decir 00, por último desde FE (-2) hasta el último FF sería el número -2 en Ca2 en hexadecimal.