Tema 2: Soluciones a los ejercicios - myTeachingURJC/Arq-computadores-01 GitHub Wiki
Soluciones a los ejercicios del Tema 2: Diseño de un repertorio de instrucciones
Contenido
- Sesión 5: ISA. Repertorios CISC y RISC
- Sesión 6: Almacenamiento de operandos
- Sesión 7: Modos de direccionamiento. Tipos de instrucciones
- Autores
- Licencia
- Enlaces
Sesión 5: ISA. Repertorios CISC y RISC
Soluciones a los ejercicios propuestos en la sesión 5: ISA. Repertorios CISC y RISC
Ejercicio 1
- Apartado a) ¿Cuantas instrucciones como máximo se pueden tener en esta arquitectura?
En el formato de la instrucción observamos que el campo opcodes es de 5 bits. Esto significa que hay un total de 32 posibles valores. Por tanto, este procesador sólo puede tener 32 instrucciones como máximo
- Apartado b) ¿Cual es el tamaño máximo de la memoria del EDSAC (en palabras)? Supón que todos los datos son palabras de 17 bits
El bit del campo T nos define el tamaño del operando: pequeño o grande. Es decir, que las instrucciones pueden trabajar con palabras de 17 bits ó de 35 bits. Para hacer este apartado nos indican que supongamos que las palabras son de 17 bits solamente
El campo Dirección del dato contiene la dirección del operando en memoria. Este campo tiene 10 bits, por lo que sólo puede haber 2 elevado a 10 = 1024 direcciones posibles. Sólo tenemos acceso a 1024 palabras desde las instrucciones. Por tanto, el tamaño máximo de la memoria será de 1024 palabras
- Apartado c) En la posición de memoria 921 se encuentra la variable var1, que tiene el valor 30 (de 17 bits). El código de operación de la instrucción de suma es el 11100 en binario, que suma al regisgtro acumulador el contenido de la variable de memoria indicada: A = A + variable, donde A es el acumulador del EDSAC. Escribe escribe la instrucción en código máquina que hace la operación: A = A + var1
Utilizando el formato de las instrucciones del EDSAC, asignamos los valores correspondientes a cada campo:
- Opcode = 11100 (binario)
- R = 0 (Bit reservador, lo ponemos a 0)
- Dirección del dato: 921 en decimal = 1110011001 binario (10 bits)
- Tamaño: 17 bits. Por tanto el bit T lo ponemos a cero
Opcode | R | Direccion | T |
---|---|---|---|
11100 | 0 | 1110011001 | 0 |
Por tanto, la instrucción en código máquina es:
11100011100110010
Ejercicio 2
- Apartado a) ¿Cuantas instrucciones como máximo se pueden tener en esta arquitectura?
En el formato de la instrucción observamos que el campo opcodes es de 3 bits. Esto significa que hay un total de 2 elevado a 3 posibles valores. Por tanto, este procesador sólo puede tener 8 instrucciones como máximo. ¡Con un computador de sólo 8 tipos de instrucciones llegamos a la luna! Bueno, en realidad, 8 son las instrucciones implementadas por hardware, sin embargo se crearon más implementadas por software
- Apartado b) ¿Cual es el tamaño máximo de la memoria del AGC (en unidades de 16 bits)?
El campo Dirección del dato contiene la dirección del operando en memoria. Este campo tiene 12 bits, por lo que sólo puede haber 2 elevado a 12 = 4096 direcciones posibles. Sólo tenemos acceso a 4096 posiciones de 16 bits desde las instrucciones. Por tanto, el tamaño máximo de la memoria será de 4096 palabras
Como curiosidad, en la actualidad, la unidad mínima de almacenamiento es de 1 byte, por eso cada dirección de memoria se refiere un byte. Un dato de 16 bits ocupa 2 posiciones de memoria. No es así en el computador del Apollo, ya que la unidad mínima de intercambio son de 16 bits
- Apartado c) [...] Escribe las instrucciones en ensamblador del AGCC para calcular A = var1 + var2
La instrución AD hace la operación A = A + var. Sabemos que inicialmente A=0, por lo tanto la instrucción AD var1
lee el valor de la primera variable y lo guarda en el acumulador. Con la instruccion AD var2
se le suma var2
al resultado anterior, obteniéndose la suma pedida. Por tanto, el programa es el siguiente:
AD var1
AD var2
- Apartado d) [...] escribe en código máquina (en hexadecimal) el programa del apartado c (var1 = 0x080, var2=0x1F0)
Siguiendo el formato descrito, colocamos los dos campos de las instrucciones, en binario
Opcode (3 bits) | Dir del Dato (12bits) |
---|---|
011 | 000010000000 (0x080) |
011 | 000111110000 (0x1F0) |
Así, el programa en código máquina (en binario) sería:
011000010000000
011000111110000
Ahora lo pasamos a hexadecimal (el enunciado nos lo piden en hexadecimal):
0x3080
0x31F0
Como las direcciones son de 12 bits se representan exactamente con 3 dígitos hexadecimales. Así, el código máquina del Apolo es muy fácil de leer: El primer dígito en hexadecimal sólo vale 0 - 7 e indica la instruccion (3 para AD). Los siguientes 3 dígitos son las dirección de acceso a memoria
Ejercicio 3
- Apartado a): Obtén el código máquina (en hexadecimal) del siguiente programa:
addi x0, x0, 0
addi x31, x15, 0x0F
Ponemos las instrucciones en el formato de la instrucción, descomponiéndola en sus campos y luego agrupamos los bits de 4 en 4 para obtener su número hexadecimal
Instrucción addi x0, x0, 0
:
Instrucción addi x31, x15, 0x0F
:
El programa en código máquina es:
0x00000013
0x00F78F93
- Apartado b): Desensambla este programa en código máquina y obtén su equivalente en lenguaje ensamblador. ¿Qué hace el programa?
0x00100193
0x00218193
Hacemos las operaciones inversas. Primero lo ponemos en binario y luego lo agrupamos en sus campos. Por el código de operación vemos que se trata de instrucciones addi, así que el formato es el mismo indicado en el enunciado
La instrucción 0x00100193
la decodificamos así:
La instrucción 0x00218193
se codifica así:
Por tanto, el programa en ensamblador es:
addi x3, x0, 1
addi x3, x3, 2
Este programa calcula la expresión x3 = 1 + 2
Sesión 6: ISA. Almacenamiento de operandos
Soluciones a los ejercicios propuestos en la sesión 6: ISA. Almacenamiento de operandos
Ejercicio 1
- Apartado a) Escribe el programa en ensamblador del computador A que realiza esta operación
Como el computador A tiene una **arquitectura Registro-Registro+*, lo primero es cargar en los registros las variables. Luego se realizan las operaciones y finalmente se almacena el resultado en la variable f, en la memoria principal. Los registros los denominamos x0 - x15
y como son de propósito general, podemos usar los que queramos para el almacenamiento de los cálculos intermedios
# -- Llevar las variables en memoria a registros
load x1, a
load x2, b
load x3, c
load x4, d
# -- Realizar las operaciones intermedias
add x5, x1, x2 #-- x5 = (a + b)
sub x5, x5, x3 #-- x5 = (a + b) - c
add x5, x5, x4 #-- x5 = (a + b) - c + d
# -- Almacenar el resultado en f
store x5, f
El programa tiene 8 instrucciones en total
Apartado b) Calcula el tráfico total (en bytes) entre el procesador y la memoria cuando se ejecuta este programa
Las instrucciones de load
y store
ocupan 5 bytes (40 bits) y al ejecutarse realizan la lectura/escritura de un dato de 4 bytes (32 bits)
Las instrucciones add
y sub
ocupan 2 bytes (16 bits) y al ejecurse no acceden a memoria por lo que no generan tráfico de datos
En esta tabla se resumen el tráfico total de bytes con la memoria, dividido en el tráfico debido a la lectura de las instrucciones más el tráfico debido a los datos
Instruccion | Trafico Instruciones (bytes) | Trafico datos (Bytes) | Total (bytes) |
---|---|---|---|
load x1, a | 5 | 4 | 9 |
load x2, b | 5 | 4 | 9 |
load x3, c | 5 | 4 | 9 |
load x4, d | 5 | 4 | 9 |
add x5, x1, x2 | 2 | 0 | 2 |
sub x5, x5, x3 | 2 | 0 | 2 |
add x5, x5, x4 | 2 | 0 | 2 |
store x5, f | 5 | 4 | 9 |
Total | 31 | 20 | 51 |
Ejercicio 2
- Apartado a) Escribe el programa en ensamblador del computador B que realiza esta operación
Este computador tiene una arquitectura registro - memoria, por lo que las instrucciones de suma y resta tienen un operando en un registro y el otro en la memoria. Teniendo en cuanta que inicialmente los registros está inicializados a 0, este programa realiza la operación pedida:
#-- Realizar las operaciones
add x1, a #-- x1 = 0 + a
add x1, b #-- x1 = (a + b)
sub x1, c #-- x1 = (a + b) - c
add x1, d #-- x1 = (a + b) - c + d
#-- Almacenar el resultado en memoria
store x1, f
En total hay 5 instrucciones
- Apartado b: Calcula el tráfico total (en bytes) entre el procesador y la memoria cuando se ejecuta este programa
Todas las instrucciones ocupan 5 bytes (40 bits), y todas realizan acceso a memoria, por lo que su tráfico de datos es de 4 bytes
El tráfico total debido a la lectura de las instrucciones es de 5 * 5 = 25 bytes. El trafíco debido a los datos es de 5 * 4 = 20 bytes. El tráfico total es de 25 + 25 = 45 bytes
Sesión 7: Modos de direccionamiento. Tipos de instrucciones
Soluciones a los ejercicios propuestos en la sesión 7: Modos de direccionamiento. Tipos de instrucciones
Ejercicio 1
- a) load_byte x1, 0x10010003
Los bytes se leen tal cual. Al ser las unidades mínimas de almacenamiento son atómicas y NO se aplica el concepto de ordenación. Así que el valor de x1 es de 0x1D
- b) load_byte x1, 0x10010005
x1 = 0xCA
- c) load_half x1, 0x10010003
Cuando se cargan datos mayores que un bytes, siempre se especifica la dirección del primer byte del dato. En las direcciones consecutivas se almacenan el resto de bytes. En este caso, queremos leer una media palabra (16-bits, 2 bytes) situada a partir de la dirección 0x10010003. Los bytes de esta media palabrá están almacenados por tanto en las direcciones 0x10010003 y 0x10010004. Pero... ¿En qué orden? En este computador nos dicen que la ordenación es little endian por lo que primero está el byte de menos peso, y luego el de mayor
x1 = 0x001D
- d) load_half x1, 0x10010005
x1 = 0xBACA
- e) load_word x1, 0x10010002
Las palabras ocupan 4 bytes. Con la instrucción dada se leen 4 bytes, de las posiciones de memoria 0x10010002, 0x10010003, 0x10010004 y 0x10010005. ¿En qué orden? Igual que antes. Este computador tiene ordenación little endian por lo el primer byte es el de menor peso y el último el de mayor
x1 = 0xCA001D2C
- f) load_word x1, 0x10010005
x1 = 0xDEFEBACA
- g) load_dword x1, 0x10010001
Las dobles palabras ocupan 8 bytes. Con esta intrucción se leen los 8 bytes a partir de la dirección 0x10010001. Sabemos que el priimer byte (el de la dirección 0x10010001 será el de menor peso)
x1 = 0xDEFEBACA001D2C3B
Ejercicio 2
- a) Como los bytes son unidades atómicas, el ordenamiento no les afecta por lo que: x1 = 0x1D
- b) x1 = 0xCA
- c) Se construye a partir de los 2 bytes situados en 0x10010003 y 0x10010004. El primero es el de mayor peso y el segundo el de menor: x1 = 0x1D00
- d) x1 = 0xCABA
- e) Se construye a partir de los 4 bytes situados en las direcciones 0x10010002, 0x10010003, 0x10010004 y 0x10010005
x1=0x2C1D00CA - f) x1 = 0xCABAFEDE
- g) Se construye a partir de los 8 bytes situados desde la dirección 0x10010001 en adelante
x1 = 0x3B2C1D00CABAFEDE
Ejercicio 3
Para poder ejecutarse cada una de las instrucciones será necesario primero un acceso a memoria para su lectura. Sin embargo, lo que nos están pidiendo son los accesos que se producen en la ejecución, una vez que la instrucción ya ha sido leida de memoria y está dentro del procesador listsa para ser ejecutada
- a) Como los bytes son las unidades mínimas de información (y son atómicas) no hay nunca problemas de alineamiento. Sólo habrá 1 acceso para leer el dato
- b) 1 acceso
- c) En el caso de las medias palabras, el número de accesos depende de si se accede a una dirección alineada o no. Las direcciones alineadas para las palabras son las direcciones pares. Así, si se lee una media palabra de una dirección par, sólo habrá un único acceso a memoria. Pero si se lee de una dirección impar, habrá 2. Como el dato está en la dirección 0x2000, que es par, el número de accesos es 1
- d) De los dos bytes de la media palabra, uno está en la palabra de la dirección 0x2004 y el otro en la de la dirección 0x2008. Por tanto el número de accesos es de 2
- e) Número de accesos: 1
- f) La direcciones alineadas para las palabras son las que son múltiplo de 4. En hexadecimal es fácil reconocerlas porque acaban en 0, 4, 8 ó C. Si la lectura es en una dirección alineada, sólo habrá un único acceso. Si es a una dirección no alineada entonces se necesitarán 2 accesos. La dirección 0x2000 está alineada, así que el número de accesos es de 1
- g) Dirección alineada: Número de accesos: 1
- h) Dirección NO alineada: Número de accesos: 2
- i) Dirección NO alineada: Número de accesos: 2
Ejercicio 4
- Apartado a) Los valores que se han almacenado en cada posición de memoria (Rellena el dibujo)
- Apartado b) ¿Cuantos accesos de escritura a memoria se han realizado en total?
Nos piden accesos de escritura, por tanto la lectura de las instrucciones está descartada. El número de accesos en escritura depende del dato utilizado y si es una dirección alineada o no (para ese dato). Si es alineada, cada instrucción provoca 1 acceso de escritura, mientras que si no es alineada se realizan 2 accesos de escritura
En esta tabla se resume toda la información:
Instrucción | Dir alineada | Accesos escritura |
---|---|---|
store_byte x1, 0xBA05 | si | 1 |
store_byte x1, 0xBA1F | si | 1 |
store_byte x2, 0xBA10 | si | 1 |
store_half x3, 0xBA07 | no | 2 |
store_half x4, 0xBA0A | si | 1 |
store_half x5, 0xBA1D | x | 1 |
store_word x6, 0xBA01 | no | 2 |
store_word x7, 0xBA0F | no | 2 |
store_word x8, 0xBA18 | si | 1 |
Total | 12 accesos |
Ejercicio 5
En los ejercicios de teoría que haya que programar un Risc-V, no se pide el programa completo, sino sólo la parte del programa con las instrucciones que implementan lo pedido
- a)
a = h + A[8]
. Utiliza el registro t0 para la variable a
El enunciado nos proporciona la dirección base del array, que está en s0 y también la variable h, que está en el registro s1. Para implementar la expresión lo primero es obtener el elemento A[8] que está en memoria. Esto lo hacemos una instrucción de load-doble word (ld). El elemento del array a leer es el que tiene índice 8. Como es un array de dobles palabras, este elemento se encuentra en la dirección A + 8 * 8 (ya que una doble palabra son 8 bytes)
El código pedido es el siguiente:
ld t1, 64(s0) #-- t1 = A[8]
addi t0, s1, t1 #-- t0 = h + A[8]
- b)
A[12] = h + A[8]
. El resultado de h + A[8] se almacena en el propio array A, en el índice 12
Para almacenar h + A[8]
en la posición 12 del array hay que obtener su dirección: A + 12 * 8 = A + 96. En el apartado anterir ya tenemos en el registro t0 el resultado h + A[8]
, así que simplemente habrá que guardar t0 en la dirección A + 96 usando la instrucción store-double-word (sd). El programa completo es:
ld t1, 64(s0) #-- t1 = A[8]
addi t0, s1, t1 #-- t0 = h + A[8]
sd t0, 96(s0) #-- A[12] = h + A[8]
Ejercicio 6
El código será muy parecido en todos los casos: las acciones a realizar son las mismas, pero cambian los valores a multiplicar los índices de los arrays para acceder a los elementos. Hay que multiplicar por el tamaño en bytes de cada tipo de dato. En el caso de dobles palabras se multiplica por 8, para las palabras por 4, para las medias palabras por 2 y se multiplica por 1 para los bytes
- Apartado a) Los elementos del array son dobles palabras
Multiplicamos por 8. Usamos las instrucciones ld (load-double) y sd (store-double)
#-- Datos enunciado:
# -- s1 = i
#-- s2 = h
#-- s3 = A
li t0, 8
mul t1, s1, t0 #-- t1 = i * 8
add s4, s3, t1 #-- s4 = A + i * 8
ld t2, 0(s4) #-- t2 = A[i*8]
add t3, s2, t2 #-- t3 = h + A[i*8]
sd t3, 96(s3) #-- A[12] = h + A[i*8]
- Apartado b) Los elementos del array son palabras
Multiplicamos por 4. Usamos las instrucciones lw (load-word) y sw (store-word)
#-- Datos enunciado:
# -- s1 = i
#-- s2 = h
#-- s3 = A
li t0, 4
mul t1, s1, t0 #-- t1 = i * 4
add s4, s3, t1 #-- s4 = A + i * 4
lw t2, 0(s4) #-- t2 = A[i*4]
add t3, s2, t2 #-- t3 = h + A[i*4]
sw t3, 48(s3) #-- A[12] = h + A[i*4]
- Apartado c) Los elementos del array son medias palabras
Multiplicamos por 2. Usamos las instrucciones lh (load-half) y sh (store-half)
#-- Datos enunciado:
# -- s1 = i
#-- s2 = h
#-- s3 = A
li t0, 2
mul t1, s1, t0 #-- t1 = i * 2
add s4, s3, t1 #-- s4 = A + i * 2
lh t2, 0(s4) #-- t2 = A[i*2]
add t3, s2, t2 #-- t3 = h + A[i*2]
sh t3, 24(s3) #-- A[12] = h + A[i*2]
- Apartado d) Los elementos del array son bytes
No se multiplica (se usa el indice directamente). Usamos las instrucciones lb (load-byte) y sb (store-byte)
#-- Datos enunciado:
# -- s1 = i
#-- s2 = h
#-- s3 = A
li t0, 2
mv t1, s1, #-- t1 = i
add s4, s3, t1 #-- s4 = A + i
lb t2, 0(s4) #-- t2 = A[i]
add t3, s2, t2 #-- t3 = h + A[i]
sb t3, 12(s3) #-- A[12] = h + A[i]
Ejercicio 7
El código será muy parecido en todos los casos: las acciones a realizar son las mismas, pero cambian los valores a multiplicar los índices de los arrays para acceder a los elementos. Hay que multiplicar por el tamaño en bytes de cada tipo de dato. En el caso de dobles palabras se multiplica por 8, para las palabras por 4, para las medias palabras por 2 y se multiplica por 1 para los bytes
- Apartado a) Los elementos del array son dobles palabras
Multiplicamos por 8. Usamos las instrucciones ld (load-double) y sd (store-double)
#-- Datos enunciado:
#-- s1 = i
#-- s2 = h
#-- s3 = A
#-- s4 = B
li t0, 8
mul t1, s1, t0 #-- t1 = i * 8
add s5, s3, t1 #-- s5 = A + i * 8
ld t2, 0(s5) #-- t2 = A[i*8]
sub t3, s2, t2 #-- t3 = h - A[i*8]
sd t3, 96(s4) #-- B[12] = h - A[i*8]
- Apartado b) Los elementos del array son palabras
Multiplicamos por 4. Usamos las instrucciones lw (load-word) y sw (store-word)
#-- Datos enunciado:
#-- s1 = i
#-- s2 = h
#-- s3 = A
#-- s4 = B
li t0, 4
mul t1, s1, t0 #-- t1 = i * 4
add s5, s3, t1 #-- s5 = A + i * 4
lw t2, 0(s5) #-- t2 = A[i*4]
sub t3, s2, t2 #-- t3 = h - A[i*4]
sw t3, 48(s4) #-- B[12] = h - A[i*4]
- Apartado c) Los elementos del array son medias palabras
Multiplicamos por 2. Usamos las instrucciones lh (load-half) y sh (store-half)
#-- Datos enunciado:
#-- s1 = i
#-- s2 = h
#-- s3 = A
#-- s4 = B
li t0, 2
mul t1, s1, t0 #-- t1 = i * 2
add s5, s3, t1 #-- s5 = A + i * 2
lh t2, 0(s5) #-- t2 = A[i*2]
sub t3, s2, t2 #-- t3 = h - A[i*2]
sh t3, 24(s4) #-- B[12] = h - A[i*2]
- Apartado d) Los elementos del array son bytes
No se multiplica (se usa el indice directamente). Usamos las instrucciones lb (load-byte) y sb (store-byte)
#-- Datos enunciado:
#-- s1 = i
#-- s2 = h
#-- s3 = A
#-- s4 = B
mv t1, s1 #-- t1 = i
add s5, s3, t1 #-- s5 = A + i
lb t2, 0(s5) #-- t2 = A[i]
sub t3, s2, t2 #-- t3 = h - A[i]
sb t3, 12(s4) #-- B[12] = h - A[i]
Autores
- Katia Leal Algara
- Juan González-Gómez (Obijuan)