SOLUCIONES a los ejercicios - myTeachingURJC/2019-20-LAB-AO GitHub Wiki
Práctica 1: Soluciones a los ejercicios
Soluciones comentadas a los ejercicios propuestos en las sesiones de la prácticas 1. Antes de ver las soluciones es importante que hayas intentado hacer los ejercicios por tu cuenta
Contenido
Práctica 1
Sesión 1
Solución a los ejercicios de la Sesión de laboratorio 1-1
Ejercicio 1
La instrucción para hacer una asignación a un registro es addi, usando como registro fuente el x0
# Solucion a la actividad no guiada 1
#-- Asignar los siguientes valores a los registro indicados:
#-- x3=3, x4=4, x5=5, x6=6, x7=7 y x8=8
.text
addi x3, x0, 3 # x3 = 3
addi x4, x0, 4 # x4 = 4
addi x5, x0, 5 # x5 = 5
addi x6, x0, 6 # x6 = 6
addi x7, x0, 7 # x7 = 7
addi x8, x0, 8 # x8 = 8
#-- Terminar
li a7, 10
ecall
Nota avanzada: En la sesión 3 vimos que estas mismas asignaciones las podemos hacer con la pseudo-instrucción li. Es el programa ensamblador el que la convierte en la instrucciónn addi equivalente. El programa sería:
# Solucion a la actividad no guiada 1
#-- También se puede usar la pseudo-instruccion li
#-- El programa queda más sencillo:
.text
li x3, 3 # x3 = 3
li x4, 4 # x4 = 4
li x5, 5 # x5 = 5
li x6, 6 # x6 = 6
li x7, 7 # x7 = 7
li x8, 8 # x8 = 8
#-- Terminar
li a7, 10
ecall
En ambos casos comprobamos que el programa funciona correctamente simulándolo y viendo el valor de sus registros en la parte derecha:
Ejercicio 2
Basta con sustituir la instrucción addi x5, x5, 1 por addi x5, x5, 2. De esta forma en cada vuelta del bucle se realizará la operación x5 = x5 + 2, en vez de x5 = x5 + 1
# Solucion a la actividad no guiada 2
#-- Programa contador que se incremete de dos en dos
.text
#-- Inicializar el regitro x5 a 0
addi x5, x0, 0
bucle:
#-- Incrementar x5 en dos unidades
#-- x5 = x5 + 2
addi x5, x5, 2
#-- Repetir indefinidamente
b bucle
Lo simulamos para comprobar que funciona correctamente. Nos fijamos en el registro x5: Efectivamente sólo toma los valores pares
Ejercicio 3
Partimos del ejemplo del contador. Es la misma estructura. Sólo hay que inicializar los tres regisros a cero y añadir los incrementos en el bucle
# Solucion a la actividad no guiada 3
# El registro x3 toma los valores 0,1,2,3,4,5...
# El x4: 0,3,6,9,12,15...
# El x5 0,5,10,15,20,25....
#-- Se repite indefinidamente
.text
#-- Inicializar los registros a 0
addi x3, x0, 0
addi x4, x0, 0
addi x5, x0, 0
bucle:
#-- Incrementar x3 en una unidad: x3 = x3 + 1
addi x3, x3, 1
#-- Incrementar x4 en 3 unidades: x4 = x4 + 3
addi x4, x4, 3
#-- Incrementar x5 en 5 unidades: x5 = x5 + 5
addi x5, x5, 5
#-- Repetir indefinidamente
b bucle
Al simularlo comprobamos que efectivamente está funcionando correctamente. El registro x3 se incrementa de uno en uno, empezando en 0. El x4 de 3 en 3, también empezando desde cero. Y el x5 de 5 en 5, comenzando por 0
Ejercicio 4
Las dos acciones que nos piden, inicializar y restar 1, las realizamos con la operacion de suma addi
# Solucion a la actividad no guiada 4
# programa que ejecute las siguientes acciones:
# * Inicializar el registro 6 a 0
# * Restarle 1
# * Terminar
.text
#-- Inicializar registro 6 a 0
addi x6, x0, 0
#-- Restar 1
addi x6, x6, -1
#-- Terminar
li a7, 10
ecall
Para entender mejor el valor de x6 al restar 1, activamos la opción de ver los registros en hexadecimal y observamos que vale 0xFFFFFFFF (todos los bits a 1). Este es el valor de -1 en complemento a dos
Ejercicio 5
Se trata de una cuenta atrás. El registro x3 comienza en 10, se va decrementando hasta llegar a 0, y termina
Ejercicio 6
Este programa implementa la multiplicación de dos registros, utilizando sumas. En los registros x5 y x6 se introducen los dos números a multiplicar. El resultado se devuelve en x7
# Es un programa que implementa la multiplicacion
# de dos registros, usando sumas
# En los registros x5 y x6 se introducen los dos numeros
# a multiplicar. El resultado se devuelve en x7
# Asi, el resultado de este programa es x7 = 5 * 6 = 30
Ejercicio 7
El objetivo de este ejercicio es familiarizarnos con los mensajes de error del ensamblador. Muchas veces al producirse un error es difícil encontrar a qué es debido
Al introducir el programa en el simulador y ensamblarlo, obtenemos este error:
Es debido a una errata en los comentarios. En vez del símbolo #, se ha introducido ;. La línea correcta sería esta:
beq x17,x0,fin #-- Comprueba terminacion
Lo mismo ha ocurrido en el otro comentario. En los ensambladores de otros microprocesadores, el símbolo ; se utiliza para introducir comentarios, pero en el RISC-V se usa #
El siguiente error es una errata al escribir la instrucción addi. La última i se ha duplicado
En la línea 8 hay otra errata. La x del registro x7 se ha duplicado
El último error es por la utilización de una etiqueta NO definida: hola. Debería ser a
Ahora lo podemos simular y comprobar qué es lo que hace: calcula los múltiplos de 8, en el registro x7. Saca 10 múltiplos, por lo que en realidad es la tabla de multiplicar del 8
Sesión 2
Solución a los ejercicios de la Sesión de laboratorio 1-2
Ejercicio 1
- Tiene 5 instrucciones en código máquina. Para comprobarlo hay que ensamblar el programa y contar el número de filas de la columna que pone Code
-
El programa tiene 5 instrucciones. Cada instrucción ocupa 4 bytes. Por tanto, su tamaño es de 5 * 4 = 20 bytes
-
Tabla
Direccion (alineada) | Instrucción en código máq. |
---|---|
0x00400000 | 00000293 |
0x00400004 | 00000313 |
0x00400008 | 00128293 |
0x0040000c | 00530333 |
0x00400010 | ff9ff06f |
- Tabla
Dirección | Byte |
---|---|
0x004000 | 93 |
0x004001 | 02 |
0x004002 | 00 |
0x004003 | 00 |
0x004004 | 13 |
0x004005 | 03 |
0x004006 | 00 |
0x004007 | 00 |
0x004008 | 93 |
0x004009 | 82 |
0x00400a | 12 |
0x00400b | 00 |
0x00400c | 33 |
0x00400d | 03 |
0x00400e | 53 |
0x00400f | 00 |
0x004010 | 6f |
0x004011 | f0 |
0x004012 | 9f |
0x004013 | ff |
- El valor obtenido es de 325
Ejercicio 2
- Este es el programa que calcula la suma de los enteros pares
#-- Solucion al ejercicio 2
#-- Calcular la suma de los numeros pares
#-- 2 + 4 + 6 + 8 + 10 + ....
.text
#-- Inicializamos los registros x5,x6 a 0
addi x5, x0, 0
addi x6, x0, 0
#-- Bucle principal
bucle:
#-- Incrementar contador principal en dos unidades
addi x5, x5, 2 #-- x5 = x5 + 2
#-- Obtener termino i-esimo
add x6, x6, x5 #-- x6 = x6 + x5
#-- Repetir el bucle
b bucle
-
El número de instrucciones varía de una implementación a otra (Tu programa puede tener un número diferente). Este tiene 5 instrucciones
-
Tiene 5 instrucciones. Cada instrucción ocupa 4 bytes. El tamaño que ocupa es de 5 * 4 = 20 bytes
-
La tabla con las instrucciones en código máquina, y en qué dirección se encuentra cada una se muestra en esta tabla. Esta es la tabla del programa implementado en el punto 1 (tu programa puede tener otras instrucciones diferentes)
Direccion (alineada) | Instrucción en código máq. |
---|---|
0x00400000 | 00000293 |
0x00400004 | 00000313 |
0x00400008 | 00228293 |
0x0040000c | 00530333 |
0x00400010 | ff9ff06f |
- El valor obtenido es: 650
Ejercicio 3
- Programa que calcula la sucesión de Fibonacci:
#-- Calculo de la serie de fibonacci: 0, 1, 1, 2, 3, 5, 8, 21...
#-- La serie se puede ver en el registro x7
#-- x5 y x6 se utilizan para los calculos intermedios
.text
#-- Valores iniciales, 1, 1
addi x5, x0, 0
addi x6, x0, 1
bucle:
#-- Calcular siguiente término en t2
add x7, x5, x6 # x7 = x5 + x6
#-- Actualizar registros
add x5, x6, x0 #-- x5 = x6
add x6, x7, zero #-- x6 = x7
b bucle
-
El valor del término 10 de fibonacci es 55 (Se obtiene cuando el bucle ha dado 8 vueltas porque en la primera se tiene el término 3. Los términos 1 y 2 son 0 y 1 respectivamente, que son los valores iniciales)
-
Esta implementación del programa tiene 6 instrucciones. La tuya puede tener un número diferente
-
Como tiene *6 instrucciones, y cada instrucción ocupa 4 bytes, el tamaño del programa es de 6 * 4 = 24 Bytes
-
Tabla con el código máquina:
Direccion (alineada) | Instrucción en código máq. |
---|---|
0x00400000 | 0x00000293 |
0x00400004 | 0x00100313 |
0x00400008 | 0x006283b3 |
0x0040000c | 0x000302b3 |
0x00400010 | 0x00038333 |
0x00400014 | 9xff5ff06f |
- Tabla con los bytes del programa
Dirección | Byte |
---|---|
0x004000 | 93 |
0x004001 | 02 |
0x004002 | 00 |
0x004003 | 00 |
0x004004 | 13 |
0x004005 | 03 |
0x004006 | 10 |
0x004007 | 00 |
0x004008 | b3 |
0x004009 | 83 |
0x00400a | 62 |
0x00400b | 00 |
0x00400c | b3 |
0x00400d | 02 |
0x00400e | 03 |
0x00400f | 00 |
0x004010 | 33 |
0x004011 | 83 |
0x004012 | 03 |
0x004013 | 00 |
0x004014 | 6f |
0x004015 | f0 |
0x004016 | 5f |
0x004017 | ff |
Ejercicio 4
## Programa para calcular la expresion:
## f = (a + b + c) - [(d - a) + (e + 3) - 30]
## Valores iniciales de prueba: a=2, b=4, c=6, d=8, e=10
.text
#-- Valores iniciales
addi x5,x0,2 #-- x5 = a = 2
addi x6,x0,4 #-- x6 = b = 4
addi x7,x0,6 #-- x7 = c = 6
addi x8,x0,8 #-- x8 = d = 8
addi x9,x0,10 #-- x9 = e = 10
#-- Calcular la expresion. Resultado en X10
add x11, x5, x6 #-- x11 = a + b
add x11, x11,x7 #-- x11 = (a + b + c)
sub x12, x8, x5 #-- x12 = (d - a)
addi x13, x9, 3 #-- x13 = (e + 3)
addi x14, x13, -30 #-- x14 = (e + 3) - 30
add x15, x12, x14 #-- x15 = [(d - a) + (e + 3) - 30]
#-- Resultado final
sub x10, x11, x15 #-- x10 = (a + b + c) - [(d - a) + (e + 3) - 30]
#-- Terminar
li a7, 10
ecall
Para el valor de las variables a=2, b=4, c=6, d=8, e=10, se obtiene que f = 23
Ejercicio 5
- La expresión que se calcula es: x10 = 2x5 + 4x6 - (x7 - x8) + 15
El término 2*x5 se obtiene porque se suma x5 con x5:
add x5, x5, x5 #-- x5 = X5 + X5 = 2*x5
El término 4*x6 se obtiene por estas dos instrucciones:
add x6, x6, x6 #-- x6 = 2*x6
add x6, x6, x6 #-- x6 = 2* (2*x6)
Si asignamos las variables a los registros de esta forma: x10 = f, x5=a, x6=b, x7=c, x8=d, tenemos que la expreión es: f = 2a + 4b - (c - d) + 15
-
Se prueba con los valores a=3, b=5, c=7, d=9, que son los que se utilizan al comienzo para inicializar los registros x5,x6,x7 y x8
-
El resultado es 43
-
El valor de la posición de memoria 0x00400015 es 03. Lo comprobamos muy fácilmente buscando la palabra alineada inferior (Dirección 0x00400014) y aplicando el criterio Little endian sacamos el valor
- El programa tiene 13 instrucciones. Cada instrucción es de 4 bytes. Por tanto ocupa 13 * 4 = 52 bytes
Ejercicio 6
- Obtener el código máquina de las instrucciones es muy sencillo usando directamente el ensamblador. Las copiamos al RARs, las ensamblamos y obtenemos el código máquina:
Estas son las dos instrucciones en código máquina
addi x0, x0, 0 -----> 0x00000013
addi x0, x0, 0xFA ---> 0x0FA00013
- Solo se diferencian en los caracteres hexadecimales FA. Parece
que esos bits codifican el valor inmediato de la instrucción addi
Si eso es cierto, el código máquina de la instruccio addi x0,x0,0xBB seria 0x0BB00013. Vamos a comprobarlo con el simulador:
¡Exacto! ¡es esa misma! :smile:
- Obtenemos el código máquina de las dos instrucciones, usando el simulador:
addi x0, x1, 0 --> 0x00008013 --> 0000 0000 0000 0000 1000 0000 0001 0011
addi x0, x2, 0 --> 0x00010013 --> 0000 0000 0000 0001 0000 0000 0001 0011
==== ==== ==== ===x x=== ==== ==== ====
Solo se diferencian en 2 bits: el 15 y el 16. Parece que esos bits codifican el número de registro
- Obtenemos el código máquina de las dos instrucciones, con el simulador:
addi x0, x0, 0 ---> 0x00000013 --> 0000 0000 0000 0000 0000 0000 0001 0011
addi x31, x0, 0 --> 0x00000F93 --> 0000 0000 0000 0000 0000 1111 1001 0011
==== ==== ==== ==== ==== xxxx x=== ====
Parece que el número de registro se codifica los bits 7-11 (5 bits)
El registro 0 tiene esos 5 bits a 0: 00000
El registro 31 tiene esos 5 bits a 1: 11111
Ejercicio 7
Por definición, la etiqueta es un símbolo que se corresponde con una dirección de memoria. Los humanos, en vez de trabajar con direcciones numéricas, que nos resultan complejas, trabajamos con etiquetas. Es el ensamblador el que tiene una tabla de símbolos en la que hace la conversion de humano a máquina
Etiqueta | Dirección |
---|---|
ini | 0x00400000 |
a | 0x00400000 |
b | 0x0040000C |
c | 0x0040001C |
d | 0x00400028 |
fin | 0x00400030 |
last | 0x00400034 |
Ejercicio 8
El PC vale 0x0040000C. Esto significa que la siguiente instrucción que
se ejecutará será la que esté en esa dirección... que es: addi x8, x8, 9
Podemos ver rápidamente qué instrucción está en cada dirección ensamblando el programa y viendo la instrucción de la dirección 0x0040000C
Ejercicio 9
Como la etiqueta vale 0x00502020, sabemos que esa es la direccion
de la primera instrucción del fragmento. A partir de ese valor
podemos calcular las demás:
Etiqueta | Direccion |
---|---|
b | 0x00502020 |
c | 0x00502030 |
d | 0x0050203C |
fin | 0x00502044 |
Ejercicio 10
#-- Programa en ensamblador para calcular la expresion:
#-- f = (d - c) + 15 - (a + b)
#-- Probarlos con las siguientes secuencias de valores:
#-- a=1,2,3,4,5...
#-- b=2,3,4,5,6..
#-- c=3,4,5,6,7..
#-- d=4,5,6,7,8..
.text
#--- Inicializacion
addi x5,x0,1 #-- x5 = a
addi x6,x0,2 #-- x6 = b
addi x7,x0,3 #-- x7 = c
addi x8,x0,4 #-- x8 = d
bucle:
#-- calcular la expresion
sub x11, x8, x7 #-- x11 = (d - c)
addi x11,x11,15 #-- x11 = (d - c) + 15
add x12,x5,x6 #-- x12 = (a + b)
sub x13, x11,x12 #-- x13 = (d - c) + 15 - (a + b)
nop #-- No hace nada. Se usa para poner aqui el Breakpoint
#-- Incrementar x5,x6,x7 y x8
addi x5,x5,1 #-- a = a+1
addi x6,x6,1 #-- b = b+1
addi x7,x7,1 #-- c = c+1
addi x8,x8,1 #-- d = d+1
#-- Repetir. Siguiente iteraccion
b bucle
En la decima iteracion, los valores iniciales son:
a=10,
b=11,
c=12,
d=13
El valor calculado es -5, que es correcto
Sesión 3
Solución a los ejercicios de la Sesión de laboratorio 1-3
Ejercicio 1
- El objetivo de este ejercicio es familiarizarse con las pseudo-instrucciones li y mv. Si se ejecuta el programa completamente, veremos que todos los resultados son correctos, salvo el del registro x17, que contedrá el valor 10 en vez de 7. En la práctica 2 veremos la causa
#-- Ejercicio 1
#-- Inicializacion de los registros x5-x8
#-- Transferencia a los registros x15-x18
#-- Para inicializar los registros y hacer
#-- transferencias no necesitamos usar
#-- el segmento de datos. El enunciado no
#-- nos expecifica que los valores de inicializacion
#-- deban estar almacenados en memoria
#-- Por tanto, solo hay segmento de codigo
#-- y NO de datos
.text
#-- Inicializar los registros
li x5, 5
li x6, 6
li x7, 7
li x8, 8
#-- Transferir los valores a los
#-- registros x15-x18
mv x15, x5
mv x16, x6
mv x17, x7
mv x18, x8
#-- Terminar
#-- ¡OJO! se modifica el registro x17
li a7, 10
ecall
-
El programa contiene 10 instrucciones en total
-
Ocupa 10 * 4 = 40 bytes
-
Al exportarlo a un fichero de hexadecimal de texto, obtenemos esto:
00500293
00600313
00700393
00800413
005007b3
00600833
007008b3
00800933
00a00893
00000073
Ejercicio 2
- Para saber las palabras almacenadas sólo hay que buscar las directivas .word del segmento de datos y contar el número total de palabras que hay. En este ejemplo hay en total 7 palabras, inicializadas con los valores 1,2,3,4,10,20 y 30. Las etiquetas NO definen palabras. Son simples alias para las direcciones de memoria
En este pantallazo se marcan todas las palabras definidas en el segmento de datos
-
Puesto que hay 7 palabras, y cada palabra ocupa 4 bytes, en segmento de datos ocupa un total de 7 * 4 = 28 bytes
-
Cuando nos piden el tamaño del programa, se refieren siempre a la parte del segmento de código. En este caso hay 2 instrucciones, por lo que el programa ocupa 8 bytes
-
Las direcciones de las etiquetas las obtenemos directamente de la tabla de símbolos del simulador:
Por tanto la solución es esta:
Etiqueta | Dirección |
---|---|
a | 0x10010000 |
b | 0x10010000 |
c | 0x10010010 |
d | 0x10010018 |
e | 0x1001001c |
- Ensamblamos el programa y miramos en la ventana del segmento de datos, en la dirección 0x10010014:
El valor almacenado es 20 (en decimal) ó 0x14 en hexadecimal
- Teniendo en cuenta que se usa el convenio Little-endian (los bytes de menor peso se almacenan en las direcciones más bajas), los bytes que se encuentran en las direcciones pedidas son:
Dirección | Byte |
---|---|
0x10010000 | 01 |
0x10010001 | 00 |
0x10010002 | 00 |
0x10010003 | 00 |
0x10010004 | 02 |
0x10010005 | 00 |
0x10010006 | 00 |
0x10010007 | 00 |
--------- | ----- |
0x10010018 | 30 |
0x10010019 | 00 |
0x1001001A | 00 |
0x1001001B | 00 |
- Si volcamos el segmento de datos a un fichero hexadecimal, obtenemos:
00000001
00000002
00000003
00000004
0000000a
00000014
0000001e
00000000
00000000
00000000
00000000
...
00000000
Se vuelcan las primeras 4KiB. Las 7 primeras palabras son las que hay en el programa. El resto de posiciones de memoria están a cero
Ejercicio 3
El programa que nos piden es el siguiente. Nos dan los nombres de las variables: v1, v2, v3 y v4: son las etiquetas que utilicemos para acceder a sus valores
#-- Programa para crear 4 variables
#-- inicializadas a unos valores
#-- Segmento de datos
.data
v1: .word 0x12345678
v2: .word 0x11223344
v3: .word 0xCACABACA
v4: .word 0x00FABADA
#-- Segmento de código
.text
li a7, 10
ecall
- Ensamblamos el programa y comprobamos que efectivamente las primeras 4 palabras tienen los valores que nos han indicado:
- Exportamos el segmento de datos a un fichero hexadecimal de texto. Las cuatro primeras posiciones contienen:
12345678
11223344
cacabaca
00fabada
- Con el comando hd vemos:
00000000 78 56 34 12 44 33 22 11 ca ba ca ca da ba fa 00 |xV4.D3".........|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001000
El byte que se encuentra en la quinta posición es: 0x44. Está en la dirección de memomria: 0x10010004
Ejercicio 4
- El programa es:
#-- Cargar las direcciones de las
#-- variables en los registros x5-x8
#-- Variables en el seg. de datos
.data
a: .word 0
b: .word 0
c: .word 0
d: .word 0
#-- Segmento de código
.text
#-- Obtener las direcciones
la x5, a
la x6, b
la x7, c
la x8, d
#-- Terminar
li a7, 10
ecall
- Ensamblamos y abrimos la tabla de símbolos
Las direcciones son:
0x10010000
0x10010004
0x10010008
0x1001000C
- Ensamblamos el programa. Hay 10 instrucciones en código máquina:
Por tanto el programa ocupa 10 * 4 = 40 bytes
Ejercicio 5
- Este es el programa modificado. Las variables se inicializan directamente en el segmento de datos. Una vez que se tienen sus direcciones en los registros x5,x6,x7 y x8, se procede a cargar sus valores en los registros x10,x11,x12 y x13 utilizando la instrucción de carga de palabras: lw
#-- Cargar las direcciones de las
#-- variables en los registros x5-x8
#-- Inicializa los registros x10-x13 con los valores de
#-- las variables
#-- Variables en el seg. de datos
.data
a: .word 1
b: .word 2
c: .word 3
d: .word 4
#-- Segmento de código
.text
#-- Obtener las direcciones
la x5, a
la x6, b
la x7, c
la x8, d
#-- Inicializar los registros
lw x10, 0(x5) #-- x10 = a
lw x11, 0(x6) #-- x11 = b
lw x12, 0(x7) #-- x12 = c
lw x13, 0(x8) #-- x13 = d
#-- Terminar
li a7, 10
ecall
Ensamblamos y ejecutamos el programa. Podemos ver los valores de las variables en memoria y cómo se han cargado en los respectivos registros
- El programa tiene 14 instrucciones. Por tanto ocupa: 14 * 4 = 56 bytes
Ejercicio 6
- El nuevo programa es el siguiente. Aunque están definidas las etiquetas b,c y d, sólo usamos la de a para inicializar el puntero en x5. A partir de él, podemos acceder a todas las variables mediante 0(x5), 4(x5), 8(x5) y 12(x5)
#-- Inicializa los registros x10-x13 con los valores de
#-- las variables. En x5 se debe situar la direccion de la variable a
#-- y usarlo para acceder al resto de variables
#-- Variables en el seg. de datos
.data
a: .word 1
b: .word 2
c: .word 3
d: .word 4
#-- Segmento de código
.text
#-- Obtener la direccion de a
la x5, a
#-- Inicializar los registros
lw x10, 0(x5) #-- x10 = a
lw x11, 4(x5) #-- x11 = b
lw x12, 8(x5) #-- x12 = c
lw x13, 12(x5) #-- x13 = d
#-- Terminar
li a7, 10
ecall
Lo ensamblamos y lo ejecutamos. Comprobamos que funciona correctamente, cargando en los registros x10-x13 los valores iniciales de las varaibles
-
Este programa hace lo mismo que el del ejercicio 5, pero sólo tiene 8 instrucciones, por lo que ocupa: 8 * 4 = 32 bytes.
-
Este programa es más optimo que el anterior, ya que ocupa menos espacio. Por ello, siempre que tengamos variables contiguas de memoria, es más óptimo acceder a ellas usando un único puntero
Ejercicio 7
- El programa se puede implementar de muchas formas. Pero, teniendo en cuenta los resultados de los ejercicios anteriores, usamos un único puntero para acceder a las variables, por lo que el programa será más óptimo
#-- Programa para calcular la expresion f = (a + b + c) - (d - 3)
#-- Variables
.data
a: .word -5
b: .word 2
c: .word 30
d: .word 5
f: .word 0
#-- Segmento de código
.text
#-- Para calcular la expresion usaremos los sig. registros:
#-- x5 = a
#-- x6 = b
#-- x7 = c
#-- x8 = d
#-- x12 = f
#-- Leer las variables y las situamos en los registros
la x4, a #-- Usamos x4 como puntero para acceder a las varaibles
lw x5, 0(x4) #-- x5 = a
lw x6, 4(x4) #-- x6 = b
lw x7, 8(x4) #-- x7 = c
lw x8, 12(x4) #-- x8 = d
#-------------- Calcular la expresión
add x9, x5, x6 #-- x9 = a + b
add x9, x9, x7 #-- x9 = a + b + c
addi x10, x8, -3 #-- x10 = d - 3
sub x12, x9, x10 #-- x12 = (a + b + c) - (d - 3)
#-- Almacenar el resultado en f
sw x12, 16(x4) #-- f = (a + b + c) - (d - 3)
#-- Terminar
li a7, 10
ecall
- Lo ensamblamos y lo ejecutamos. El valor obtenido en f es correcto: 25
-
El programa tiene 13 instrucciones, por lo que ocupa 13 * 4 = 52 ybtes
-
En el pantallazo anterior se puede ver. Es la variable que se encuentra en la quinta posición. Su dirección es la 0x10010010. También lo podemos ver mostrando la tabla de símbolos
Ejercicio 8
- Este es el programa que calcula la sucesión de fibonacci, dejando los términos calculaos en palabras consecutivas del segmento de datos
#-- Calcular la sucesion de fibonacci
#-- Almacenarla en el segmento de datos,
#-- en palabras consecutivas
.data
#-- Valores iniciales de la secuencia de fibonacci
fib0: .word 0
fib1: .word 1
.text
#-- Puntero para acceder a los datos
la x5, fib0
#-- Los terminos de Fibonacci estan en los registros x10 y x11
lw x10, 0(x5) #-- Primer termino de fibonacci
lw x11, 4(x5) #-- Segundo termino de fibonacci
#-- x5 es el puntero hacia el siguiente termino de fibonacci en memoria
addi x5, x5, 8
bucle:
#-- Obtener el siguiente termino de Fibonacci
add x12, x10, x11
#-- Almacenarlo en la memoria, en la direccion apuntada por x5
sw x12, 0(x5)
#-- Incrementar el puntero x5 para apuntar a la siguiente palabra
addi x5, x5, 4
#-- Actulizar los terminos anteriores de fibonacci
mv x10, x11
mv x11, x12
#-- Repetir
b bucle
En esta animación se muestra la simulación del programa, y cómo está funcionando correctamente
- Al ejecutarlo sin breakpoint, al cabo de un tiempo vemos que le programa se para y aparece un error en la consola
Si miramos en la parte de la derecha, el error dice:
line 29: Runtime exception at 0x00400018: address out of range 0x10400000
Estamos usando un bucle infinito, por lo que se va rellenando el segmento de datos indefinidamente. Hasta llegar a su límite: estamos intentando acceder a una dirección que está fuera del segmento de datos
Ejercicio 9
Se puede probar bien poniendo un breakpoint y ejecutando manualmente, o bien bajando la velocidad y que se ejecute sin breakpoint. Se comprueba que efectivamente se está accediendo secuencialmente a la memoria. En esta animación se muestra en acción
Ejercicio 10
Nos piden un programa que escriba el valor 0xAA5555AA en ciertas palabras del segmento de datos: en la primera (1), cuarta, quinta y octava. Esas direcciones se corresponden con los desplazamientos (offsets): 0, 0xC, 0x10 y 0x1C. Sólo hay que usar un puntero que tenga la dirección de la primera palabra y escribir el valor patrón en esos offsets:
#-- Comprobacion de la memoria
#-- Este programa debe escribir un valor en las palabras
#-- de la memoria 0, 3, 4 y 7
.data
memoria:
.text
#-- Puntero para acceder a la memoria, en x5
la x5, memoria
#-- Valor de test a escribir:
li x10, 0xAA5555AA
#-- Escribir en la primera posicion
sw x10, 0(x5)
#-- Escribir en la cuarta palabra
sw x10, 0xC(x5)
#-- Escribir en la quinta palabra
sw x10, 0x10(x5)
#-- Escribir en la octava palabra
sw x10, 0x1C(x5)
#-- Terminar
li a7, 10
ecall
Comprobamos que al ejecutarlo efectivamente se obtiene el patrón pedido, y también vemos que en las posiciones indicadas se ha escrito el valor 0xAA5555AA
Ejercicio 11
Para obtener ese patrón de acceso a memoria podemos bien escribir cualquier valor en esas posiciones, o bien leerlo. La herramienta de visualización de memoria nos hace el recuento de los accesos en lectura y/o escritura. Usamos por ejemplo escrituras, como en el ejercicio anterior
Lo que tenemos que calcular son los desplazamientos necesarios para acceder a las posiciones de memoria pedidas. Cada cuadrado es una palabra, y en cada línea hay 16 palabras: 16 * 4 = 64 bytes. Si se incrementa el offset en 64, se accede al cuadrado que está debajo, en la siguente fila
A partir de esto vamos calculando los offsets de las 9 posiciones pedidas:
#-- Generar un "smiley" en el monitor
#-- de acceso a memoria :-)
.data
memoria:
.text
#-- Puntero al comienzo del segmento de datos
la x5, memoria
#-- Valor a almacenar en las posiciones de memoria
#-- vale cualquiera
li x10, 1
#-- Ojos
sw x10, 0x48(x5)
sw x10, 0x50(x5)
sw x10, 0x88(x5)
sw x10, 0x90(x5)
#-- Parte superior sonrisa
sw x10, 0x104(x5)
sw x10, 0x114(x5)
#-- Parte inferior sonrisa
sw x10, 0x148(x5)
sw x10, 0x14C(x5)
sw x10, 0x150(x5)
#-- Terminar
li a7, 10
ecall
Lo ensamblamos y lo ejecutamos. Vemos que el patrón que aparece es el pedido. También podemos ver los valores almacenados en el segmento de datos (en las 9 posiciones)
Autores
- Katia Leal Algara
- Juan González-Gómez (Obijuan)