En esta práctica, utilizando una
CPU de ejemplo implementada en Logisim, haremos las veces de Unidad de Control,
es decir, controlaremos el procesamiento de las siguientes instrucciones:
a) ADD $t0, $t1, $t2 f) LUI $s0,0x0011
b) ADDI $s0,$s1, 0x0011 g) SW $t4, 0x0111
c) ORI $t0, $t2, 0x00A1 h) SLT $t1, $t2, $t0
d) SLL $t0, $t0, 0x0002
i) J 0x000001A
e) SLR $t1, $t0, 0x0002 j) JR
$s0
Pasos
a seguir:
1.
Codificación de las instrucciones
2. Transferencia de registros y señales de control
3. Simulación en Logisim.
1.
Codificación de las instrucciones:
Una instrucción se puede
codificar tomando los códigos de operación correspondientes y siguiendo la estructura
del tipo de instrucción correspondiente (R, I, J). Para poder codificar las
instrucciones anteriores, debemos saber a qué valores equivalen los registros.
2.
Transferencia de registros y señales de control.
Escribir la secuencia de
transferencias y acciones consiste en especificar lo que sucede dentro de la CPU
por medio de las transferencias que se llevan a cabo entre los registros,
indicando también las señales de carga, triestado y selección que permiten
estas transferencias. Utilizaremos esta imagen para seguir los pasos:
Para ser lo más eficiente
posible, siempre que podamos, realizaremos
varias acciones en un mismo ciclo, cuando éstas no necesiten utilizar el mismo
bus.
3.
Simulación en Logisim.
En este paso asumiremos el papel
de la unidad de control para marcar en el presente circuito todas las señales
de control establecidas en el paso anterior para llevar a cabo las
instrucciones.
Al final de la práctica se explicará detalladamente todos
los pasos necesarios para realizar la simulación de una de las instrucciones.
Solución de
la Práctica
a) ADD $t0, $t1, $t equivale a ADD R8, R9, R10
Instrucción tipo R
|
Nmemónico
|
0
|
RS=$t1=9
|
RT=$t2=10
|
RD=$t0=8
|
0
|
0x2a
|
Binario
|
000000
|
01001
|
01010
|
01000
|
00000
|
10000
|
Hexadecimal
|
0x012A4020
|
S1: MAR ß PC T4, C1
S2: PC ß PC+4 C4
MBR ß MP Td,
L, C2
S3: RI ß MBR T3, C6
S4: Decodificación
S5: R8 ß R9+R10 RA=01001, RB=01010, MA=0,
MB=0, op="00001", T5, RC=01000
SC
S7: Comprobar
si hay interrupciones
b) ADDI $s0, $s1, 0x0011 equivale a ADDI R16, R17, 0x0011
Instrucción tipo I
|
Nmemónico
|
8
|
RS=$s1=17
|
RT=$s0=16
|
Imm=0x0011
|
Binario
|
001000
|
10001
|
10000
|
0000000000010001
|
Hexadecimal
|
0x22300011
|
S1: MAR ß PC T4, C1
S2: PC ß PC+4 C4
MBR ß MP Td,
L, C2
S3: RI ß MBR T3, C6
S4: Decodificación
S5: RT2 ß RI (0x0011) T8
C10
S6: R16 ß R17
+ RT2 RA=17,
MA=0, MB=0, op="00001",
T5,
RC=16
SC
S7: Comprobar
si hay interrupciones
c) ORI $t0, $t2, 0x00A1 equivale a ORI R8,R10,0x00A1
Instrucción tipo I
|
Nmemónico
|
0xD
|
RS=$t2=10
|
RT=$t2=8
|
Imm=0x00A1
|
Binario
|
001101
|
01010
|
01000
|
0000000010100001
|
Hexadecimal
|
0x354800A1
|
S1: MAR ß PC T4, C1
S2: PC ß PC+4 C4
MBR ß MP Td,
L, C2
S3: RI ß MBR T3, C6
S4: Decodificación
S5: RT2 ß RI (0x00A1) T8
C10
S6: R8 ß R10
OR Rt2 RA=10,
MA=0, MB=1, op="00003",
T5,
RC=8
SC
S7: Comprobar
si hay interrupciones
d) SLL $t0, $t0, 0x0002 equivale a SLL R8, R8, 0x0002
Instrucción tipo R
|
Nmemónico
|
0
|
RS=no
hay
|
RT=$t0=8
|
RD=$t0=8
|
Desp=0x0002
|
0
|
Binario
|
000000
|
00000
|
01000
|
01000
|
00010
|
000000
|
Hexadecimal
|
0x00084080
|
S1: MAR ß PC T4, C1
S2: PC ß PC+4 C4
MBR ß MP Td,
L, C2
S3: RI ß MBR T3, C6
S4: Decodificación
S5: RT2 ßRI (0x0002) T8
C10
S6: R8 ßR8
<< 0X0002 RA=01000,
MA=0, MB=1, op="00008",
T5,
RC=01000
SC
S7: Comprobar
si hay interrupciones
e) SLR $t1, $t0, 0x0002 equivale a SLL R9, R8,
0x0002
Instrucción tipo R
|
Nmemónico
|
0
|
RS=$t0=8
|
RT=no
hay
|
RD=$t1=9
|
Desp=0x0002
|
2
|
Binario
|
000000
|
01000
|
00000
|
01001
|
00010
|
000010
|
Hexadecimal
|
0x01004882
|
S1: MAR ß PC T4,
C1
S2: PC ß PC+4 C4
MBR ß MP Td,
L, C2
S3: RI ß MBR T3, C6
S4: Decodificación
S5: RT2 ß RI (0x0002) T8
C10
S6: R9 ß R8
>> 0X0002 RA=01000,
MA=0, MB=1, op="00005",
T5,
RC=01001
SC
S7: Comprobar
si hay interrupciones
f) LUI $s0, 0x0011 equivale a lui R16,0x0011
Instrucción tipo I
|
Nmemónico
|
0xf
|
0
|
RT=$s0=16
|
Imm=0x0011
|
Binario
|
001111
|
00000
|
10000
|
0000 0000 0001 0001
|
Hexadecimal
|
0x3C100011
|
S1: MAR ß PC T4, C1
S2: PC ß PC+4 C4
MBR ß MP Td, L, C2
S3: RI ß MBR T3, C6
S4: Decodificación
S5: RT2 ß RI T8
C10
S6: R16 ß R16
RA=10000,
MA=0, MB=1, op=”0006”
T5,
RC=10000
SC
S7: Comprobar
si hay interrupciones
g) SW $t4, 0x0111 equivale a sw R12, 0X0111
Instrucción tipo I
|
Nmemónico
|
0x2b
|
RS=0
|
RT=$t4=12
|
Imm=0x0111
|
Binario
|
101011
|
00000
|
01100
|
0000 0001 0001 0001
|
Hexadecimal
|
0xAC0C0111
|
S1: MAR ß PC T4, C1
S2: PC ß PC+4 C4
MBR ß MP Td,
L, C2
S3: RI ß MBR T3, C6
S4: Decodificación
S5: MAR ß RI(0x0111) T8
C1
S6: MBR ß R10 RA=01010
T1
C3
S7: MP ß MBR Ta,
Td, E
S8: Comprobar
si hay interrupciones
h) SLT $t1, $t2, $t0 equivale a SLT R9,R10,R8
Instrucción tipo R
|
Nmemónico
|
0
|
RS=$t2=10
|
RT=$t0=8
|
RD=$t1=9
|
0
|
0x2a
|
Binario
|
000000
|
01010
|
01000
|
01001
|
00000
|
101010
|
Hexadecimal
|
0x0148482A
|
S1: MAR ß PC T4, C1
S2: PC ß PC+4 C4
MBR ß MP Td,
L, C2
S3: RI ß MBR T3, C6
S4: Decodificación
S5:RT3ßR10-R8
RA=01010,RB=01000,MA=0,MB=0, op=00001
C11
REßALU
C8
S6:RT1ß
RE(BIT SIGNO)
T7
C9
S7: R9ß NOT(RT2)
MA=1,Op=00110
T5
RC=01001,SC
S8: Comprobar
si hay interrupciones
i) J 0x000001A j target
Instrucción tipo
J
|
Nmemónico
|
2
|
0x0000001A
|
Binario
|
000010
|
0000 0000 0000 0000 0000 0001 1010
|
Hexadecimal
|
0x0800001A
|
S1: MAR ß PC T4, C1
S2: PC ß PC+4 C4
MBR ß MP Td,
L, C2
S3: RI ß MBR T3, C6
S4:
Decodificación
S5: PC ß RI(0x0000001A) T8
C5
S6: Comprobar
si hay interrupciones
j) JR $s0 jr rs
Instrucción tipo
R
|
Nmemónico
|
0
|
RS=$S0=16
|
0
|
8
|
Binario
|
000000
|
10000
|
000 0000 0000 0000
|
001000
|
Hexadecimal
|
0x02000008
|
S1: MAR ß PC T4, C1
S2: PC ß PC+4 C4
MBR ß MP Td,
L, C2
S3: RI ß MBR T3, C6
S4: Decodificación
S5: PC ß R16 RA=10000,
T1
C5
S6: Comprobar
si hay interrupciones
Simulación con Logisim
En primer lugar vamos a
introducir los códigos de operación obtenidos anteriormente en la memoria. Para
ello:
1. Hacemos clic derecho en la
memoria.
2. Clicamos en Editar
contenidos...
3. Introducimos por teclado los
códigos de operación en hexadecimal en las primeras 10 posiciones, debe quedar una cosa así:
4. Cerramos la ventana.
Es recomendable que guardemos el
estado de la memoria (mediante uno de los botones de la parte inferior del
editor de contenidos) para poder abrirlo en cualquier momento, ya que la
memoria se limpia cada vez que cerramos Logisim.
Vamos
a simular las instrucción ADD $t0, $t1, $t2.
En primer lugar debemos abrir el
triestado T4 para sacar la dirección de memoria donde está contenida la
instrucción. En este caso la primera está contenida en la primera dirección por
lo que el contador estará todo a 0. A su vez activamos la señal de carga del
registro MAR (C1) que es un registro que almacena la dirección de la
instrucción a la que se va a acceder. En este ejemplo la instrucción que
contendrá la memoria almacenada es la de la instrucción ADD $t0, $t1, $t2 pero como hemos dicho puede contener cualquier instrucción
porque estos pasos son los mismos para
todas.
Nótese que la instrucción está
almacenada en memoria en hexadecimal.
En el siguiente ciclo abriremos
la memoria en modo lectura y accederemos a la posición que nos indica el registro
MAR y acto seguido guardaremos el contenido de esa posición (instrucción en hexadecimal)
en el registro MBR. Para ello abriremos el triestado TD y activaremos el modo
lectura (L) y también el pin de selección, para seleccionar la posición de
memoria que contiene la instrucción y activamos C2 para almacenar su contenido
en el registro MBR. Simultáneamente debemos accionar la carga C4 del contador
del programa para sumar 4 bytes al contenido de éste
para poder acceder más tarde a
la siguiente instrucción mediante el mismo mecanismo que estamos haciendo ahora
(hay que sumar 4 bytes ya que una instrucción ocupa 32bits en memoria).
Por último, antes de decodificar
la instrucción en la unidad de control, debemos llevarla desde el registro MBR
al registro RI, que es un registro que sirve para almacenar la instrucción
justo antes de ser decodificada por la unidad de control. Para realizar este
paso necesitamos activar el triestadoT3, y la carga C6.
A partir de aquí será la unidad
de control la encargada de generar las señales para que se lleve a cabo la
instrucción. En esta simulación seremos nosotros los encargados de generar
dichas señales.
Como es necesario que existan datos en los registro para realizar
la suma, previamente hemos
introducido 1 en $t1 y 2 en $t2.
Primero debemos llevar los datos
a la ALU. Para ello seleccionamos el registro $t1, mediante RA=01001 y RB=01010
(dejando los multiplexores que hay antes de la ALU a 0, que significa que los
datos vienen del banco de registros) y una vez hecho esto se realiza la suma en
la ALU mediante el código de operación 0. Y para almacenar el resultado de la
suma debemos accionar T5, seleccionar el registro $t0 en la señal RC y activar
SC para poder realizar el almacenamiento en el banco de registros. A la vez que
se almacena la suma en el banco debemos almacenar los indicadores de la
operación en el registro de indicadores mediante la señal de carga C8.
FAQs
¿Qué es una señal de triestado?
Son señales que sirven para liberar datos de los registros y se representan con una T.
¿Qué son las señales de carga?
Son señales que sirven para introducir datos en los registros y se representan con una
C.
¿Cómo se introduce un dato en la memoria con logisim?
Para introducir datos en la memoria con logisim debemos clickar con el botón derecho
del ratón sobre la memoria y pulsamos en Editar Contenidos... Una vez lo hayamos
hecho se nos abrirá una ventana. La primera columna de esa ventana nos dice cuál es
la dirección de la primera posición de cada fila, siendo las siguientes posiciones los
grupos de ceros que hay a la derecha y que a su vez, esos grupos de ceros son el
contenido de cada posición de la memoria. Para modificar esos contenidos, pinchamos
en la posición que queramos e introducimos los datos que queramos, sabiendo que el
contenido se expresa en hexadecimal. Aún así en el resumen del tema 4 ponemos una
breve explicación de como se hace.
¿Cómo sé el código de la operación que quiero realizar en la ALU?
Los códigos de las operaciones viene en una tabla del propio enunciado de la práctica.
¿Por qué $t0 es R8 o $s0 es R16?
Hemos utilizado una tabla vista en teoría, concretamente hemos utilizado los registro
del MIPS. También puedes verla en el propio enunciado de la práctica.
¿Cómo podemos saber el orden de los registros a la hora de codificar la instrucción y
si son de tipo R,I o J?
En la teoría del tema 3 vienen una serie de tablas con la sintaxis y el orden de los
registros, así como el número de bits que tienes que utilizar para ello, también te dice
de que tipo es cada instrucción.