Repository navigation
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
Solución a los ejercicios de la Sesión L3
- 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
- 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
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
- 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
- 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
ecallEnsamblamos 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
- 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
ecallLo 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
- 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

- 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 bucleEn 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
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

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
ecallComprobamos 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

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
ecallLo 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)

- Katia Leal Algara
- Juan González-Gómez (Obijuan)


L1: El simulador RARs
L2: Calculando expresiones
L3: Práctica 1-3. Variables
L4: Pract 2-1. E/S mapeada
L5: Práctica 2-2: Inst. ecall
L6: Prác 2-3: Cadenas
L7: Práct 3-1: Bucles y saltos
L8: Práct 3-2: Cadenas II
L9: Pract 4-1: Subrut. Nivel-1
L10: Pract 4-2: La pila
L11: Pract 4-3: Recursividad
L12: Pract 5-1. Heap. Listas
L13: RV32I: Resto de instrucciones
L14: Macros
L15: Entrada/Salida a bajo nivel
L16: Multiplicaciones/divisiones. Unit Tests 🚧
L17: Biblioteca stdio: salida a alto nivel 🚧
Los registros de estado y control (CSR)
Interrupciones y excepciones
Borrador
Soluciones a los ejercicios planteados en cada sesión para practicar:
Sesión L1
Sesión L2
Sesión L3
Sesión L4
Sesión L5
Sesión L6
Sesión L7
Sesión L8
Sesión L9
Sesión L10
Sesión L11
Sesión L12
Simulacro examen 1
GISAM. Ordinario. 2019-Dic-11
GISAM. Extra. 2020-Jul-03
GISAM. Ordinario. 2021-Ene-21
GISAM. Ordinario. 2022-Ene-10
GISAM. Extra. 2022-Jun-29
GISAM. Parcial 1. 2022-Oct-26
GISAM. Parcial 2. 2022-Nov-30
GISAM. Parcial 3. 2022-Dic-21
GISAM. Parcial 1. 2023-Oct-09
GISAM. Parcial 2. 2023-Nov-11
GISAM. Parcial 3. 2023-Dic-20
GISAM. Extra. 2024-Jun-17
GISAM. Parcial 1. 2024-Oct-14
GISAM. Parcial 2. 2024-Nov-13
GISAM. Parcial 3. 2024-Dic-16
GISAM. Extra. 2025-Jun-17
GISAM. Parcial 1. 2025-Oct-20
GISAM. Parcial 2. 2025-Nov-19
GISAM. Parcial 3. 2026-Enero-9
GISAM. Parcial 1. 2026-Oct-21
TELECO. Ordinario. 2019-Dic-13
TELECO. Extra. 2020-Jul-07
TELECO. Ordinario. 2021-Ene-21
TELECO. Extra. 2021-Jul-02
TELECO. Ordinario. 2022-Ene-10
TELECO. Extra. 2022-Jun-29
TELECO. Ordinario. 2023-Ene-10
TELECO. Extra. 2023-Jun-29
TELECO. Parcial 1. 2023-Oct-20
TELECO. Parcial 2. 2023-Nov-17
TELECO. Parcial 3. 2023-Dic-22
TELECO. Extra. 2024-Jun-17
TELECO. Parcial 1. 2024-Oct-10
TELECO. Parcial 2. 2024-Nov-21
TELECO. Parcial 3. 2024-Dic-19
TELECO. Extra. 2025-Jun-17
TELECO. Parcial 1. 2025-Oct-10
TELECO. Parcial 2. 2025-Nov-13
TELECO. Parcial 3. 2026-Ene-21
TELECO. Extra. 2026-Jun-25
TELECO. Parcial 1. 2026-Oct-09
Robótica. Ordinario. 2020-Jun-1
Robótica. Extra. 2020-Jul-13
Robótica. Ordinario. 2021-Mayo-20
Robótica. Extra. 2021-Junio-16
Robótica. Parcial 1. 2022-Feb-25
Robótica. Parcial 2. 2022-Abril-1
Robótica. Parcial 3. 2022-Mayo-6
Robótica. Parcial 1. 2023-Feb-27
Robótica. Parcial 2. 2023-Mar-27
Robótica. Parcial 3. 2023-May-08
Robótica. Parcial 1. 2024-Feb-26
Robótica. Parcial 2. 2024-Mar-20
Robótica. Parcial 3. 2024-May-06
Robótica. Extra. 2024-Junio-24
Robótica. Parcial 1. 2025-Feb-25
Robótica. Parcial 2. 2025-Mar-31
Robótica. Parcial 3. 2025-May-19
Robótica. Parcial 1. 2026-Feb-23
Robótica. Parcial 2. 2026-Abr-13
Robótica. Parcial 3. 2026-May-11
Datos. Parcial 1. 2023-Oct-09
Datos. Parcial 2. 2023-Nov-15
Datos. Parcial 3. 2023-Dic-20
Datos. Parcial 1. 2024-Oct-09
Datos. Parcial 2. 2024-Nov-13
Datos. Parcial 3. 2025-Ene-17
Datos. Parcial 1. 2025-Oct-15
Datos. Parcial 2. 2025-Nov-19