Esta práctica se compone de tres partes, en la primera de ellas, veremos como se codifican diferentes instrucciones de la forma que quedarían en memoria y sean procesables por el ordenador, esto será una secuencia en binario de las diferentes partes de cada instrucción. Continuaremos viendo las señales que son necesarias generar para efectuar dichas operaciones por la ALU y unidad de control, y por último, utilizando el programa Logisim, con una CPU real, donde recrearemos todas estas instrucciones para visualizar la secuencia de pasos.
Primera parte:
Para codificar las instrucciones, necesitaremos saber el tipo de instrucción que estamos tratando (tipo R, I o J), como está estructurada y numero de bits que corresponden a cada parte. Para ello haremos uso de el siguiente documento de referencia, Apendice Hennessy Patterson. En dicho documento, buscaremos la instrucción que nos interese y veremos algo como lo siguiente:
En la parte izquierda vemos como se emplea la instrucción add normalmente. Consta de tres registros, de los cuales, los llamados rs y rt se sumarán, guardando el resultado de la suma en el registro llamado rd.
En la pequeña tabla vemos como codificaríamos la instrucción en memoria y debajo el numero de bits de cada parte.
Debemos notar que aunque la instrucción tenga un determinado orden de los registros al escribirse, cuando la codificamos en memoria el orden de los mismo varía. Es decir, el registro rd pasa a tercer lugar, rs al primero y rt al segundo. Por otra parte, vemos que la primera celda consta 6 bits a cero (operación de tipo aritmética) y la última celda con el número hexadecimal es el código de la operación (en este caso una suma).
Con esto sabemos como está estructurada nuestra instrucción, pero aun necesitamos saber el numero que corresponde a cada registro. Pongamos un ejemplo, en la instrucción add $t0, $s1, $s3, necesitamos conocer el número de los registros $t0, $s1 y $s3 (no hay que confundir con el valor). Para ello, en la práctica se nos proporciona una tabla donde podemos consultarlo, aunque también podemos hacerlo en el mismo documento de referencia que hemos empleado para las instrucciones.
Por lo que vemos, el registro $t0 es el número 8, el registro $s1 es el número 17 y el registro $s3 es el número 19 (deberemos pasarlos a binario).
Ya tenemos todos los datos necesarios para formar nuestra instrucción:
- 1) 6 bits: 000000
- 2) 5 bits: rs = $s1 = 17 = 10001
- 3) 5 bits: rt = $s3 = 19 = 10011
- 4) 5 bits: rd = $t0 = 8 = 01000
- 5) 5 bits: 00000
- 6) 6 bits: 0x20 = 100000
Ordenada en memoria sería: 00000010001100110100000000100000
Y convertida a hexadecimal: 0x02334020
Emplearemos el mismo método para todas las instrucciones, teniendo en cuenta como están formadas las mismas según el tipo que sean.
Segunda parte:
En esta parte debemos indicar la secuencia de transferencia y acciones que se realizan para cada una de las instrucciones basándonos en la CPU que nos proporciona la práctica.
Debemos tener en cuenta para empezar, que el ciclo de captación de instrucción (FETCH) se realiza siempre, para todas las instrucciones que realiza la CPU. Por lo tanto la incluiremos en todas las instrucciones.
Primero se carga en MAR la dirección de la instrucción que se va a ejecutar, la cual está en el contador de programa, después se incrementa en contador de programa para dejar preparada la siguiente instrucción y se guarda en MBR la instrucción codificada que corresponde a la dirección que había en MAR, por ultimo se carga en el registro de instrucción la propia instrucción que teníamos en MBR. Después de esto se produce la decodificación de la instrucción. Podríamos decir que las transferencias serían:
S1: MAR ß PC
S2: PC ß PC + 4 | MBR ß MP
S3: RI ß MBR
S4: Decodificación
Todo esto en lenguaje de señales quedaría de la siguiente manera:
S1: T4, C1
S2: Td, L, C4, C2
S3: T3, C6
S4: -------------------
A partir de este punto veríamos en que consiste nuestra instrucción, que registros están involucrados y que datos están haciendo uso de un determinado bus en un determinado momento.
En nuestro ejemplo queremos utilizar la instrucción add $t0, $s1, $s3, es decir:
R8($t0) ß R17($s1) + R19($s3)
¿Que señales necesitaríamos para realizar esta acción?
Debemos fijarnos en la CPU que nos han dado, lo primero es seleccionar con RA y RB los registros R17 y R19, después indicaremos en los multiplexores MA y MB un cero, para que tome el dato directamente y no el de los registros RT1 y RT2, continuaremos indicando la operación que vamos a realizar (una suma), tomaremos el resultado directamente sin pasar por el registro RT3 abriendo el triestado T5, seleccionaremos el registro en el que vamos a guardar el resultado con RC, en este caso el R8 y por ultimo activaremos la carga con SC:
RA = R17, RB = R19, MA = 0, MB = 0, OP = SUMA, T5, RC = R8, SC
Debemos tener en cuenta que no todas las operaciones pueden realizarse directamente como esta, en algunas tendremos que guardar los valores en registros intermedios para dejar libre el bus, en otras tomaremos datos del registro de instrucción y en otros modificaremos el contenido de PC, por lo tanto utilizaremos mas señales y más ciclos.
Resolución de la práctica:
a) ADD $t0, $t1, $t2
add rd, rs, rt
Instrucción tipo R
| ||||||
Mnemónico
|
ADD
|
rs=$t1
|
rt=$t2
|
rd=$t0
|
0
|
0x0020
|
Binario
|
.000000
|
.01001
|
.01010
|
01000
|
00000
|
100000
|
Hexadecimal
|
0x012A4020
| |||||
En este ejercicio, las señales que tendremos que generar serán como en ejemplo que se ha dado anteriormente, únicamente varían los registros que utilizaremos. Recordemos que debemos incluir siempre la fase de captación en todas las instrucciones.
| Lenguaje de transferencias | Lenguaje de señales |
S1:MAR ß PC
S2: PC ß PC+4, MBR ß MP
S3 :RI ß MBR
S4 : Decodificación
S5: R8 ß R9+R10
|
S1: T4, C1
S2: Td, L, C4, C2
S3: T3, C6
S4: ----------------
S5: RA=(R9), RB=(R10), MA=0, MB=0, OP=(SUMA), T5, RC=(R8), SC
|
b) ADDI $s0,$s1, 0x0011
addi rt, rs, imm
Instrucción tipo I
| ||||
Mnemónico
|
ADDI
|
rs=$s1
|
rt=$s0
|
0x0011
|
Binario
|
.001000
|
10001
|
10000
|
0000000000001011
|
Hexadecimal
|
0x2230000B
| |||
En esta instrucción utilizaremos un valor inmediato. Este valor inmediato lo sacaremos de la propia instrucción, es decir, tendremos que sacar ese valor del registro de instrucción (RI) y llevarlo a los registros RT1 o RT2 para utilizarlos posteriormente en la suma.
Lenguaje de transferencias
|
Lenguaje de señales
|
S1:MAR ← PC
S2: PC ← PC+4, MBR ← MP
S3:RI ← MBR
S4: Decodificación
S5: RT2 ← RI
S6: R16 ← R17+RT2
|
S1: T4, C1
S2: Td, L, C4, C2
S3: T3, C6
S4: -----------------
S5: T8, C10
S6: RA=1(R17),OP=(SUMA), MA=0, MB=1, T5, RC=(R16), SC
|
c) ORI $t0, $t2, 0x00A1
ori rt, rs, imm
Instrucción tipo I
| ||||
Mnemónico
|
ORI
|
rs=$t2
|
rt=$t0
|
0x00A1
|
Binario
|
001101
|
01010
|
01000
|
0000000010100001
|
Hexadecimal
|
0x354800A1
| |||
En este caso realizaremos una operación OR entre un valor de un registro y un valor inmediato, nuevamente tendremos que tomar la parte del valor inmediato del registro de instrucción y llevarlo a un registro intermedio (RT1 o RT2) para realizar la operación OR.
Falta terminar
Lenguaje de transferencias
|
Lenguaje de señales
|
S1:MAR ← PC
S2: PC ← PC+4, MBR ← MP S3:RI ← MBR S4: Decodificación S5: RT2 ← RI S6: R8 ← R10 OR RT2 |
S1: T4, C1
S2: Td, L, C4, C2 S3: T3, C6 S4: ----------------- S5: T8, C10 S6: RA=R10, MA=0, MB=1, OP=OR, T5, RC=R8, SC |
d) SLL $t0, $t0, 0x0002
sll rd, rt, shamt
Instrucción tipo R
| ||||||
Mnemónico
|
SLL
|
rs
|
rt=$t0
|
rd=$t0
|
shamt=0x0002
|
0
|
Binario
|
.000000
|
.00000
|
01000
|
01000
|
00010
|
000000
|
Hexadecimal
|
0x00084080
| |||||
SLL es una operación de tipo desplazamiento, la cual desplazará un numero de bits a la izquierda. Primero debemos obtener el número de bits que van a desplazarse del registro de instrucción y guardarlo en un registro intermedio (por ejemplo RT1). Normalmente realizaríamos la operación directamente leyendo del registro que vamos a desplazar los bits y escribiendo en otro, pero en este caso, el registro del que leemos y en el que vamos a escribir es el mismo, por lo que tendremos que guardar el resultado de la operación en el registro RT3 para dejar libre el bus. Una vez aquí el dato ya podremos guardarlo en el registro destino en el siguiente ciclo de reloj.
Lenguaje de transferencias
|
Lenguaje de señales
|
S1:MAR ← PC
S2: PC ← PC+4, MBR ← MP S3:RI ← MBR S4: Decodificación S5: RT2 ← RI S6: RT3 ← R8 SLL RT2 S7: R8 ← RT3 |
S1: T4, C1
S2: Td, L, C4, C2 S3: T3, C6 S4: ----------------- S5: T8, C10 S6: RA=(R8), OP=(SLL), MA=0, MB=1, C11 S7: T6, RC=(R8), SC |
e) SLR $t1, $t0, 0x0002
srl rd, rt, shamt
Instrucción tipo R
| ||||||
Mnemónico
|
SRL
|
rs
|
rt=$t0
|
rd=$t1
|
shamt=0x0002
|
0x2
|
Binario
|
.000000
|
.00000
|
01000
|
01001
|
00010
|
000010
|
Hexadecimal
|
0x00084882
| |||||
SLR es una operación de tipo desplazamiento, pero en este caso los bits se desplazan a la derecha. El planteamiento del problema es exactamente igual que en el ejercicio anterior, solo que esta vez no necesitaremos guardar el resultado de la operación en RT3 porque el registro del que se lee el dato y el que se guarda es distinto.
Lenguaje de transferencias
|
Lenguaje de señales
|
S1:MAR ← PC
S2: PC ← PC+4, MBR ← MP
S3:RI ← MBR S4: Decodificación S5: RT2 ← RI S6: R9 ← R8+RT2 |
S1: T4, C1
S2: Td, L, C4, C2 S3: T3, C6 S4: ----------------- S5: T8, C10 S6: RA=(R8), OP=(desplazamiento), MA=0, MB=1, T5, RC=(R9), SC |
f) LUI $s0,0x0011 HAY QUE REVISAR ESTA INSTRUCCIÓN
lui rt, imm
Instrucción tipo I
| ||||
Mnemónico
|
LUI
|
0
|
rt=$s0
|
0x0011
|
Binario
|
001111
|
00000
|
10000
|
0000000000001011
|
Hexadecimal
|
0x3C10000B
| |||
Esta operación, carga el valor inmediato que se le especifica en la parte alta del registro que le indicamos.
Lenguaje de transferencias
|
Lenguaje de señales
|
S1:MAR ß PC
S2: PC ß PC+4, MBR ß MP
S3 :RI ß MBR
S4 : Decodificación
S5: MAR ß RI
S6: MBR ß MP
S7: R16 ß MBR
|
S1: T4, C1
S2: Td, L, C4, C2
S3: T3, C6
S4: -------------------
S5: T8, C1
S6: Td, L, C2
S7: RC(R16), SC |
g) SW $t4, 0x0111
sw rt, address
Instrucción tipo I
| ||||
Mnemónico
|
SW
|
rs=0
|
rt=$t4
|
0x00A1
|
Binario
|
001101
|
00000
|
01101
|
0000000001101111
|
Hexadecimal
|
0x340D006F
| |||
Esta instrucción guarda en la dirección que le indicamos el dato que se encuentra en el registro que escribimos como primer parámetro. Por lo tanto, esta instrucción es un poco diferente a las anteriores. Primero tendremos que guardar en el registro MAR la dirección que tenemos en el registro de instrucción, después guardaremos en el registro MBR el dato que hay en el registro $t4 y por último, escribiremos en memoria principal, el dato que hay en el registro MBR en la dirección que indica el registro MAR.
Lenguaje de transferencias
|
Lenguaje de señales
|
S1:MAR ß PC
S2: PC ß PC+4, MBR ß MP
S3 :RI ß MBR
S4 : Decodificación
S5: MAR ß RI
S6: MBR ß R12
S7: MP ß MBR
|
S1: T4, C1
S2: Td, L, C4, C2
S3: T3, C6
S4: -------------------
S5: T8, C1
S6: RA(R12), T1, C3
S7: Td, Ta, E |
h) SLT $t1, $t2, $t0
slt rd, rs, rt
Instrucción tipo R
| ||||||
Mnemónico
|
SLT
|
rs=$t2
|
rt=$t0
|
rd=$t1
|
0
|
0x002a
|
Binario
|
.000000
|
01010
|
01000
|
01001
|
00000
|
101010
|
Hexadecimal
|
0x0148482A
| |||||
Esta instrucción realiza una comparación, si $t2 es menor que $t0, pone a 1 $t1, si es al contrario, pone a 0 $t1. No varía en nada con respecto a una operación ADD con respecto a señales se refiere.
Lenguaje de transferencias
|
Lenguaje de señales
|
S1:MAR ß PC
S2: PC ß PC+4, MBR ß MP
S3 :RI ß MBR
S4 : Decodificación
S5: R9 ß R10 slt R8
|
S1: T4, C1
S2: Td, L, C4, C2
S3: T3, C6
S4: -------------------
S5: RA(R10), RB(R8), OP(SLT), MA(0), MB(0), T5, RC(R9), SC
|
i) J 0x000001A
j dir
Instrucción tipo J
| ||
Mnemónico
|
J
|
0x000001A
|
Binario
|
000010
|
00000000000000000000011010
|
Hexadecimal
|
0x0800001A
| |
Está es una instrucción de tipo salto. Modificará el contenido del contador de programa (PC) para que se ejecute una instrucción determinada en vez de la que tocaría a continuación. Asi que simplemente cogeremos del registro de instrucción la dirección de la siguiente instrucción y la guardaremos en el registro PC.
Lenguaje de transferencias
|
Lenguaje de señales
|
S1:MAR ß PC
S2: PC ß PC+4, MBR ß MP
S3 :RI ß MBR
S4 : Decodificación
S5: PC ß RI
|
S1: T4, C1
S2: Td, L, C4, C2
S3: T3, C6
S4: -------------------
S5: T8, C5
|
j) JR $S0
jr rs
Instrucción tipo J
| ||||
Mnemónico
|
JR
|
rs=$s0
|
0
|
0x8
|
Binario
|
000000
|
10000
|
000000000000000
|
001000
|
Hexadecimal
|
0x02000008
| |||
Esta instrucción es parecida a la anterior con la diferencia de que la dirección no se obtiene del registro de instrucción, sino de un registro del banco de registros que hemos indicado. Simplemente modificaremos el contenido de PC con el valro de este registro.
Lenguaje de transferencias
|
Lenguaje de señales
|
S1:MAR ß PC
S2: PC ß PC+4, MBR ß MP
S3 :RI ß MBR
S4 : Decodificación
S5: PC ß R16
|
S1: T4, C1
S2: Td, L, C4, C2
S3: T3, C6
S4: -------------------
S5: RA(R16), T1, C5
|
Tercera parte:
a) ADD $t0, $t1, $t2
1) Primero ponemos en la memoria el valor inmediato 01001 ($t1).
3) Activamos la lectura de la memoria y ya aparece visible en el bus de datos.
4) Capturamos el dato en MBR seleccionando doblemente C2.
5) Luego lo pasamos al bus interno seleccionando el triestado (T3).
6) Capturamos el dato en el banco de registro, nosotros lo hemos hecho en la captura 3.
8) Cambiamos el registro a la posición 4.
9) Cambiamos el contenido de la dirección a 01010 ($t2).
10) Desactivamos el triestado (T3).
11) Habilitamos el triestado (TD).
12) Hacemos un flaco en C2.
13) Luego lo pasamos al bus interno seleccionando el triestado (T3).
14) Hacemos un flanco en SC.
17) Ya tenemos un dato en el registro tercero (RA=01001) y otro en el cuarto (RB=01010), por lo tanto, ya podemos operar en la ALU, mediante los multiplexores (MA, MB).
18) Ya podemos ver la salida de la suma (SALIDA ALU) y para capturar el dato de salida en uno de los registros, tenemos que llevar el dato de salida hasta el bus interno activando el triestado (T5).
19) Ya podemos ver el dato en el bus interno y por lo tanto, lo podemos capturar en el banco, seleccionamos el registro donde lo queremos guardar, un nuestro caso, será el registro cinco ($t0) y hacemos una captura en SC.
20) Al final vemos que en el registro cinco ($t0), se ha guardado el resultado que ha salido de la ALU.
El resto de apartados se harían de la misma forma y pongo en este enlace todas las fotos por si no se ven bien.



No hay comentarios:
Publicar un comentario