Skip to content

Practica 3: Soluciones a los ejercicios

Juan Gonzalez-Gomez edited this page Nov 3, 2019 · 50 revisions

Práctica 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

Contenido

Práctica 3

Sesión 7

Solución a los ejercicios de la Sesión de laboratorio L7:3-1

Ejercicio 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

Ejercicio 2

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

Ejercicio 3

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

Ejercicio 4

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

Ejercicio 5

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 

Ejercicio 6

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

Ejercicio 7

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

Ejercicio 8

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

Ejercicio 9

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

Ejercicio 10

  1. 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

  1. 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

  2. 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

  1. 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

Sesión 8

Solución a los ejercicios de la Sesión de laboratorio L8:3-2

Ejercicio 1

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

Ejercicio 2

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

Ejercicio 3

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

Ejercicio 4

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

Ejercicio 5

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

Ejercicio 6

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

Ejercicio 7

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

Ejercicio 8

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

Ejercicio 9

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

Ejercicio 10

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

Autores

Licencia

Enlaces

Página principal


Sesiones de Prácticas

P1: Simulador RARs

L1: Práctica 1-1. RARs
L2: Práctica 1-2. Ensamblador
L3: Práctica 1-3. Variables

P2: E/S mapeada. Llamadas al sistema

L4: Pract 2-1. E/S mapeada
L5: Práctica 2-2: Inst. ecall
L6: Prác 2-3: Cadenas

P3: Bucles y Saltos condicionales

L7: Práct 3-1: Bucles y saltos
L8: Práct 3-2: Cadenas II

P4: Subrutinas

L9: Pract 4-1: Subrut. Nivel-1
L10: Pract 4-2: La pila
L11: Pract 4-3: Recursividad

P5: Memoria Dinámica

L12: Pract 5-1. Heap. Listas

VÍDEO DE DESPEDIDA

Ejercicios de examen

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

SOLUCIONES

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

Clone this wiki locally