-
Notifications
You must be signed in to change notification settings - Fork 22
Practica 3: Soluciones a los ejercicios
Soluciones comentadas a los ejercicios propuestos en las sesiones de la práctica 3. 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 de laboratorio L7:3-1
La comparación de dos números introducidos por el usuario se puede hacer de muchas formas. Sin embargo, en este ejercicio nos piden explícitamente que usemos beq. Siguiendo las prácticas de buena programación, en este programa hay un único punto de entrada y un único punto de salida
#-- Solucion Ejercicio 1
#-- Pedir dos numeros al usuario y comprobar si son iguales
.include "servicios.asm"
.data
#-- Mensajes a sacar por la consola
msg_iguales: .string "IGUALES"
msg_no_iguales: .string "DIFERENTES"
msg_num: .string "Introduce un numero: "
.text
#-- Pedir los dos numeros al usuario y guardarlos en los
#-- registros t0 y t1
#-- Print "Introduce un numero"
la a0, msg_num
li a7, PRINT_STRING
ecall
#-- Leer primer entero (t0)
li a7, READ_INT
ecall
mv t0, a0
#-- Print "Introduce un numero"
la a0, msg_num
li a7, PRINT_STRING
ecall
#-- Leer primer entero (t1)
li a7, READ_INT
ecall
mv t1, a0
#----- Realizar la comparacion
beq t0, t1, iguales
#-- NO son iguales
la a0, msg_no_iguales
li a7, PRINT_STRING
ecall
b fin
#-- Son iguales
iguales:
la a0, msg_iguales
li a7, PRINT_STRING
ecall
#--- PUNTO DE SALIDA
fin: li a7, EXIT
ecall
Ahora nos piden explícitamente que implementemos la misma comparación, pero usando la condición de NO igualdad (bne)
#-- Solucion Ejercicio 2
#-- Pedir dos numeros al usuario y comprobar si son iguales
#-- Hay que usar la instruccion bne
.include "servicios.asm"
.data
#-- Mensajes a sacar por la consola
msg_iguales: .string "IGUALES"
msg_no_iguales: .string "DIFERENTES"
msg_num: .string "Introduce un numero: "
.text
#-- Pedir los dos numeros al usuario y guardarlos en los
#-- registros t0 y t1
#-- Print "Introduce un numero"
la a0, msg_num
li a7, PRINT_STRING
ecall
#-- Leer primer entero (t0)
li a7, READ_INT
ecall
mv t0, a0
#-- Print "Introduce un numero"
la a0, msg_num
li a7, PRINT_STRING
ecall
#-- Leer primer entero (t1)
li a7, READ_INT
ecall
mv t1, a0
#----- Realizar la comparacion
bne t0, t1, diferentes
#-- Son iguales
la a0, msg_iguales
li a7, PRINT_STRING
ecall
b fin
#-- Son diferentes
diferentes:
la a0, msg_no_iguales
li a7, PRINT_STRING
ecall
#--- PUNTO DE SALIDA
fin: li a7, EXIT
ecall
El menú es en realidad UNA ÚNICA CADENA, que tiene caracteres de salto de línea '\n' entre medias. Por tanto, se puede definir usando la directiva .string de esta manera:
menu_str: .string "\n\nMenu de opciones\n================\n1. Incrementar contador\n2.Exit\n\nOpcion? :"
El programa imprime el menú en la consola, invocando al servicio PRINT_STRING. Luego se invoca el servicio READ_CHAR para leer un carácter. En función del carácter introducido, se salta a las etiquetas opcion1 y opcion2 para ejecutar la opción que toque. Si no es ninguna de esas opciones se imprime el mensaje de error. Se usa la instrucción beq para realizar las comparaciones
#-- Solucion al ejericio 3: Menu con 2 opciones
.include "servicios.asm"
.data
#-- Definicion de las cadenas con los mensajes a sacar
menu_str: .string "\n\nMenu de opciones\n================\n1. Incrementar contador\n2.Exit\n\nOpcion? :"
cont_str: .string "\nContador: "
error: .string "\nERROR: Opcion invalida"
exit_str: .string "\nEXIT: Terminando el programa\n"
.text
#-- t2 lo usamos como contador
li t2, 0
#-- Bucle principal
menu:
#-- Imprimir el menu
la a0, menu_str
li a7, PRINT_STRING
ecall
#-- Pedir la opcion al usuario. Usamos el servicio READ_CHAR porque es
#-- una especificación del enunciado
li a7, READ_CHAR
ecall
#-- a0 contiene la opcion elegida, como caracter
#-- ¿Es la opcion 1?
li t0, '1'
beq a0, t0, opcion1
#-- ¿Es la opcion 2?
li t0, '2'
beq a0, t0, opcion2
#-- Si llega aqui es que es una opcion incorrecta
#-- Imprimir mensaje error y volver al menu
la a0, error
li a7, PRINT_STRING
ecall
#-- volver el menu
b menu
#-- Opcion 1: Incrementar el contador e imprimir su valor
opcion1:
#-- Incrementar el contador
addi t2, t2, 1
#------- Mostrar el valor del contador: "Contador: "
la a0, cont_str
li a7, PRINT_STRING
ecall
#-- Imprimir valor del contador
li a7, PRINT_INT
mv a0, t2
ecall
#-- Volver al comienzo para sacar el menu
b menu
#-- Opcion 2: Terminar
opcion2:
#-- Imprimir mensaje de fin
la a0, exit_str
li a7, PRINT_STRING
ecall
#-- PUNTO DE SALIDA
fin: li a7, EXIT
ecall
Si se estuviese haciendo un programa con un menú con más opciones, incluir todo el menú en una directiva .string puede resultar poco legible. Se puede implementar en múltiples líneas teniendo en cuenta que ES UNA UNICA CADENA, y que su final está determinado por el carácter '\0'
Así, podemos usarla directiva .ascii que me almacena en memoria una serie de caracteres SIN AÑADIR EL '\0' al final. Colocamos una directiva .ascii por cada línea y al final añadimos el carácter '\0':
.data
#-- Una cadena UNICA, pero definida linea a linea
menu_str: .ascii "\n\n"
.ascii "Menu de opciones\n"
.ascii "================\n"
.ascii "\n1. Incrementar contador\n"
.ascii "2.Exit\n"
.ascii "\n"
.ascii "Opcion? :"
#-- Hay que añadir el byte 0
#-- para indicar el final de la cadena
.byte 0
#-- El resto del programa es igual....
Se define el contador en el registro t0, que se incrementa y se imprime en un buble. La condición de terminación del bucle es cuando t0 es igual al número n introducido por el usuario
Este programa tiene muchas solucionens diferentes. Esta sería una. Pero a tí se te puede ocurrir otra
#-- Solucion al ejercicio 4
#-- Pedir al usuario que introducezca un numero
#-- entero (n). El programa imprime los numeros
#-- desde el 1 hasta el n, separados por el carater ','
.include "servicios.asm"
.data
msg_pedir_n: .string "Introduce un numero (n): "
.text
#------ Pedir numero n al usuario
la a0, msg_pedir_n
li a7, PRINT_STRING
ecall
li a7, READ_INT
ecall
#-- a0 contiene n. Lo guardamos en t1
mv t1, a0
#-- t0 es el contador
li t0, 0
#--- Bucle
bucle:
#-- Si t0 == n, terminar
beq t0, t1, fin_bucle
#-- Incrementar contador
addi t0, t0, 1
#-- Imprimir el contador
mv a0, t0
li a7, PRINT_INT
ecall
#-- Imprimir el carater de separacion ','
li a0, ','
li a7, PRINT_CHAR
ecall
#-- Repetir
b bucle
fin_bucle:
#-- Terminar
li a7, EXIT
ecall
En este ejercicio hay que usar una cadena definida en tiempo de ejecución: es decir, no la conocemos hasta que el usuario la introduce. Por ello hay que reservar espacio a priori, con la directiva .space. En el enunciado me especifican que sea de 1024. Si no me lo indicasen, lo elijes tú (pero tienes que poner un valor con sentido común)
Sabemos que las cadenas terminan en 0, pero el enunciado me pide explícitamente que use el carácter '\n' para detectar el fin (El servicio READ_STRING incluye este carácter al final)
#-- Solución al ejericicio 5
#-- calcular la longitud de la cadena introducida por el usuario
.include "servicios.asm"
.eqv MAX 1024
.data
#-- Aqui se almacena la cadena introducida por el usuario
cad: .space MAX
msg_introduce_cad: .string "Introduce una cadena: "
msg_longitud: .string "Longitud: "
.text
#-- Pedir al usuario que introduzca la cadena
la a0, msg_introduce_cad
li a7, PRINT_STRING
ecall
la a0, cad
li a1, MAX
li a7, READ_STRING
ecall
#----- La cadena introducida se encuentra en cad
#-- El contador de cacteres esta en t0
li t0, 0
#-- t1 es el puntero a la cadena
la t1, cad
#--- Bucle para recorrer la cadena
bucle:
#-- Leer el carácter de la cadena
lb t2, 0(t1)
#-- Si el caracter es \n, terminar
li t3, '\n'
beq t2, t3, fin_bucle
#-- Incrementar le contador de caracteres
addi t0, t0, 1
#-- Apuntar al siguiente caracter
addi t1, t1, 1
b bucle
#-- Hemos llegado al final de la cadena
#-- Imprimir su lognitud
fin_bucle:
#--- Imprimir la longitud de la cadena
la a0, msg_longitud
li a7, PRINT_STRING
ecall
#-- La longitud está en el contador t0
mv a0, t0
li a7, PRINT_INT
ecall
#-- Terminar
li a7, EXIT
ecall
Para comparar la relación menor que (<) usamos la instrucción blt. Para la relacion mayor que (>) se usa bgt. Si no se cumple ninguna de ellas, entonces es que los números son iguales (==)
#-- Solucion al ejercicio 6
#-- Pedir al usuario 2 numeros enteros (n1,n2) e imprimir
#-- en pantalla cual su relacion
.include "servicios.asm"
.data
msg_n1: .string "Introduce n1: "
msg_n2: .string "Introduce n2: "
msg_menor: .string "n1 < n2"
msg_igual: .string "n1 == n2"
msg_mayor: .string "n1 > n2"
.text
#----- Pedir los numeros n1 y n2. Se guaardan en
#--- t1 y t2 respectivamente
la a0, msg_n1
li a7, PRINT_STRING
ecall
li a7, READ_INT
ecall
mv t1, a0
la a0, msg_n2
li a7, PRINT_STRING
ecall
li a7, READ_INT
ecall
mv t2, a0
#--- Realizar las comparaciones entre t1 y t2
#-- ¿n1 < n2?
blt t1, t2, menor
#-- ¿n1 > n2?
bgt t1, t2, mayor
#-- Si llega aqui es que son iguales n1 == n2
la a0, msg_igual
li a7, PRINT_STRING
ecall
#-- Terminar
b fin
menor: #-- n1 es menor que n2
la a0, msg_menor
li a7, PRINT_STRING
ecall
#-- Terminar
b fin
mayor: #-- n1 es mayor que n2
la a0, msg_mayor
li a7, PRINT_STRING
ecall
fin:
#-- Terminar
li a7, EXIT
ecall
Se usa el registro t0 para ir acumulando la suma de los números introducios por el usuario. Cuando introduce el número 0 se termina el bucle, y se imprime el valor de t0, que tiene la suma total
#-- Solución al ejercicio 7
#-- Calcular al suma de los números introducidor por el usuario
.include "servicios.asm"
.data
msg_num: .string "Introduzca numero: "
msg_total: .string "La suma total es: "
.text
#-- El regitro t0 se contiene a suma de los numeros
li t0, 0
bucle:
#-- Pedir numero
la a0, msg_num
li a7, PRINT_STRING
ecall
li a7, READ_INT
ecall
#-- Si se introduce el 0 se termina
beq a0, zero, imprimir_total
#-- Sumar el numero
add t0, t0, a0
#-- Pedir siguiente numero
b bucle
imprimir_total:
#-- Imprimir mensaje
la a0, msg_total
li a7, PRINT_STRING
ecall
#-- Imprimir el total
mv a0, t0
li a7, PRINT_INT
ecall
#-- Terminar
li a7, EXIT
ecall
Los dos primeros términos, 0 y 1, se imprimen directamente usando un cadena definida en tiempo de compilación:
msg_fib_ini: .string "0,1,"
Se define la constante N inicializada a 10. Será la que se use para finalizar el bucle. Los registro t0 y t1 se usan para almacenar dos términos de la sucesión de Fibonacci. El siguiente término será la suma de estos dos
Por último, el regitro t2 se usa de contador, indicando el número del término actual. Se inicializa con 2. Cuando es igual a N, se finaliza
#-- Solución al ejercicio 8
#-- Calcular los diez primeros terminos de la sucesion de fibonacci
.include "servicios.asm"
.data
#-- Cadena con los numeros iniciales de fibonacci
msg_fib_ini: .string "0,1,"
#-- Máximo termino de fibonacci que calcular
.eqv N 10
.text
#-- Los registros t0 y t1 contienen los terminos anteriores
#-- de fibonacci. Inicialmente: t0=0, t1 = 1
li t0, 0
li t1, 1
#-- El registro t2 contiene el numero del termino actual
li t2, 2
#-- Imprimir los terminos iniciales
la a0, msg_fib_ini
li a7, PRINT_STRING
ecall
bucle:
#-- Cacular el termino actual: t3 = t0 + t1
add t3, t0, t1
#-- Imprimir el termino actual
mv a0, t3
li a7, PRINT_INT
ecall
#-- Si se ha llegado al término N, terminar
li t4, N
beq t2, t4, fin
#-- No es el ultimo
#-- Incrementar el numero de termino
addi t2, t2, 1
#-- Imprimir la ',' de separacion
li a0, ','
li a7, PRINT_CHAR
ecall
#-- Preparase para calcular los siguientes términos
mv t0, t1
mv t1, t3
#-- Repetir
b bucle
fin:
#-- Terminar
li a7, EXIT
ecall
Para resolver este ejercicio hay que recorrer la cadena de principio a fin. Cuando el carácter leído sea igual a 'a' se incrementa el contador de 'a's, almacenado t1
Los caracter son números. Para comparar el carácter leido con el de una constante, bien lo indicamos dando su valor ASCII (97) o bien usamos la notación 'a'
Si en t2 tenemos el carácter actual, leido de la cadena, para comprobar si es igual a 'a' hacemos lo siguiente:
li t3, 'a' ##-- Cargar en t3 el valor (ASCII) del carácter
beq t2, t3, etiqueta #-- Saltar a etiqueta si t2 == 'a'
Este es el programa completo:
#-- Solución al ejercicio 9
#-- Contar la cantidad de caracteres 'a' que hay en una
#-- cadena introducida por el usuario
.include "servicios.asm"
#-- Tamaño máximo de la cadena pedida al usuario
.eqv MAX 1024
.data
msg_pide_cad: .string "Introduce una cadena: "
msg_result: .string "Contador del caracter 'a': "
#--- Cadena pedida al usuario
cad: .space MAX
.text
#-- Pedir cadena al usuario
la a0, msg_pide_cad
li a7, PRINT_STRING
ecall
la a0, cad
li a1, MAX
li a7, READ_STRING
ecall
#-- En t0 metermos el puntero a la cadena, para recorrerla
la t0, cad
#-- En t1 metemos el contador de 'a's
li t1, 0
bucle:
#-- Leer el caracter actual
lb t2, 0(t0)
#-- Comprobar si se ha llegado al final de la cadena
beq t2, zero, fin_bucle
#-- Comprobar si es el caracter 'a'
li t3, 'a'
bne t2, t3, continua #--> NO, continua
#-- Se ha encontrado una 'a'
#-- Incrementar contador
addi t1, t1, 1
continua:
#-- Pasar al siguiente caracter: Incrementar puntero
addi t0, t0, 1
b bucle
#--- Imprimir el resultado
fin_bucle:
la a0, msg_result
li a7, PRINT_STRING
ecall
#-- Imprimir el valor del contador de 'a's
mv a0, t1
li a7, PRINT_INT
ecall
fin:
#-- Terminar
li a7, EXIT
ecall
- En las instrucciones de salto del RISCV, el último argumento indica la dirección relativa de la instrucción destino, pero expresado en "medias palabras". Nos está indicando que el salto se realizará 10 medias-palabras hacia adelante. Es decir, 5 instrucciones hacia adelante. Como el jal está en la direcciónn 0x00400000, salta a la dirección 0x00400000 + 5 * 4 (5 palabras más adelante), que en hexadecimal es: 0x00400000 + 0x14 = 0x00400014
Salta a la dirección 0x0040014
-
La instrucción, por tanto, que se ejecutará después de jal será la que está en la dirección 0x00400014: addi x30, x0, 5
-
En el código fuente trabajamos con etiquetas, por lo que el programa original podría ser:
jal x0, next
addi x6,x0,1
addi x7,x0,2
addi x28,x0,3
addi x29,x0,4
next:
addi x30,x0,5
addi x17,x0,10
ecall
Si usamos directamente la instrucciónn jal x0, 10, aunque se trata de una instrucción correcta del RISC-V, el ensamblador producirá un mensaje de error. Este ensamblador nos obliga a usar etiquetas, que es lo que los humanos entendemos
- Si ensamblamos ese código, efectivamente obtenemos el segmento de código original
Como li es una pseudoinstruccion para inicilizar registros, que es equivalente a addi, el programa original también podría ser este otro. El segmento de código obtenido es exactamente igual
.text
jal x0, next
li t1, 1
li t2, 2
li t3, 3
li t4, 4
next: li t5, 5
li a7, 10
ecall
Solución a los ejercicios de la Sesión de laboratorio L8:3-2
Con el servicio READ_INT solicitamos un número entero al usuario. En a0 obtenemos el número introducido. Para que se imprima como carácter sólo hay que invocar al servicio PRINT_CHAR, que interpretará este número como un código ASCII y sacará en la consola su carácter correspondiente
##-- Solución al ejercicio 1
##-- Obtener el carácter correspondiente al código ASCII
##-- pedido al usuario
.include "servicios.asm"
.data
msg1: .string "Introduzca codigo ASCII: "
msg2: .string "El caracter es: "
.text
#-- Imprimir mensaje 1
la a0,msg1
li a7, PRINT_STRING
ecall
#-- Pedir código ASCII al usuario
li a7, READ_INT
ecall
#-- a0 contiene el numero introducido
#-- Lo guardamos en t0
mv t0, a0
#-- Imprimir mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir caracter ASCII correspondiente
mv a0, t0
li a7, PRINT_CHAR
ecall
#--- Terminar
li a7, EXIT
ecall
Este ejercicio es el inverso. Ahora pedimos al usuario un carácter usando el servicio PRINT_CHAR. Lo que se guarda en el registro a0 es código ASCII del carácter introducido. Para mostrarlo en pantalla sólo hay que invocar el servicio PRINT_INT
##-- Solución al ejercicio 2
##-- Calcular el código ASCII del caracter introducido
##-- por el usuario
.include "servicios.asm"
.data
msg1: .string "Introduzca un carácter: "
msg2: .string "\nSu código ASCII es: "
.text
#-- Imprimir mensaje 1
la a0,msg1
li a7, PRINT_STRING
ecall
#-- Pedir carácter al usuario
li a7, READ_CHAR
ecall
#-- a0 contiene el carácter introducido
#-- Lo guardamos en t0
mv t0, a0
#-- Imprimir mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir su código ASCII
mv a0, t0
li a7, PRINT_INT
ecall
#--- Terminar
li a7, EXIT
ecall
Al usuario se le pide un carácter, que debe estar comprendido entre '0' y '9'. En la tabla ASCII, los dígitos del 0 al 9 están ordenados en forma ascendente, de manera que el código ASCII del dígito '9' es mayor que el del dígito '0'.
Si el carácter introducido por el usuario es menor que '0', será incorrecto. De igual manera, si es mayor que '9' también será incorrecto. En caso contrario es correcto, y para convertirlo a número sólo hay que restarle '0':
#-- Solución al ejercicio 3
#-- Pedir al usuario un carácter y convertirlo a
#-- su número entero, si es válido ('0' - '9')
.include "servicios.asm"
.data
msg1: .string "Introduce un numero de un digito (0 - 9): "
error: .string "\nCaracter inválido\n"
msg2: .string "\nEl número es: "
.text
bucle_pedir:
#--- Imprimir mensaje 1
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Pedir el dígito (es un caracter)
li a7, READ_CHAR
ecall
#-- El dígito está en a0. Lo movemos a t0
#-- Si es menor que '0' es incorrecto
li t1, '0'
blt a0, t1, no_valido
#-- Si es mayor que '9' es incorrecto
li t1, '9'
bgt a0, t1, no_valido
#-- El carácter es válido: Realizar la conversión
li t1 '0'
sub t2, a0, t1 #-- t2 = a0 - '0'
#-- Imprimir el mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir el numero en la consola: Servicio PRINT_INT
mv a0, t2
li a7, PRINT_INT
ecall
#-- Terminar: saltar al punto de salida
b fin
no_valido:
#-- El digito introducido NO es valido
#-- Imprimir mensaje de error
la a0, error
li a7, PRINT_STRING
ecall
#-- volver a pedir
b bucle_pedir
fin:
#-- Terminar
li a7, EXIT
ecall
En este ejercicio nos piden que convertamos a un número una cadena de 2 caracteres. Por ejemplo "01", "23", etc... Nos dan la fórmula a aplicar, así que es la que usamos. La única consideración a tener en cuenta es que en memoria hay que reservar espacio para 3 bytes: los dos caracteres más el cero
#-- Solución al ejericio 4: Conversion de una
#-- cadena de caracteres de 2 dígitos a un número
.include "servicios.asm"
#-- Numero maximo de caracteres: 3, dos digitos más el 0
.eqv MAX 3
.data
cadnum: .space MAX #-- Se reservan 3 bytes de espaci
msg1: .string "\nIntroduzca cadena de dos dígitos: "
msg2: .string "\nNumero: "
.text
#-- Imprimir mensaje 1
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Pedir cadena al usuario
la a0, cadnum
li a1, MAX
li a7, READ_STRING
ecall
#-- Leer los digitos d1 y d0
#-- t0 = d0
lb t0, 1(a0)
#-- t1 = d1
lb t1, 0(a0)
#-- Calcular la expresion: num = (d1 - 48) * 10 + (d0 - 48)
#-- t2 = 48
li t2, 48
#-- t3 = d0 - 48
sub t3, t0, t2
#-- t4 = d1 - 48
sub t4, t1, t2
#-- t6 = (d1 - 48) * 10
li t5, 10
mul t6, t4, t5
#-- t6 = (d1 - 48) * 10 + (d0 - 48)
add t6, t6, t3
#-- Imprimir el mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir el numero calculado
mv a0, t6
li a7, PRINT_INT
ecall
#-- Terminar
li a7, EXIT
ecall
Tenemos que hacer una conversión genérica de una cadena a número. El enunciado nos dice explícitamente que NO contemplemos los mensajes de error, así que supondremos que el usuario simpre introducirá cadenas con los dígitos '0' - '9'. Es importante recalcar que NO nos piden que hagamos la conversión de cualquier manera, sino usando un algoritmo concreto. Así que tendremos que implementar uno por uno los pasos de ese algoritmo
#-- Solución al ejericio 5: Conversion de una cadena
#-- variable a número
.include "servicios.asm"
.eqv MAX 10
.data
cadnum: .space MAX #-- Cadena a convertir
msg1: .string "\nIntroduzca cadena: "
msg2: .string "\nNumero: "
.text
#-- Imprimir mensaje 1
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Pedir cadena al usuario
la a0, cadnum
li a1, MAX
li a7, READ_STRING
ecall
#--- t0: Resultado parcial
li t0, 0
next_car:
#--- Leer digito
lb t1, 0(a0)
#-- ¿Es \n? Hemos terminado
#-- El resultado es el que esta en t0
li t5, '\n'
beq t1,t5, imprimir
#-- El caracter no es cero
#-- Multiplicar t0 por 10
li t2, 10
mul t0, t0, t2
#-- Obtener el numero del digito (t1 - '0')
li t3, '0'
sub t4, t1, t3 #-- t4 = t1 - '0
#-- t0 = t0 + t4
add t0, t0, t4
#-- Apuntar al siguiente caracter
addi a0, a0, 1
#-- Repetir
b next_car
imprimir:
#-- Imprimir el mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir el numero calculado
mv a0, t0
li a7, PRINT_INT
ecall
#-- Terminar
li a7, EXIT
ecall
Para implementar la lectura de números negativos, NO nos han dado un algoritmo concreto, por lo que tendremos que pensar cómo hacerlo. En la solución presentada aquí, se usa el registro t6 para almacenar 1 ó -1 en función de si es positivo o negativo. Por defecto se suponer positivo, y a t6 se le asigna el valor 1
Si el primer carácter de la cadena es el menos ('-') se asigna a t6 el valor -1 y se convierte el resto de la cadena a número como en el ejercicio 5. El resultdo final será ese número multiplicado por el registro t6, que nos lo convierte a negativo si es el caso
#-- Solución al ejericio 6: Conversion de una cadena
#-- variable a número. Puede ser tanto un numero positivo
#-- como negativo
.include "servicios.asm"
.eqv MAX 10
.data
cadnum: .space MAX #-- Cadena a convertir
msg1: .string "\nIntroduzca cadena: "
msg2: .string "\nNumero: "
.text
#-- Imprimir mensaje 1
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Pedir cadena al usuario
la a0, cadnum
li a1, MAX
li a7, READ_STRING
ecall
#--- t0: Resultado parcial
li t0, 0
#-- Primero comprobamos si hay signo
#-- En el registro t6 metemos -1 ó 1
#-- dependiendo de si tiene o no signo
#-- Multiplicaremos el resultdo final por t6
li t6, 1
#--- Leer primer digito
lb t1, 0(a0)
#-- ¿NO es signo menos? --> ir al bucle principal
li t5, '-'
bne t1, t5, next_car
#-- Es signo menos, guardar -1 en t6
li t6, -1
#-- Apuntar al siguiente caracter
addi a0, a0, 1
#-- Bucle principal
next_car:
#--- Leer digito
lb t1, 0(a0)
#-- ¿Es \n? Hemos terminado
#-- El resultado es el que esta en t0
li t5, '\n'
beq t1,t5, imprimir
#-- El caracter no es cero
#-- Multiplicar t0 por 10
li t2, 10
mul t0, t0, t2
#-- Obtener el numero del digito (t1 - '0')
li t3, '0'
sub t4, t1, t3 #-- t4 = t1 - '0
#-- t0 = t0 + t4
add t0, t0, t4
#-- Apuntar al siguiente caracter
addi a0, a0, 1
#-- Repetir
b next_car
imprimir:
#-- El resultado está en t0
#-- multiplicar t0 = t6 * t0
#-- para añdir el signo
mul t0, t6, t0
#-- Imprimir el mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir el numero calculado
mv a0, t0
li a7, PRINT_INT
ecall
#-- Terminar
li a7, EXIT
ecall
En este programa hay que realizar una copia de un cadena introducida por el usuario. Como no nos dicen el tamaño máximo de la cadena, elegimos nosotros uno (usando el sentido común). Por ejemplo 32. En el segmento de datos hay que situar primero la cadena original. La cadena destino puede estar en cualquier posición, por ejemplo a continuación de la origen
Es muy importante copiar también el carácer final '\0'
#-- Solución al ejercicio 7
#-- Copiar una cadena de una posicion de memoria a otra
.include "servicios.asm"
.eqv MAX 32
.data
cad_orig: .space MAX
cad_destino: .space MAX
msg1: .string "\nIntroduce cadena: "
msg2: .string "Cadena copia: "
.text
#-- Imprimir mensaje 1
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Pedir cadena
la a0, cad_orig
li a1, MAX
li a7, READ_STRING
ecall
#------ Copiar la cadena
#-- Puntero a la cadena destino
la t0, cad_destino
bucle:
#-- Leer caracter original
lb t1, 0(a0)
#-- Almacenarlo en cadena destino
sb t1, 0(t0)
#-- ¿Es 0?
beq t1,zero, fin
#-- Incrementar los punteros
addi a0, a0, 1
addi t0, t0, 1
#-- Repetir
b bucle
#------ Imprimir la cadena destino
fin:
#-- Imprimir mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir la cadena copiada
la a0, cad_destino
li a7, PRINT_STRING
ecall
#-- Terminar
li a7, EXIT
ecall
El programa debe recorrer la cadena, sumando K unidades a cada carácter. Para ello se lee el cacter, se le suma K y se vuelve a guardar. Luego se repite hasta llegar al final de la cadena
#-- Solución al ejercicio 8
#-- Cifrar una cadena
#-- El cifrado es simple: Se suma una constante a cada caracter
.include "servicios.asm"
#-- Tamaño máximo de la cadena
.eqv MAX 32
#-- Constante a sumar, para cifrar
.eqv K 5
.data
cad: .space MAX
msg1: .string "Introduce cadena: "
msg2: .string "Cadena cifrada: "
.text
#-- Imprimir mensaje msg1
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Pedir cadena al usuario
la a0, cad
li a1, MAX
li a7, READ_STRING
ecall
bucle:
#-- Leer caracter
lb t0, 0(a0)
#-- Condicion de finalizacion
li t1, '\n'
beq t0, t1, fin
#-- Sumar K al caracter
addi t0,t0, K
#-- Almacenar el caracter cifrado
sb t0, 0(a0)
#-- Apuntar al siguiente caracter
addi a0, a0, 1
#-- Repetir
b bucle
fin: #-- Hemos terminado
#-- Imprimir el mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir la cadena
la a0, cad
li a7, PRINT_STRING
ecall
#-- Terminar
li a7, EXIT
ecall
La cadena se recorre normalmente, leyendo los caracteres uno a uno. Si el carácter leido es menor que 'a', entonces no hay es un carácter en minúsculas: se pasa al siguiennte. Si es mayor que 'z', ocurre lo mismo: se pasa al siguiente. En caso contrario está en el rango 'a' - 'z', por lo que es un carácter válido en minúsculas y habrá que convertirlo a mayúsculas. Basta con restarle el número 32. El bucle se repite hasta llegar al final
#-- Solución al ejercicio 9
#-- Pasar una cadena de minúsculas a mayúsculas
#-- Para pasar un caracter a mayúsculas hay que restar 32
#-- Solo se pasan los caaracteres 'a'-'z'
.include "servicios.asm"
#-- Tamaño máximo de la cadena
.eqv MAX 32
.data
cad: .space MAX
msg1: .string "Introduce cadena: "
msg2: .string "Cadena en mayusculas: "
.text
#-- Imprimir mensaje msg1
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Pedir cadena al usuario
la a0, cad
li a1, MAX
li a7, READ_STRING
ecall
bucle:
#----------- Pasar a mayúsculas
#-- Leer caracter
lb t0, 0(a0)
#-- Condicion de terminacion
beq t0, zero, fin
#-- Si el caracter es menor que 'a' o mayor que 'z'
#-- hay que pasar al siguiente
li t1, 'a'
blt t0,t1,next
li t1, 'z'
bgt t0, t1, next
#-- Hay que pasarlo a mayusculas
addi t0,t0,-32
#-- Guardarlo
sb t0, 0(a0)
next:
#-- Pasar al siguiente caracter
addi a0, a0, 1
#-- Repetir
b bucle
fin: #-- Hemos terminado
#-- Imprimir el mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir la cadena
la a0, cad
li a7, PRINT_STRING
ecall
#-- Terminar
li a7, EXIT
ecall
Para invertir la cadena, tenemos que usar dos punteros, uno por la izquierda y otro por la derecha, igual que en el ejemplo del palíndromo. Por ello, primero se recorre la cadena para tener el puntero derecho apuntando al último carácter. A partir de ahí, cada puntero recorre la cadena en direcciones opuestas: el derecho se decrementa, el izquierdo se incrementa. En cada paso se intercambian los caracteres de ambos punteros: el primer carácter pasa a la última posición, y el último a la primera. El bucle se repite hasta que el puntero derecha sea menor o igual al izquierdo. En ese momento hemos terminado
#-- Solución al ejercicio 10
#-- Invertir una cadena
.include "servicios.asm"
#-- Tamaño máximo de la cadena
.eqv MAX 32
.eqv K 5
.data
cad: .space MAX
msg1: .string "Introduce cadena: "
msg2: .string "Cadena invertida: "
.text
#-- Imprimir mensaje msg1
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Pedir cadena al usuario
la a0, cad
li a1, MAX
li a7, READ_STRING
ecall
#-- t1 es el puntero derecho
#-- Para obtenerlo hay que recorrer la cadena hasta llegar al caracter '\n'
mv t1, a0
recorrer:
#-- Leer car
lb t2, 0(t1)
#-- ¿Es \n?
li t3, '\n'
beq t2, t3, fin_recorrer
#-- No hemos llegado al final
addi t1, t1, 1
#--- bucle
b recorrer
fin_recorrer:
#-- Decrementar a1 en una unidad para que apunte al último
#-- caracter
addi t1,t1,-1
#-- a0 es el puntero izquierod. t1 es el upntero derecho
bucle:
#-- Condicion de salida: ¿puntero derecho <= puntero izquierdo?
ble t1,a0 fin
#-- Intercambiar los caracteres izquierdo y derecho
#-- TODO
#-- Leer caracter izquierdo
lb t0, 0(a0)
#-- Leer caracter derecho
lb t2, 0(t1)
#-- Intercambiarlos
sb t2, 0(a0)
sb t0, 0(t1)
#-- Incrementar puntero izquierdo
addi a0, a0, 1
#-- Decrementar puntero derecho
addi t1, t1, -1
#-- Repetir
b bucle
fin: #-- Hemos terminado
#-- Imprimir el mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir la cadena
la a0, cad
li a7, PRINT_STRING
ecall
#-- Terminar
li a7, EXIT
ecall
- Katia Leal Algara
- Juan González-Gómez (Obijuan)
L1: Práctica 1-1. RARs
L2: Práctica 1-2. Ensamblador
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
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
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
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
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
Práctica 1: Sesiones 1,2 y 3
Práctica 2: Sesiones 4, 5 y 6
Práctica 3: Sesiones 7 y 8
Práctica 4: Sesiones 9, 10 y 11
Práctica 5: Sesión 12