Examen: Parcial 2:2024_12_19:TELECO - myTeachingURJC/2019-20-LAB-AO GitHub Wiki
Examen Parcial 3: 2024-12-19. Teleco
- Tiempo: 50 minutos
- Descripción: Examen Parcial 3. Laboratorio. Grados de Telecomunicaciones
- Fecha: 2024/Dic/19
- Temario: Sesiones L9,L10
Contenido
Enunciado
El examen se ha realizado a través de Aula virtual
Programa (10 ptos)
Escribe un programa en ensamblador del Riscv para calcular el mínimo entre dos números introducidos por el usuario. Este programa está compuesto por un programa principal y 2 funciones
-
Función min(n1,n2): Esta función calcula el valor mínimo entre dos números enteros, y lo devuelve. Tiene, por tanto, dos parámetros de entrada y una salida. NO imprime nada en la consola
-
Función print_min(n1,n2). Función para imprimir en la consola el valor mínimo de dos números, en el formato: "Min(n1,n2)=min\n", donde n1 es el primer número introducido por el usuario, n2 el segundo y min es el valor mínimo entre ambos. Se debe llamar a la función min(n1,n2) para calcular el valor mínimo, y luego imprimirlo en la consola en el formato indicado. La función NO tiene ningún parámetro de salida
El programa principal implementa el siguiente algoritmo:
- Pedir el primer numero al usuario (n1)
- Si este número es -1, terminar
- Pedir segundo numero al usuario (n2)
- Llamar a la funcion print_min(n1,n2) para imprimir el número mínimo
- Repetir desde el paso 1
En este pantallazo se muestra el funcionamiento del programa cuando el usuario introduce tres pares de números y luego -1 para terminar
Se Pide:
a) (3 ptos). Implementa la función min(n1,n2) en el fichero min.s
b) (3 ptos). Implementa la función print_min(n1,n2) en el fichero print_min.s
c) (4 ptos). Implementa el programa principal en el fichero main.s
NOTA: Todas las constantes necesarias para los servicios del sistema operativo deberán estar en el fichero so.s
NOTA: Ficheros a entregar:
- so.s
- min.s
- print_min.s
- main.s
Solución al programa
- Fichero min.s:
#----------------------------------------------------------------
#-- Funcion min(n1, n2): Calcular el valor mínimo entre n1 y n2
#-------------------------------
#-- ENTRADAS:
#-- * n1 (a0): Primer numero
#-- * n2 (a1): Segundo numero
#-- SALIDAS:
#-- * Numero minimo (a0)
#----------------------------------------------------------------
.globl min
.text
min:
#-- Si n1 < n2, min(n1,n2)=n1
blt a0,a1, fin
#-- n2 >= n1, min(n1,n2)=n2
mv a0,a1
fin:
ret
- Fichero print_min.s:
.include "so.s"
#-----------------------------
#-- print_min(n1,n2)
#--
#-- Imprimir el mensaje: "MIN(n1, n2)=min"
#--------------------------------------------
#-- ENTRADA:
#-- -n1 (a0): Primer numero
#-- -n2 (a1): Segundo numero
#-- SALIDA:
#-- -Ninguna
#------------------------------------------------
.globl print_min
.data
msg4: .string "\nMin("
msg5: .string ", "
msg6: .string ")= "
.text
print_min:
#-- ¡¡Es una funcion intermedia!!
#-- Crear la pila
addi sp,sp,-16
#-- Guardar la direccion de retorno
sw ra, 12(sp)
#-- Guardar parametros en la pila
sw a0, 0(sp) #-- Numero 1
sw a1, 4(sp) #-- Numero 2
#-- Imprimir "Min("
la a0, msg4
li a7, PRINT_STRING
ecall
#-- Imprimir primer numero
lw a0, 0(sp) #-- Recuperar numero 1 de la pila
li a7, PRINT_INT
ecall
#-- Imprimir ", "
la a0,msg5
li a7, PRINT_STRING
ecall
#-- Imprimir segundo numero
lw a0, 4(sp) #-- Recuperar numero 2 de la pila
li a7, PRINT_INT
ecall
#-- Imprimir ")= "
la a0,msg6
li a7, PRINT_STRING
ecall
#-- Calcular el numero minimo
lw a0, 0(sp)
lw a1, 4(sp)
jal min
#-- Imprimir numero minimo
li a7, PRINT_INT
ecall
#-- Imprimir \n
li a0, '\n'
li a7, PRINT_CHAR
ecall
#-- Recuperar la direccion de retorno
lw ra, 12(sp)
#-- Liberar la pila
addi sp,sp,16
#-- Terminar
ret
- Fichero main.s:
#----------------------------------
#-- Programa principal:
#----------------------------------
.include "so.s"
.data
#-- Mensajes indicados en la ESPECIFICACION
msg1: .string "\nPrimer numero : "
msg2: .string "Segundo numero: "
.text
bucle:
##-- 1. Pedir el primer numero al usuario (n1)
#-- Imprimir mensaje al usuario para el primer numero
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Pedir numero 1 al usuario
li a7, READ_INT
ecall
#-- 2. Si este número es -1, terminar
li t0, -1
beq a0,t0,fin
#-- s0: Contiene el primer numero (n1)
mv s0,a0
#-- 3. Pedir segundo numero al usuario (n2)
#-- Imprimir mensaje al usuario para el segundo numero
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Pedir numero 2 al usuario
li a7, READ_INT
ecall
#-- a0: n2
mv a1, a0
#-- 4. Llamar a la funcion print_min(n1,n2) para imprimir el número mínimo
#-- print_min(n1,n2)
mv a0, s0 #-- Primer numero (n1)
jal print_min
#-- 5. Repetir desde el paso 1
b bucle
fin:
#-- Terminar
li a7, EXIT
ecall
- Fichero so.s:
#-- Código de los servicios del sistema operativo
#-- Incluir estos archivos en tus programas
#-- para acceder a ellos fácilmente, y hacerlos más
#-- legibles
.eqv PRINT_STRING 4
.eqv READ_STRING 8
.eqv READ_INT 5
.eqv PRINT_INT 1
.eqv PRINT_CHAR 11
.eqv READ_CHAR 12
.eqv EXIT 10
Evaluación
La evaluación del programa se hace en dos fases:
-
Funcionalidad (2.5 ptos): Se comprueba si el programa funciona, y si cumple con las especificaciones (Nombre del fichero correcto, ensablado sin errores, sin errores en tiempo de ejecución, resultado correcto, variables definidas en sus posiciones de memoria especificadas, etc). Esto se hace mediante un script de test, que automatiza el proceso. Se quitan puntos según los errores encontrados:
- Violación de especificaciones: -0.5
- Programa no ensambla: -0.5
- Warning en el ensamblado (-0.5)
- Error en tiempo de ejecución al pasar las pruebas: Runtime error: -0.5
- Retraso en la entrega: -0.5
- No hay segmento de código: -0.5
- Variable no contiene el valor correcto: -0.5
- El programa no termina (-0.5): No se llama al servicio exit del sistema operativo para terminar el programa de forma controlada
- VIOLACION DEL CONVENIO DE USO DE REGISTROS (-0.5). Algún registro estático se ha modificado al ejecutar la función
- La función no pasa ninguno de los test de funcionalidad (Nota 0 en apartado de funcionalidad)
- ...
-
Código (2.5 ptos): Se inspecciona visualmente cómo está hecho el código: código limpio, claro, con comentarios, instrucciones correctas, fallos de programación, etc... Se restan puntos por errores encontrados en el código:
- Código sin sentido (-0.5): Se ha introducido una instrucción, o directiva, que no tiene relación con el enunciado y no se da una explicación explícita de porqué se ha puesto
- Comentario contradictorio (-0.5): La instrucción hace una cosa, pero en los comentarios se indica otra distinta
- Comentarios no coherentes (-0.5): Se indica algo en los comentarios que no tiene nada que ver con el código que se está escribiendo
- Uso de un registro NO inicializado (-0.5)
- Violacion de especificaciones (-0.5)
- VIOLACION DEL CONVENIO DE USO DE REGISTROS (-0.5)
- Instrucción incorrecta (-0.5)
- Instrucción innecesaria (-0.5)
- Etiqueta no definida como global (-0.5)
- Dato inventado (-0.5). El código añade algo, o supone algo que no tiene sentido según lo que dice el enunciado
- No hay comentarios, o son muy escasos (-0.5)
- Función con 2 puntos de salida (-0.5)
- VIOLACION DE LA ABI: (-0.5)
- Uso de número mágico (-0.5)
- ...
TEST automático
🚧 TODO 🚧
Los scripts de test están disponibles, por si quieres probarlos con tus programas para comprobar tu evaluación
- Script de Test: TEST.zip
Preparando el entorno
El script de test se debe ejecutan en la terminal de LINUX
Sigue lo siguientes pasos:
- Crea un directorio donde se realizarán las pruebas. Por ejemplo Parcial3
- Pon en ese directorio los ficheros solución del examen:
min.s
,print_min.s
,main.s
yso.s
. Puedes bajartelos si quieres, para probar min.s, print_min.s, main.s y so.s - Descarga el fichero con el escript de test: TEST.zip
- Cópialo en el directorio
Parcial3
- Descomprímelo
La estructura queda así:
Parcial3/
.
├── main.s
├── min.s
├── print_min.s
├── so.s
└── TEST
├── 01-TEST-min.py
├── 02-TEST-print_min.py
├── 03-TEST-main.py
├── ansi.py
├── arquibot.py
├── input.txt
├── main_TB.s
├── min_SOL.s
├── min_TB.s
├── print_min_SOL.s
├── print_min_TB.s
├── rars.py
├── servicios.s
├── so.s
├── system.h
└── test.h
Ejecutamos los scripts python 01-TEST-min.py, 02-TEST-print_min.py y 03-TEST-main.py para probar respectivamente los apartados a, b y c:
obijuan@JANEL:~/Parcial3/TEST$ ./01-TEST-min.py
══════════════════════════════════════════════════════════════════════
ARQUI-BOT
══════════════════════════════════════════════════════════════════════
TESTING: ../min.s
───────────────────────────────────
> ❌️ RARS no existe
> Descargando RARS desde la URL: https://github.com/TheThirdOne/rars/releases/download/v1.5/rars1_5.jar
> OK!
> ✅️ RARS EXISTE
> ✅️ min_TB.s existe
> ✅️ ../min.s existe
> 🚧 Ejecutando: java -jar rars1_5.jar nc me ic 10000 dump .text HexText text.hex min_TB.s ../min.s
> 🎫 Instrucciones totales: 244
> ✅️ El programa termina llamando a EXIT
> ⏱️ Ciclos de ejecución: 230
> ✅️ ¡Salida exacta!
Salida:
Convenio OK!!
OK!!
OK!!
OK!!
> 🧹️ Eliminado text.hex antiguo
──────────────────────────────────────────────────────────────────────
Pulsa ENTER...
Primero comprueba si en el directorio está el fichero rars_1.5.jar. Si no es así, se lo baja del repositorio. A continuación prueba el fichero min.s
utilizando como programa principal min_TB.s
. Este programa principal realiza diferentes llamadas a la función min() para comprobar si funciona correctamente. También se comprueba el convenio de uso de los registros
Este es el resultado de la ejecución del segundo test:
══════════════════════════════════════════════════════════════════════
ARQUI-BOT
══════════════════════════════════════════════════════════════════════
TESTING: ../print_min.s
───────────────────────────────────
> ✅️ RARS EXISTE
> ✅️ print_min_TB.s existe
> ✅️ ../print_min.s existe
> ✅️ min_SOL.s existe
> 🚧 Ejecutando: java -jar rars1_5.jar nc me ic 10000 dump .text HexText text.hex print_min_TB.s ../print_min.s min_SOL.s
> 🎫 Instrucciones totales: 449
> ✅️ El programa termina llamando a EXIT
> ⏱️ Ciclos de ejecución: 600
> ✅️ ¡Salida exacta!
Salida:
Min(80, 100)= 80
Convenio OK!!
Min(1, 10)= 1
Convenio OK!!
Min(50, 4)= 4
Convenio OK!!
Min(70, 5)= 5
Convenio OK!!
> 🧹️ Eliminado text.hex antiguo
──────────────────────────────────────────────────────────────────────
Pulsa ENTER...
Ahora se prueba el fichero print_min.s
, utilizando el programa principal print_min_TB.s
. Se hacen diferentes llamadas a la función print_min() y se comprueba automáticamente su salida
Este es el resultado del tercer test:
obijuan@JANEL:~/Parcial3/TEST$ ./03-TEST-main.py
══════════════════════════════════════════════════════════════════════
ARQUI-BOT
══════════════════════════════════════════════════════════════════════
TESTING: ../main.s
───────────────────────────────────
> ✅️ RARS EXISTE
> ✅️ ../main.s existe
> ✅️ min_SOL.s existe
> ✅️ print_min_SOL.s existe
> 🚧 Ejecutando: java -jar rars1_5.jar nc me ic 10000 dump .text HexText text.hex ../main.s min_SOL.s print_min_SOL.s
> 🎫 Instrucciones totales: 79
> ✅️ El programa termina llamando a EXIT
> ⏱️ Ciclos de ejecución: 238
> ✅️ ¡Salida exacta!
Salida:
Primer numero: Segundo numero:
Min(1, 2)= 1
Primer numero: Segundo numero:
Min(2, 1)= 1
Primer numero: Segundo numero:
Min(40, 100)= 40
Primer numero:
> 🧹️ Eliminado text.hex antiguo
──────────────────────────────────────────────────────────────────────
Pulsa ENTER...
Se comprueba el programa principal main.s
, utilizando los ficheros min_SOL.s
y print_min_SOL.s
que contienen las funciones min() y print_min() respectivamente. Estas funciones cumplen todas las especificaciones y NO violan el convenio de uso de registros
Autores
- Juan González-Gómez (Obijuan)