Sean las siguientes instrucciones:
a) ADD $t0, $t1, $t2 b) ADDI $s0,$s1, 0x0011 c) ORI $t0, $t2, 0x00A1 d) SLL $t0, $t0, 0x0002 e) SRL $t1, $t0, 0x0002 | f) LUI $s0,0x0011 g) SW $t4, 0x0111 h) SLT $t1, $t2, $t0 i) J 0x000001A j) JR $S0 |
Para codificar las instrucciones en hexadecimal, es necesario saber las tablas de equivalencia de las diferentes instrucciones de MIPS. Cada instrucción se codifica en base a su propia tabla específica que combina su código de instrucción con los diferentes registros, y el número de bits necesarios para su codificación.
ADD $t0, $t1, $t2
Así pues, para la primera instrucción, tendremos la siguiente tabla:
A continuación debemos poner los registros en sus correspondientes celdas, teniendo en cuenta que la instrucción es:
Una vez claro lo anterior, debemos tener en cuenta la codificación en hexadecimal de cada uno de los registros, que lo podemos mirar en la siguiente tabla:
Los registros con puntos suspensivos, por ejemplo t0…t7 – 8…15, se refiere a que los registros intermedios tienen números correlativos entre el 8 y el 15.
Una vez que ya sabemos el código de los registros utilizados en la operación, podemos proceder a codificar la instrucción, según el número de bits antes citado, primero en decimal, luego en binario, y por último, agrupando los números de 4 en 4, en hexadecimal.
El número 0x20, está en hexadecimal y no en decimal, así que tenemos que pasarlo a decimal para mayor comodidad al convertirlo a binario.
El número 0x20, está en hexadecimal y no en decimal, así que tenemos que pasarlo a decimal para mayor comodidad al convertirlo a binario.
0 | 9 ($t1) | 10 ($t2) | 8 ($t0) | 0 | 32 (0x20) |
000000 | 01001 | 01010 | 01000 | 00000 | 100000 |
Una vez codificado en binario, tenemos que agrupar los números de 4 en 4 bits de la siguiente manera:
0000 – 0001 – 0010 – 1010 – 0100 - 0000 – 0010 – 0000
Ahora para pasarlo a hexadecimal, tenemos que pasar cada grupo de cuatro a decimal, teniendo en cuenta que a partir del 10, serían A, B, C... hasta F. Por tanto la codificación en memoria de la instrucción en hexadecimal, sería la siguiente: 0x012A4020
Las siguientes instrucciones se codifican de la misma forma, pero en base a las diferentes tablas de cada instrucción, escritas más abajo:
ADDI $s0, $s1, 0x0011
El addi se realiza exactamente igual que el anterior, pero con la única diferencia, de que los últimos 16 bits, son para el inmediato, en lugar de para Rd, el 0 y el 0x20, y que en este caso es 0x0011. El resultado de la codificación es: 0x22300001
ORI $t0, $t2, 0x00A1
Esta instrucción se codifica igual que el addi pero cambiando el código de la instrucción, que es 0xD en lugar de 8. El resultado de la codificación es: 0x354800A1
SLL $t0, $t0, 0x0002
En este caso, Rs no existe en la instrucción, por tanto, seria 00000. El resultado es: 0x00084080.
SRL $t1, $t0, 0x0002
El SRL, al igual que SLL, no tiene Rs, por tanto, ese espacio se rellena con 00000. La instrucción codificada es: 0x00084882
LUI $s0, 0x0011
Esta instrucción carga los 16 bits de la parte baja del valor inmediato en la parte alta del registro. Los bits de la parte baja se ponen a 0. Rt sería $s0 y el inmediato sería 0x0011. La codificación sería: 0x3C100011
SW $t4, 0x0111
En esta instrucción no existe Rs, por tanto se rellena de ceros (00000). El offset sería la dirección, es decir, 0x0111. La codificación sería: 0xAC0C0111.
SLT $t1, $t2, $t3
Esta instrucción se codifica igual que la instrucción ADD (ya que la tabla es muy similar). La codificación sería: 0x014B482A.
J 0x000001A
Esta instrucción es la más fácil. Solo hay que poner la dirección 0x000001A en binario en los 26 bits restantes de poner el código de operación que es 2. La codificación sería: 0x0800001A.
JR $s0
En esta instrucción, al igual que la anterior, solo habría que colocar $s0 en rs. El resultado sería: 0x02000008.
2. Utilizando la CPU descrita en clase teórica y el lenguaje de transferencia de registro, realizar la secuencia de transferencias y acciones.
La secuencia de transferencia de registros, se hace en tres pasos, que corresponden con las tres fases de ejecución de una instrucción, y observando el esquema anterior para así poder saber qué debemos hacer y qué señales tendremos que activar. Las diferentes secuencias que se realizan se indican con C1, C2, C3... Así de C1 a C3, corresponden con la fase de lectura de instrucciones que es igual en todas las instrucciones, la C4 con la fase de decodificación y las demás con la de ejecución.
Pasemos pues a explicar lo que significa lo que hay en cada secuencia de transferencia:
· MAR es un registro que permite a la CPU comunicarse con la memoria y los dispositivos externos, al igual que MBR.
· PC es el registro encargado de almacenar la dirección de memoria a la que se está accediendo.
· MP corresponde con la memoria principal, que permite almacenar programas y datos.
· RI es el registro de instrucciones que almacena la instrucción a ejecutar.
C1: MAR ß PC | Lleva la dirección de memoria a la que se accede al registro MAR |
C2: PC ß PC + 4 | Incrementa la dirección de memoria en 4 unidades, como se observa en el esquema. |
C2: MBR ß MP | Carga en MBR lo contenido en la memoria principal. |
C3: RI ß MBR | Carga los datos del registro MBR en el registro de instrucciones para poder operar con ellos. |
C4: Decodificación | Corresponde con la segunda fase de ejecución de una instrucción. Este ciclo permite que la unidad de control realice la ejecución de la secuencia de señales de control que den lugar a la instrucción. |
C5: R8 ($t0)=R9($t1)+R10($t2) | Esta línea se encarga de realizar la operación. R8, R9 y R10 se refiere a los registros sacados del banco de registros del esquema. La equivalencia es la misma que en el ejercicio 1. |
Como las secuencias de C1 a C4 son siempre igual, sólo se pondrá la secuencia de C5 en adelante.
ADDI $s0, $s1, 0x0011
C5: RT1 ß MBR | Se guarda en el registro temporal RT1 el inmediato, encontrado en MBR. |
C6: R16($s0)=R17($s1)+RT1(0x0011) | Esta línea se encarga de realizar la operación, guardando el resultado en el registro $s0, la suma de $s1 con el inmediato. R16 y R17 se sacan del banco de registros del esquema. |
ORI $t0, $t2, 0x00A1
C5: RT1 ß MBR | Se guarda en el registro temporal RT1 el inmediato, encontrado en MBR. |
C6: R8 ($t0)=R10($t2)OR RT1(0x00A1) | Esta línea se encarga de realizar la operación, guardando el resultado en el registro $t0 el resultado de la operación R10 OR RT1 |
SLL $t0, $t0, 0x0002
C5: RT1 ß MBR | Se guarda en el registro temporal RT1 el inmediato, encontrado en MBR. |
C6: R8($t0) = Desplazado.Izq(R8($t0),RT1(=0x0002)) | Esta línea se encarga de realizar la operación, guardando el resultado en el registro $t0 de desplazar a la izquierda el propio registro 0x0002. |
SRL $t1, $t0, 0x0002
C5: RT1 ß MBR | Se guarda en el registro temporal RT1 el inmediato, encontrado en MBR. |
C6: R9($t1) = Despl. Der.(R8($t0),RT1(=0x0002)) | Esta línea se encarga de realizar la operación, guardando el resultado en el registro $t1 de desplazar a la derecha el número 0x0002 a $t0. |
LUI $s0, 0x0011
C5: RT1 ß MBR | Se guarda en el registro temporal RT1 el inmediato, encontrado en MBR. |
C6: | Esta línea se encarga de realizar la operación. |
SW $t4, 0x0111
C5: MAR ß RI | Se guarda en el registro temporal RT1 el inmediato, encontrado en MBR. |
C6: MBR ß R12($t4) | Esta línea guarda el registro 12 del banco de registros, en MBR. |
C7: MP ßMBR | Lleva el registro MBR a la memoria principal. |
3. Comprobar que todo lo anterior se ha realizado de forma correcta mediante el simulador que se adjunta para la práctica. Se introducirá el código de instrucción en la memoria de manera que sean posible realizar todas las fases de la instrucción.
Para realizar este ejercicio, debemos saber las señales que se activan en el circuito de la práctica. Dicho circuito nos lo dan para poder realizar lo pedido. El programa que utilizaremos para visualizar el circuito es el logisim-win2.7.1. Se adjunta la imagen del circuito a continuación:
Lo más cómodo es ir mirando la siguiente imagen para saber que señales debemos de activar y así poder ir siguiendo los pasos en Logisim:
Debemos tener en cuenta que los triestados no pueden estar activados ya que cuando se activa un triestado hay que desactivar los demás para que no se produzcan errores.
ADD $t0, $t1, $t2
Señales que se activan | |
C1: MARß PC | T4 = 1 C1 = 1 |
C2: PC ß PC + 4 | C1 = 0 TD = 1 Sel = 1 L = 1 C4 = 1 C4 = 0 |
C2: MBR ß MP | C2 = 1 C2 = 0 |
C3: RI ß MBR | T4 = 0 T3 = 1 C7 = 1 C7 = 0 |
C4: Decodificación | Ninguna |
C5: R8 ($t0)=R9($t1)+R10($t2) |
Lo primero que debemos hacer al abrir el circuito en el Logisim es fijarnos donde está cada cosa que vamos a necesitar. Tras esto, seleccionamos el botón de la mano marrón (situado en la esquina superior izquierda) para poder comenzar a realizar la simulación. Luego, empezamos activando las señales antes indicadas una detrás de otra pinchando en el botón cuadrado correspondiente de cada señal. Así si T4 = 1 pincharemos en dicho recuadro para poner el “1” y pinchando de nuevo ponemos un “0”. Las señales de la secuencia desde C1 a C4 se activan siempre igual para todas las instrucciones.
Debemos tener en cuenta que la ALU sólo tiene implementadas en el circuito las siguientes funciones:
- 00001 Suma
- 00002 Resta
- 00003 OR
- 00004 AND
- 00005 Desplazamiento a la derecha de 1,2,3,4 bits
- 00006 Desplazamiento a la izquierda de 1,2,3,4 bits
- 00007 NOT
- 00008 XOR
Por lo tanto, sólo podremos usar esas funciones, poniendo los números de cada función en binario. Así si queremos realizar un AND, pondríamos en el “Código de operación” el valor 00100. También debemos tener en cuenta que el acceso a la memoria solo se realiza en formato Word (32 bits). Las direcciones se visualizan como bloque de 4 bytes:
00000000 representan las direcciones 00000000-00000003
00000001 representan las direcciones 00000004-00000007
00000002 representan las direcciones 00000008-0000000B
Para que se inicie el programa la memoria debe estar activada: Sel = 1, en modo lectura L=1 y el triestado que conecta el bus de direcciones con el registro MAR abierto TD=1. La señal “Sel” se encuentra arriba del circuito (y es la primera empezando por la izquierda) y es como se muestra en la imagen siguiente, y la señal “L” es la tercera empezando por la izquierda:
Para reiniciar todo el sistema se cuenta con una entrada de RESET general.
ADDI $s0, $s1, 0x0011
Señales que se activan | |
C1: MAR ß PC | T4 = 1 C1 = 1 |
C2: PC ß PC + 4 | C1 = 0 TD = 1 Sel = 1 L = 1 C4 = 1 C4 = 0 |
C2: MBR ß MP | C2 = 1 C2 = 0 |
C3: RI ßMBR | T4 = 0 T3 = 1 C7 = 1 C7 = 0 |
C4: Decodificación | Ninguna |
C6: R16($s0)=R17($s1)+RT1(0x0011) | RA = 10000 ($s0) RB = 10001 ($s1) MA = 0 MB = 0 T3 = 0 T8 = 1 C10 = 1 C10 = 0 T8 = 0 MB = 1 C. Op = 000001 T5 = 1 RC = 16(10 = 10000 SC = 1 y SC = 0 |
ORI $t0, $t2, 0x00A1
Como las señales que se activan en la secuencia de C1 a C4 son siempre igual en todas las instrucciones, no las ponemos. Por ello a partir de ahora, sólo vamos a ir poniendo las secuencias de C5 en adelante.
Señales que se activan | |
C5: RT1 ß MBR | E = 0 TD = 0 TA = 0 T1 = 0 T3 = 0 T4 = 1 C1 = 1 y luego C1 = 0 TD = 1 Sel = 1 y L = 1 T4 = 0 T3 = 1 C7 = 1 y C7 = 0 C9 = 1 y C9 = 0 |
C6: R8 ($t0)= R10($t2) OR RT1(0x00A1) | RA = 01000 MA = 0 y MB = 0 C.Op = 00011 (OR) T8 = 0 T1 = 1 C3 = 1 y C3 = 0 TA = 1 E = 1 |
SLL $t0, $t0, 0x0002
Señales que se activan | |
C5: RT1ß MBR | T5 = 0 T4 = 1 C1 = 1 y luego C1 = 0 TD = 1 Sel = 1 y L = 1 T4 = 0 T3 = 1 C7 = 1 y C7 = 0 |
C6: R8($t0) = Desplazado.Izq(R8($t0),RT1(=0x0002)) | RB = 01000 MA = 0 y MB = 0 C9 = 1 y C9 = 0 T3 = 0 MA = 1 C.Op= 00110 (despl. a la izq) T5 = 1 SC = 1 y SC = 0 |
SW $t4, 0x0111
Señales que se activan | |
C5: MAR ß RI | C7 = 1 y C7 = 0 T8 = 1 C1 = 1 y luego C1 = 0 |
C6: MBR ß R12($t4) | T5 = 0 T4 = 1 TD = 1 Sel = 1 y L = 1 en memoria T4 = 0 T3 = 1 |
C7: MP ßMBR | RA = 001100 MA = 0 y MB = 0 T8 = 0 T1 = 1 C3 = 1 y C3 = 0 TA = 1 E = 1 |