-
Notifications
You must be signed in to change notification settings - Fork 22
Practica 2: Soluciones a los ejercicios
Soluciones comentadas a los ejercicios propuestos en las sesiones de la práctica 2. 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 L4:2-1
Tenemos que implementar un programa en el que haya un contador en la variable contador, inicializada con la constante INICIO, y que se incremente según la constante INC
#-- Ejercicio 1
#-- Contador con valor incial e incremento
#-- DEFINICION de constantes
.eqv INICIO 100 #-- Valor de inicio del contador
.eqv INC 10 #-- Incremento del contador
#-- Variables
.data
contador: .word 0
#-- Código
.text
#-- Usamos el registro x5 como contador
#-- x5 = INICIO (Inicializacion)
li x5, INICIO
#-- PUntero a la variale contador: x6
la x6, contador
bucle:
#-- Actualizar la variable contador
#-- Almacenar el valor de x5 en contador
sw x5, 0(x6)
#-- Incrementar el contador
addi x5, x5, INC
#-- Bucle infinito
b bucle
Al ejecutar el programa, observamos que los 4 elementos de la tabla, que tienen los valores 0xBEBECAFE, 0xFACEB00C, 0x00FABADA, 0xCACABACA se han cargado en los registros x10, x11, x12 y x13 respectivamente
Este programa nos enseña cómo definir una tabla y cómo acceder de manera sencilla a sus elementos, usando identificadores. Si en vez de el identificador utilizásemos directamente los números de desplazamiento, el programa sería mucho más difícil de entender. Somo humanos. Necesitamos que los programas tengan información para humanos
Así, con la instrucción:
lw x10, E1(x5)
hemos cargado el elemento 1 de la tabla en el registro x10, y con
lw x13, E4(x5)
cargamos el elemento 4 en el registro x13
En este programa tenemos que incrementar en una unidad TODOS los elementos de la tabla. Como todavía no sabemos hacer bucles, lo haremos manualmente. Primero leemos los valores de la tabla y los cargamos en los registros del x10 al x13. Al estar en los registros, ya podemos realizar las operaciones, que en este ejemplo es incrementar cada registro en 1 unidad. Por último, hay que almacenar los registros incrementados en sus posiciones de la tabla, usando instrucciones sw
##-- Solución al Ejercicio 3
##-- Incrementar cada uno de los elmementos de la tabla en INC unnidades
#-- Definiciones. Estos indetificadores nos permiten acceder
#-- directamente a los elementos de la tabla: E1, E2, E3 y E4
.eqv E1 0
.eqv E2 4
.eqv E3 8
.eqv E4 0xC
#-- Incremento: Valor a incrementar TODOS los elementos de la tabla
.eqv INC 1
#----------------------- Variables
.data
#-- Tabla de 4 elementos, inicializados a ciertos valores
tabla: .word 0xBEBECAFE, 0xFACEB00C, 0x00FABADA, 0xCACABACA
#------------------------ Código
.text
#-- x5 es un puntero a la tabla (x5 contiene la direccion del primer elemento de la tabla)
la x5, tabla
#-- Leer todos los elementos de la tabla, y situarlos en los registros x10, x11, x12 y x13
lw x10, E1(x5)
lw x11, E2(x5)
lw x12, E3(x5)
lw x13, E4(x5)
#-- Incrementar los registros en INC unidades
addi x10, x10, INC
addi x11, x11, INC
addi x12, x12, INC
addi x13, x13, INC
#-- Actualizar la tabla con los nuevos valores
sw x10, E1(x5)
sw x11, E2(x5)
sw x12, E3(x5)
sw x13, E4(x5)
#-- Terminar
li a7, 10
ecall
Al ensamblar y ejecutar el programa, comprobamos que los 4 elementos de memoria están incrementados en 1 unidad:
- 0xBEBECAFE --> 0xBEBECAFF
- 0xFACEB00C --> 0xFACEB00D
- 0x00FABADA --> 0x00FABADB
- 0xCACABACA --> 0xCACABACB
Esta es la forma típica de trabajar con elementos de memoria: primero se cargan a registros, ahí se hacen las operaciones, y luego se almacenan de nuevo en memoria (Arquitectura load-store)
En el programa contador del ejericio 1, se utilizaba la variable contador, almacenada en el segmento de datos. Ahora, en vez de almacenarlo en esa variable, hay que escribirlo en la dirección 0xFFFF0000, donde está el puerto de salida. En el simulador RARS NO hay ningún periférico en esa dirección, por lo que en nuestro programa simplemente veremos que la posición de la dirección 0xFFFF0000 se incrementa en cada pasada del bucle
##-- Solución al Ejercicio 4
##-- Contador que se envía por los LEDs
#-- DEFINICION de constantes
.eqv INICIO 100 #-- Valor de inicio del contador
.eqv INC 10 #-- Incremento del contador
.eqv LEDS 0xFFFF0000 #-- Direccion del puerto de salida
#------------------------ Código
.text
#-- X5: contador. Inicializar a INICIO
li x5, INICIO
#-- x6: Puntero para acceso al puerto de salida
li x6, LEDS
bucle:
#-- Sacar el contador actual por los LEDs
SW x5, 0(x6)
#-- Incrementar contador
addi x5, x5, INC
#-- Repetir bucle
b bucle
Al simularlo paso a paso vemos cómo la ventana inferior cambia y nos muestra la zona de E/S (MMIO). Ahí está nuestro contador, incrementándose de 10 en 10
El display derecho en el simulador RARs está en la dirección 0xFFFF0010, por lo que el programa es el mismo del ejercicio 4 pero cambiando la constante con la dirección del periférico
##-- Solución al Ejercicio 5
##-- Contador que se envía por el puerto del display
#-- DEFINICION de constantes
.eqv INICIO 0 #-- Valor de inicio del contador
.eqv INC 1 #-- Incremento del contador
.eqv DISPLAY 0xFFFF0010 #-- Direccion del puerto del display
#------------------------ Código
.text
#-- X5: contador. Inicializar a INICIO
li x5, INICIO
#-- x6: Puntero para acceso al Display
li x6, DISPLAY
bucle:
#-- Sacar el contador actual por el display
SW x5, 0(x6)
#-- Incrementar contador
addi x5, x5, INC
#-- Repetir bucle
b bucle
Lo ensamblamos y lo ejecutamos paso a paso. Observamos cómo se van encendido los segmentos del display
Para ciertos valores del contador, obtenemos dígitos y letras reconocibles:
Contador | Elemento en display |
---|---|
6 | Dígito 1 |
7 | Dígito 7 |
30 | Letra J |
63 | Dígito 0 |
79 | Dígito 3 |
91 | Dígito 2 |
95 | Letra a |
103 | Dígito 9 |
102 | Dígito 4 |
109 | Dígito 5 |
110 | Letra Y |
113 | Letra F |
115 | Letra P |
116 | Letra h |
118 | Letra H |
119 | Letra A |
121 | Letra E |
124 | Letra b |
125 | Dígito 6 |
126 | Dígito 8 |
(En el ejercicio no se trata de obtener todos, sino de reconocer unos cuantos y entender el funcionamiento)
En este ejercicio nos están pidiendo que calculemos los valores para sacar un 3, y luego para 1,2 y 4. Estos valores bien los podemos obtener ejecutando el ejercicio anterior hasta que aparezcan en el display, o bien los podemos calcular directamente dibujando los numeros y obteniendos los bits a 1 de los segmentos que hay que encender para que aparezca cada numo.
Así, para que aparezca el dígito 3 hay que encender los segmentos a,b,c,d y g, que se corresponden con los bits 0,1,2,3 y 6. El numero binario es: 01001111, Lo pasamos a hexadecimal: 0x4F. En decimal es 79
#-- Solucion al ejercicio 6
#-- Programa para mostrar por el display
#-- el digito 3
#-- CONSTANTES
.eqv DISPLAY 0xFFFF0010 #-- Direccion del puerto de salida del display
#-- Valore para que se muestren en el display los diferentes digitos
.eqv DIG3 0x4F #-- Digito 3
.text
#-- x5 es el puntero al display
li x5, DISPLAY
#-- Valor a sacar por el display
li x6, DIG3
#-- Sacarlo por el display
sw x6, 0(x5)
#-- Terminar
li a7, 10
ecall
Al ejecutarlo, vemos el dígito 3 en el display:
Calculamos el valor para el resto de dígitos que nos piden, y los almacenamos como constantes. Cambiando la constante que cargamos en el registro x6 comprobamos el número que sale en el display. Este programa de prueba está pensado para probar sólo un valor cada vez que se ejecuta
#-- Solucion al ejercicio 6
#-- Programa para mostrar por el display
#-- el digito 3
#-- CONSTANTES
.eqv DISPLAY 0xFFFF0010 #-- Direccion del puerto de salida del display
#-- Valore para que se muestren en el display los diferentes digitos
.eqv DIG1 0x06 #-- Digito 1
.eqv DIG2 0x5B #-- Digito 2
.eqv DIG3 0x4F #-- Digito 3
.eqv DIG4 0x66 #-- Digito 4
.text
#-- x5 es el puntero al display
li x5, DISPLAY
#-- Valor a sacar por el display
li x6, DIG3
#-- Sacarlo por el display
sw x6, 0(x5)
#-- Terminar
li a7, 10
ecall
Hay que escribir un programa para que salga por el display los digitos 1,2,3 y 4 consecutivamente, cuando se ejecuta paso a paso (¡Ojo! Si lo ejecutamos del tirón, si hacerlo paso a paso, no veremos cómo aparecen los dígitos)
Los valores para sacar los dígitos 1,2,3 y 4 los denotamos mediante las consatantes DIG1-DIG4 respectivamente. Creamos una tabla con 4 posiciones en el segmento de datos. Para acceder a estos elementos usaremos los offset 0, 4, 8 y 12, pero usando los identificadores E1-E4
##-- Solución al Ejercicio 7
##-- Leer los valores de una tabla y mostrar en el display
##-- Los valores de la tabla haran que en el display aparezcan
##-- los digitos 1,2,3 y 4
#-- Definiciones. Estos indetificadores nos permiten acceder
#-- directamente a los elementos de la tabla: E1, E2, E3 y E4
.eqv E1 0
.eqv E2 4
.eqv E3 8
.eqv E4 0xC
#-- Estos son las constantes para representar los digitos en el 7 segmentos
#-- Valore para que se muestren en el display los diferentes digitos
.eqv DIG1 0x06 #-- Digito 1
.eqv DIG2 0x5B #-- Digito 2
.eqv DIG3 0x4F #-- Digito 3
.eqv DIG4 0x66 #-- Digito 4
#-- Direccion del display
.eqv DISPLAY 0xFFFF0010
#----------------------- Variables
.data
#-- Tabla de 4 elementos, inicializados a ciertos valores
tabla:
.word DIG1
.word DIG2
.word DIG3
.word DIG4
#------------------------ Código
.text
#-- x5 es un puntero a la tabla (x5 contiene la direccion del primer elemento de la tabla)
la x5, tabla
#-- x6 es el puntero al display
li x6, DISPLAY
#-- Leer el primer elmento y sacarlo por el display
lw x10, E1(x5)
sw x10, 0(x6)
#-- Leer el segundo elemento y sacarlo por el display
lw x10, E2(x5)
sw x10, 0(x6)
#-- Leer el tercer elemento y sacarlo por el display
lw x10, E3(x5)
sw x10, 0(x6)
#-- Leer el cuarto elemento y sacarlo por el display
lw x10, E4(x5)
sw x10, 0(x6)
#-- Terminar
li a7, 10
ecall
Lo ensamblamos y lo ejecutamos paso a paso. Vemos cómo aparece la cuenta del 1 al 4 en el display
Este es el programa ampliado, para contar del 0 al 9
##-- Solución al Ejercicio 8
##-- Hacer que salga un contador del 0 al 9 por el display
##-- Usar una tabla
#-- Definiciones. Estos indetificadores nos permiten acceder
#-- directamente a los elementos de la tabla: E1, E2, E3, E4.....
.eqv E1 0
.eqv E2 4
.eqv E3 8
.eqv E4 0xC
.eqv E5 0x10
.eqv E6 0x14
.eqv E7 0x18
.eqv E8 0x1C
.eqv E9 0x20
.eqv E10 0x24
#-- Estos son las constantes para representar los digitos en el 7 segmentos
#-- Valore para que se muestren en el display los diferentes digitos
.eqv DIG0 0x3F #-- Digito 0
.eqv DIG1 0x06 #-- Digito 1
.eqv DIG2 0x5B #-- Digito 2
.eqv DIG3 0x4F #-- Digito 3
.eqv DIG4 0x66 #-- Digito 4
.eqv DIG5 0x6D #-- Digito 5
.eqv DIG6 0x7D #-- Digito 6
.eqv DIG7 0x07 #-- Digito 7
.eqv DIG8 0x7F #-- Digito 8
.eqv DIG9 0x6F #-- Digito 9
#-- Direccion del display
.eqv DISPLAY 0xFFFF0010
#----------------------- Variables
.data
#-- Tabla de 4 elementos, inicializados a ciertos valores
tabla: .word DIG0 #-- E1
.word DIG1 #-- E2
.word DIG2 #-- E3
.word DIG3 #-- E4
.word DIG4 #-- E5
.word DIG5 #-- E6
.word DIG6 #-- E7
.word DIG7 #-- E8
.word DIG8 #-- E9
.word DIG9 #-- E10
#------------------------ Código
.text
#-- x5 es un puntero a la tabla (x5 contiene la direccion del primer elemento de la tabla)
la x5, tabla
#-- x6 es el puntero al display
li x6, DISPLAY
#-- Leer el primer elmento y sacarlo por el display
lw x10, E1(x5)
sw x10, 0(x6)
#-- Leer el segundo elemento y sacarlo por el display
lw x10, E2(x5)
sw x10, 0(x6)
#-- Leer el tercer elemento y sacarlo por el display
lw x10, E3(x5)
sw x10, 0(x6)
#-- Leer el cuarto elemento y sacarlo por el display
lw x10, E4(x5)
sw x10, 0(x6)
lw x10, E5(x5)
sw x10, 0(x6)
lw x10, E6(x5)
sw x10, 0(x6)
lw x10, E7(x5)
sw x10, 0(x6)
lw x10, E8(x5)
sw x10, 0(x6)
lw x10, E9(x5)
sw x10, 0(x6)
lw x10, E10(x5)
sw x10, 0(x6)
#-- Terminar
li a7, 10
ecall
En esta animación lo vemos en funcionamiento
Es ejericicio es casi igual que el 8, pero con los elementos de la tabla en otro orden y con un bucle infinito para que la cuenta se repite indefinidamente
##-- Solución al Ejercicio 9
##-- Cuenta atrás en el display de 7 segmentos
##-- Al llegar a 0 vuelve a comenzar desde 9
#-- Definiciones. Estos indetificadores nos permiten acceder
#-- directamente a los elementos de la tabla: E1, E2, E3, E4.....
.eqv E1 0
.eqv E2 4
.eqv E3 8
.eqv E4 0xC
.eqv E5 0x10
.eqv E6 0x14
.eqv E7 0x18
.eqv E8 0x1C
.eqv E9 0x20
.eqv E10 0x24
#-- Estos son las constantes para representar los digitos en el 7 segmentos
#-- Valore para que se muestren en el display los diferentes digitos
.eqv DIG0 0x3F #-- Digito 0
.eqv DIG1 0x06 #-- Digito 1
.eqv DIG2 0x5B #-- Digito 2
.eqv DIG3 0x4F #-- Digito 3
.eqv DIG4 0x66 #-- Digito 4
.eqv DIG5 0x6D #-- Digito 5
.eqv DIG6 0x7D #-- Digito 6
.eqv DIG7 0x07 #-- Digito 7
.eqv DIG8 0x7F #-- Digito 8
.eqv DIG9 0x6F #-- Digito 9
#-- Direccion del display
.eqv DISPLAY 0xFFFF0010
#----------------------- Variables
.data
#-- Tabla de 4 elementos, inicializados a ciertos valores
tabla: .word DIG9 #-- E1
.word DIG8 #-- E2
.word DIG7 #-- E3
.word DIG6 #-- E4
.word DIG5 #-- E5
.word DIG4 #-- E6
.word DIG3 #-- E7
.word DIG2 #-- E8
.word DIG1 #-- E9
.word DIG0 #-- E10
#------------------------ Código
.text
#-- x5 es un puntero a la tabla (x5 contiene la direccion del primer elemento de la tabla)
la x5, tabla
#-- x6 es el puntero al display
li x6, DISPLAY
repetir:
#-- Leer el primer elmento y sacarlo por el display
lw x10, E1(x5)
sw x10, 0(x6)
#-- Leer el segundo elemento y sacarlo por el display
lw x10, E2(x5)
sw x10, 0(x6)
#-- Leer el tercer elemento y sacarlo por el display
lw x10, E3(x5)
sw x10, 0(x6)
#-- Leer el cuarto elemento y sacarlo por el display
lw x10, E4(x5)
sw x10, 0(x6)
lw x10, E5(x5)
sw x10, 0(x6)
lw x10, E6(x5)
sw x10, 0(x6)
lw x10, E7(x5)
sw x10, 0(x6)
lw x10, E8(x5)
sw x10, 0(x6)
lw x10, E9(x5)
sw x10, 0(x6)
lw x10, E10(x5)
sw x10, 0(x6)
b repetir
Lo simulamos a baja velocidad (3 instrucciones por segundo) y vemos la cuenta atrás...
Para conseguir la animación pedida, sólo hay encender un segmento cada vez. Y en el perímetro sólo hay 6 segmentos: a,b,c,d,e y f. Los valores a enviar para que se enciendan serán los de desplazar un bit a la izquierda: 0x01, 0x02, 0x04, 0x08, 0x10 y 0x20
##-- Solución al Ejercicio 10
##-- Animacion en el display
#-- Definiciones. Estos indetificadores nos permiten acceder
#-- directamente a los elementos de la tabla: E1, E2, E3, E4.....
.eqv E1 0
.eqv E2 4
.eqv E3 8
.eqv E4 0xC
.eqv E5 0x10
.eqv E6 0x14
.eqv E7 0x18
.eqv E8 0x1C
.eqv E9 0x20
.eqv E10 0x24
#-- Direccion del display
.eqv DISPLAY 0xFFFF0010
#----------------------- Variables
.data
#-- Tabla de 4 elementos, inicializados a ciertos valores
tabla: .word 0x01 #-- E1
.word 0x02 #-- E2
.word 0x04 #-- E3
.word 0x08 #-- E4
.word 0x10 #-- E5
.word 0x20 #-- E6
#------------------------ Código
.text
#-- x5 es un puntero a la tabla (x5 contiene la direccion del primer elemento de la tabla)
la x5, tabla
#-- x6 es el puntero al display
li x6, DISPLAY
repetir:
#-- Leer el primer elmento y sacarlo por el display
lw x10, E1(x5)
sw x10, 0(x6)
#-- Leer el segundo elemento y sacarlo por el display
lw x10, E2(x5)
sw x10, 0(x6)
#-- Leer el tercer elemento y sacarlo por el display
lw x10, E3(x5)
sw x10, 0(x6)
#-- Leer el cuarto elemento y sacarlo por el display
lw x10, E4(x5)
sw x10, 0(x6)
lw x10, E5(x5)
sw x10, 0(x6)
lw x10, E6(x5)
sw x10, 0(x6)
b repetir
Este es el aspecto que tiene la animación al ejecutar el programa a baja velocidad:
Solución a los ejercicios de la Sesión de laboratorio L5:2-2
Nos piden escribir un programa para calcular la expresión: f = (2*a - b) + c - 1. En ella hay 4 variables matemáticas: a, b,c y f. Para su implementación, como no nos lo piden explícitamente, usamos **registros **para los cálculos. ¿Qué registros? A partir de ahora siempre usaremos registros definidos en la ABI. Para hacer cáclulos temporales usaremos los registros del t0 al t6
#-- Ejercicio 1. Programa para calcular
#-- la expresion f = (2*a - b) + c - 1
#-- Para su evaluacion usar los valores:
#-- a=10, b=20, c=30
#-- Resultado: t5 = 29
.eqv EXIT 10
.text
#- Asignacion de registros:
#- t0 = a, t1 = b, t2 = c, t5 = f
#-- Inicializacion
li t0, 10 #-- a = 10
li t1, 20 #-- b = 20
li t2, 30 #-- c = 30
#----- Calculo de la expresion
#-- t0 = 2*a
add t0, t0, t0
#-- t3 = (2*a - b)
sub t3, t0, t1
#-- t4 = c - 1
addi t4, t2, -1
#-- t5 = (2*a - b) + c - 1
add t5, t3, t4
#-- Terminar
li a7, EXIT
ecall
Recuerda que se puede hacer de muchas formas, tantas como programadores haya 😉 Puedes utilizar los registros t0-t6 que quieras. Si para los cálculos itermedios no estás realizando llamadas al sistema, tambień podrías usar los registros a0-a7
Comprobamos que el cálculo es correcto. En el registro t5 se almacena el resultado final, que es 29, para los valores iniciales: a=10, b=20 y c=30
Desde el terminal de python comprobamos rápidamente que esto es así, con estos comandos:
a,b,c = 10,20,30
f = (2*a - b) + c - 1
f
Para calcular la suma de dos números tenemos que almacenarlos en dos registros de RISC-V y realizar la operación de suma. Podemos usar, por ejemplo, los registros t0 y t1. Como no nos dicen nada de variables, directamente usamos los registros
Para pedir al usuario los números invocamos al servicio READ_INT dos veces. Al pedir el primer número, el sistema operativa nos lo devuelve en el registro a0. Para no perder este valor, porque en la siguiete llamada al sistema se escribirá el segundo, lo guardamos en t0, usando la mv
#-- Suma de dos numeros introducidor por el teclado
#-- Códigos de servicio
.eqv EXIT 10
.eqv READ_INT 5
.eqv PRINT_INT 1
.text
#-- Pedir el primer numero al usuario
li a7, READ_INT
ecall
#-- El valor introducido se devuelve en a0
#-- t0 = primer numero
mv t0, a0
#-- Pedir el segundo numero
li a7, READ_INT
ecall
#-- t1 = segundo numero
mv t1, a0
#-- Realizar la suma
#-- a0 = t0 + t1
add a0, t0, t1
#-- Imprimir el numero en la consola
li a7, PRINT_INT
ecall
#-- Terminar
li a7, EXIT
ecall
Activamos la opción Setting/pop up dialog... para que sea más fácil. Lo ejecutamos y lo probamos con los valores 10 y 20. En la consola veremos esto:
**** user input : 10
**** user input : 20
30
En esta animación se muestra el programa en funcionamiento
- Desde la consola ejecutamos el programa de esta forma:
java -jar rars1_3_1.jar Ejercicio-02.s
RARS 1.3 Copyright 2003-2019 Pete Sanderson and Kenneth Vollmar
10
20
30
Program terminated by calling exit
Aunque para sumar dos números introducidos por el usuario no hace falta usar variables, en este ejercicio nos lo están pidiendo explicitamente. Nos dicen en qué orden se debe hacer. Lo que no nos digan explícitamente lo podemos implementar como queramos, y en el orden que queramos
#-- Suma de dos numeros introducidor por el teclado
#-- Los valores leidos se deben almacenar en las
#-- variables a y b. El resultado en f
#-- El resultado se saca por la consola
#-- Códigos de servicio
.eqv EXIT 10
.eqv READ_INT 5
.eqv PRINT_INT 1
#-- Cosntantes de acceso a las variables
.eqv VA 0
.eqv VB 4
.eqv VF 8
.data
#-- Variables. Inicializadas a 0
variables:
.word 0 #-- Variable a
.word 0 #-- Variable b
.word 0 #-- Variable f = a + b
.text
#-- s0: Puntero a las variables
la s0, variables
#-- Pedir el primer numero al usuario
li a7, READ_INT
ecall
#-- El valor introducido se devuelve en a0
#-- Almacenarlo en a
sw a0, VA(s0)
#-- Pedir el segundo numero
li a7, READ_INT
ecall
#-- Almacenarlo en b
sw a0, VB(s0)
#-- Realizar la suma. Nos indican explicitamente que leamos
#-- las variables
#-- t0 = a
lw t0, VA(s0)
#-- t1 = b
lw t1, VB(s0)
#-- Realizar la suma
#-- a0 = t0 + t1
add a0, t0, t1
#-- Almacenar la suma en F
sw a0, VF(s0)
#-- Imprimir el numero en la consola
li a7, PRINT_INT
ecall
#-- Terminar
li a7, EXIT
ecall
Al ejecutarlo, comprobamos que efectivametne las variables contienen lo que ha introducido el usuario, y el resultado de la suma:
En esta animación se muestra en funcionamento:
En el ejercicio 1 se nos pidió que evaluásemos la expresión f = (2*a - b) + c - 1 para unos valores iniciales. Bien, ahora se nos pide que se calcule para tres valores introducidos por el usuario
#-- Suma de dos numeros introducidor por el teclado
#-- Los valores leidos se deben almacenar en las
#-- variables a y b. El resultado en f
#-- El resultado se saca por la consola
#-- Códigos de servicio
.eqv EXIT 10
.eqv READ_INT 5
.eqv PRINT_INT 1
.text
#-- Pedir el primer numero al usuario
li a7, READ_INT
ecall
#-- El valor introducido esta en a0
#-- t0 = a
mv t0, a0
#-- Pedir el segundo numero
li a7, READ_INT
ecall
#-- t1 = b
mv t1, a0
#-- Pedir el tercer numero
li a7, READ_INT
ecall
#-- t2 = c
mv t2, a0
#----- Calculo de la expresion
#-- t0 = 2*a
add t0, t0, t0
#-- t3 = (2*a - b)
sub t3, t0, t1
#-- t4 = c - 1
addi t4, t2, -1
#-- t5 = (2*a - b) + c - 1
add t5, t3, t4
#-- Imprimir el resultado en la consola
#-- El numero a imprimir debe estar en a0
mv a0, t5
li a7, PRINT_INT
ecall
#-- Terminar
li a7, EXIT
ecall
Si se prueba con los valores 10,20 y 30, obtenemos el valor 29, que se mostró que es correcto
En esta animación se muestra el programa completo en funcionamiento:
En este programa hay que pedir un número entero al usuario, usando el servicio READ_INT y escribirlo en la dirección donde está mapeado el display de 7 segmentos derecho
#-- Ejercicio 5
#-- Pedir un numero entero al usuario
#-- y enviarlo tal cual al display de 7 segmentos derecho
#-- Test: el 255 (0xFF) debe encender todos los segmentos
#-- Direccion del display derecho
.eqv DISP_R 0xFFFF0010
.eqv EXIT 10
.eqv READ_INT 5
.text
#-- Pedir Numero al usuario
li a7, READ_INT
ecall
#-- El valor está en a0
#-- t0 = puntero para acceder al display
li t0, DISP_R
#-- Sacar el numero por el display
sw a0, 0(t0)
#-- Terminar
li a7, EXIT
ecall
Hacemos una comprobación introduciendo el número 255, que hace que se enciendan todos los segmentos y el punto
En esta animación lo vemos en funcionamiento. Se ejecuta dos veces, una introduciendo 255 y la otra 79, que se corresponde con el dígito 3
Esta es una forma fácil de experimentar con el display de 7 segmentos, y comprobar si un valor calculado efectivamente activa los segmentos que se quiere
Este tipo de programas, en los que hay que hacer varias acciones repetidas, los implementamos con bucles. Pero todavía NO lo sabemos hacer, así que lo hacemos sin bucles. El objetivo es practicar con las llamadas al sistema, y con el acceso a memoria
#-- Ejercicio 6: escribir en memoria las 4 palabras introducidas por
#-- el usuario. Luego leerlas e imprimirlas en la consola
#-- Códigos de servicio
.eqv EXIT 10
.eqv READ_INT 5
.eqv PRINT_INT 1
.eqv PRINT_CHAR 11
#-- Segmento de datos
.data
datos:
.text
#-- t0 es un puntero al comienzo del segmento de datos
la t0, datos
#-- Pedir valor al usuario
li a7, READ_INT
ecall
#-- Almacenar el numero en la direccion indicada por t0
sw a0, 0(t0)
#-- Incrementar t0 para apuntar a la siguiente palabra
addi t0, t0, 4
#-- Pedir valor al usuario
li a7, READ_INT
ecall
#-- Almacenar el numero en la direccion indicada por t0
sw a0, 0(t0)
#-- Incrementar t0 para apuntar a la siguiente palabra
addi t0, t0, 4
#-- Pedir valor al usuario
li a7, READ_INT
ecall
#-- Almacenar el numero en la direccion indicada por t0
sw a0, 0(t0)
#-- Incrementar t0 para apuntar a la siguiente palabra
addi t0, t0, 4
#-- Pedir valor al usuario
li a7, READ_INT
ecall
#-- Almacenar el numero en la direccion indicada por t0
sw a0, 0(t0)
#-- Incrementar t0 para apuntar a la siguiente palabra
addi t0, t0, 4
#------------- Ya estan todos los valores en la memoria
#-- Ahora los leemos y los imprimimos
#-- t0 apunta al comienzo de los datos
la t0, datos
#-- Leer palabra
lw a0, 0(t0)
#-- Imprimir palabra en la consola
li a7, PRINT_INT
ecall
#-- Imprimir una coma
li a0, ','
li a7, PRINT_CHAR
ecall
#-- Incrementar puntero t0
addi t0, t0, 4
#-- Leer palabra
lw a0, 0(t0)
#-- Imprimir palabra en la consola
li a7, PRINT_INT
ecall
#-- Imprimir una coma
li a0, ','
li a7, PRINT_CHAR
ecall
#-- Incrementar puntero t0
addi t0, t0, 4
#-- Leer palabra
lw a0, 0(t0)
#-- Imprimir palabra en la consola
li a7, PRINT_INT
ecall
#-- Imprimir una coma
li a0, ','
li a7, PRINT_CHAR
ecall
#-- Incrementar puntero t0
addi t0, t0, 4
#-- Leer palabra
lw a0, 0(t0)
#-- Imprimir palabra en la consola
li a7, PRINT_INT
ecall
#-- Incrementar puntero t0
addi t0, t0, 4
#-- Terminar
li a7, EXIT
ecall
En esta animación se muestra en funcionamiento:
Para recorrer el segmento de datos usamos un registro puntero, por ejemplo el t0. En cada pasada del bucle se incrementa t0 en 4 unidades para apuntar a la siguiente palabra
#-- Ejercicio 7: Volcado de memoria
#-- Situar 4 palabras en la memoria y hacer un bucle infinito que la vaya
#-- recorriendo mostrando en pantalla sus valores
#-- Usar el caracter de salto de linea para separar las palabras
#-- Códigos de servicio
.eqv EXIT 10
.eqv PRINT_INT 1
.eqv PRINT_CHAR 11
#-- Segmento de datos
.data
datos: .word 1,2,3,4,5,6,7,8,9,10
.text
#-- t0 es un puntero al comienzo del segmento de datos
la t0, datos
bucle:
#-- Leer palabra
lw a0, 0(t0)
#-- Imprimir el numero en la consola
li a7, PRINT_INT
ecall
#-- Imprimir el salto de linea
li a0, '\n'
li a7, PRINT_CHAR
ecall
#-- Incrementar el puntero
addi t0, t0, 4
#-- Bucle infinito
b bucle
Tras ejecutarlo con el Breakpoint, vemos en la consola cómo aparecen los números del 1 al 10, que estaban en la memoria. Luego se imprimen ceros, que es lo que hay en las posiciones de memoria consecutivas
En esta animación lo vemos en funcionamiento:
El programa es similar al que hemos hecho en ejercicios pasados, pero usando los registros t0, t1 y t2 para almacenar los términos de fibonacci
#-- Ejercicio 8. Calcular la secuencia de fibonacci e
#-- imprimirla en la consola
#-- Códigos de servicio
.eqv EXIT 10
.eqv PRINT_INT 1
.eqv PRINT_CHAR 11
#-- Valores de fibonacci iniciales
.eqv INI0 0
.eqv INI1 1
.text
#-- Usamos los registros t0 y t1 para los dos terminos anteriores
li t0, INI0
li t1, INI1
#-- Los terminos iniciales no se imprimen
bucle:
#-- calcular el siguiente termino
add t2, t1, t0
#-- Imprimir el siguiente termino
mv a0, t2
li a7, PRINT_INT
ecall
#-- Imprimir el caracter ,
li a0, ','
li a7, PRINT_CHAR
ecall
#-- Actualizar los terminos
mv t0, t1
mv t1, t2
#-- Bucle infinito
b bucle
Lo ejecutamos bien paso a paso (con Breakpoints) o bien a velocidad lenta y vemos cómo en la consola va apareciendo la serie de Fibonacci:
En esta animación se muestra en funcionamiento:
#-- Ejercicio 9. Cifrador sencillo
#-- Leer un caracter,incrementarlo en una unidad e imprimirlo en la consola
#-- Repetirlo en bucle infinito
#-- Códigos de servicio
.eqv READ_CHAR 12
.eqv PRINT_CHAR 11
.text
bucle:
#-- Leer caracter del usuario
li a7, READ_CHAR
ecall
#-- Incrementar el caracter recibido en una unidad
addi a0, a0, 1
#-- Imprimir el caracter en la consola
li a7, PRINT_CHAR
ecall
#-- Imprimir un salto de linea
li a0, '\n'
li a7, PRINT_CHAR
ecall
#-- Bucle infinito
b bucle
Después de haber introducido estos 4 caracteres: 'h', 'o', 'l' y 'a', en la consola veremos su siguiente letra en el alfabeto
En esta animación se muestra en funcionamiento:
Examinando la ayuda, vemos que el sistema operativo nos ofrece el servicio Print_IntHex, cuyo código es el 34, para imprimir un número entero en hexadecimal
#-- Ejercicio 10: Volcado de memoria en hexadecimal
#-- Usar el caracter de salto de linea para separar las palabras
#-- Códigos de servicio
.eqv EXIT 10
.eqv PRINT_INT 1
.eqv PRINT_CHAR 11
.eqv PRINT_INT_HEX 34
#-- Segmento de datos
.data
datos: .word 10,11,12,13,14,15,127,255,0x00FABADA, 0xCAFEBACA
.text
#-- t0 es un puntero al comienzo del segmento de datos
la t0, datos
bucle:
#-- Leer palabra
lw a0, 0(t0)
#-- Imprimir el numero en la consola
li a7, PRINT_INT_HEX
ecall
#-- Imprimir el salto de linea
li a0, '\n'
li a7, PRINT_CHAR
ecall
#-- Incrementar el puntero
addi t0, t0, 4
#-- Bucle infinito
b bucle
Esto es lo que sale en la consola, tras 11 iteraciones:
Y en esta animación lo vemos en funcionamiento:
Solución a los ejercicios de la Sesión de laboratorio L6:2-3
- Las cadenas en tiempo de compilación se definen con la directiva .string (.asciz es equivalente). El programa pedido es el siguiente:
#-- Solucion Ejercicio 1
.data
.string "Cadena 1"
.string "Cadena 2"
.string "Cadena 3"
- Ensamblamos el programa y observamos el contenido de la segunda palabra. En hexadecimal es: 0x3120616e
Si la vemos en ASCII, su contenido es: 1 an
- Lo podemos contar de varias formas. Una es contando los caracteres que hay en las cadenas, contabilizando también los '\0' de terminación de cada cadena. Así cada cadena tiene en total 9 bytes, y como hay 3 cadenas, nos sale un total de 9 * 3 = 27 bytes
También lo podemos contador directamente en el segmento de datos:
. Vemos que hay 6 palabras completas (6 * 4 = 24 bytes) más 3 bytes de la ultima palabra. Que hacen un total de 27 bytes
- Las cadenas se almacenan carácter a carácter, cada uno en una dirección consecutiva, y terminado en '\0'. Por tanto, en la memoria tendremos esto:
Direccion | Carácter |
---|---|
0x10010000 | 'C' |
0x10010001 | 'a' |
0x10010002 | 'd' |
0x10010003 | 'e' |
0x10010004 | 'n' |
0x10010005 | 'a' |
0x10010006 | ' ' |
0x10010007 | '1' |
0x10010008 | '\0' |
0x10010009 | 'C' |
0x1001000A | 'a' |
0x1001000B | 'd' |
0x1001000C | 'e' |
0x1001000D | 'n' |
0x1001000E | 'a' |
0x1001000F | ' ' |
0x10010010 | '2' |
0x10010011 | '\0' |
0x10010012 | 'C' |
0x10010013 | 'a' |
0x10010014 | 'd' |
0x10010015 | 'e' |
0x10010016 | 'n' |
0x10010017 | 'a' |
0x10010018 | ' ' |
0x10010019 | '3' |
0x1001001A | '\0' |
Que son exactamente 27 bytes
Las cadenas se definen en tiempo de compilación con .string (o .asciz, que es equivalente). Para imprimirlas se invoca dos veces al servicio de PrintString
#-- Solucion Ejercicio 2
.eqv PRINT_STRING 4
.eqv EXIT 10
.data
cad1: .string "Hola\n"
cad2: .string "Adios\n"
.text
#-- Imprimir la primera cadena
la a0, cad1
li a7, PRINT_STRING
ecall
#-- Imprimir la segunda cadena
la a0, cad2
li a7, PRINT_STRING
ecall
#-- Terminar
li a7, EXIT
ecall
En vez de usar "numeros mágicos" para los códigos de los servicios de EXIT y PrintString, se han definido identificadores, como ya sabemos hacer. Sin embargo, a partir de ahora estos códigos los incluiremos en un fichero separado (servicios.asm) y usaremos .include para incluirlos en nuestros programas. Así, el código quedaría de esta forma:
#-- Solucion Ejercicio 2
.include "servicios.asm"
.data
cad1: .string "Hola\n"
cad2: .string "Adios\n"
.text
#-- Imprimir la primera cadena
la a0, cad1
li a7, PRINT_STRING
ecall
#-- Imprimir la segunda cadena
la a0, cad2
li a7, PRINT_STRING
ecall
#-- Terminar
li a7, EXIT
ecall
Al ensamblarlo y ejecutarlo vemos las cadenas en la consola:
Hay que combinar los servicios de impresión de Cadena y lectura de un número entero. Al leer los números hay que llevar el valor devuelto en a0 a alguno de los registros para luego hacer la suma. Como no nos dice explícitamente que usemos variables, y no nos hacen falta, no las usamos
.include "servicios.asm"
.data
#-- Cadenas con los mensajes a imprimir en cada momento
msg1: .string "Introduce primer numero: "
msg2: .string "Introduce el segundo numero: "
msg3: .string "La suma es: "
.text
#-- Primer mensaje
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Pedir numero
li a7, READ_INT
ecall
#-- Guardar el primer numero en t1
mv t1, a0
#-- Segundo mensaje
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Pedir numero
li a7, READ_INT
ecall
#-- Guardar el segundo numero en t2
mv t2, a0
#-- Calcular la suma en t3
add t3, t1, t2
#-- Imprmir mensaje 3
la a0, msg3
li a7, PRINT_STRING
ecall
#-- Imprimir el resultado final
li a7, PRINT_INT
mv a0, t3
ecall
#-- Terminar
li a7, EXIT
ecall
Este ejercicio es para practicar con las cadenas definidas en tiempo de ejecución. Hay que usar la directiva .space para reservar espacio para su almacenamiento. Tenemos que calcular su tamaño máximo. En este ejericcio nos dicen explícitamente que el tamaño máximo debe ser de 1024. Si no nos dijeran, estbleceríamos nosotros su valor (un valor sensato)
- Este es el programa. Usamos la constante MAX para establecer el tamaño máximo. La usamos con la directiva .space y con el servicio READ_STRING. Así, si queremos establecer otro valor sólo hay que modificar esta constante al comienzo del programa
#-- Solucion ejercicio 4
#-- Lectura de una cadena
#-- Se pide al usuario que introduzca un texto
#-- que luego se imprime en la consola
#-- Codigo de servicios
.include "servicios.asm"
#-- Tamaño máximo del texto
.eqv MAX 1024
.data
#-- Mensajes de salida
msg1: .string "Introduce un texto: "
msg2: .string "Esto es lo que has escrito: \n"
#-- Texto introducido por el usuario
texto: .space MAX
.text
#-- Imprimir mensaje 1 pidiendo un texto
la a0, msg1
li a7, PRINT_STRING
ecall
#-- Leer texto introducido
la a0, texto
li a1, MAX
li a7, READ_STRING
ecall
#-- Imprimir mensaje 2
la a0, msg2
li a7, PRINT_STRING
ecall
#-- Imprimir texto introducido por el usuario
la a0, texto
li a7, PRINT_STRING
ecall
#-- Terminar
li a7, EXIT
ecall
- Cuando se introduce la cadena "Búsca el carácter X", el carácter 'X' está almacenado en la dirección 0x10010045
- La cadena ocupa 5 bytes (4 caracteres + el \0). A continuación hay definidos 4 bytes, por lo que el tamaño total es de 5 + 4 = 9 bytes. Esta es la posición de los elementos en el segmento de datos:
- En total los datos ocupan 3 palabras, aunque de la última sólo se usa un bytes
-
Los bytes almacenados, en orden, son '1','2','3','4','\0',0xAA,0xBB,0xCC, 0xDD
-
Al ejecutarlo se produce un error en tiempo de ejecución (una excepción). Estos errores se consideran graves, porque se aborta el programa por completo. En concreto, es un error de alineamiento de palabras
- Como no está claro el propósito del programa, porque el programador no ha puesto comentarios, vamos a analizar las diferentes alternativas. El error es debido a que se está intentando leer la palabra que está en la direcciónn 0x10010005, que NO está alineada. Una solución es alinearla, colocando .align 2:
#-- Solución ejercicio 5
.data
.string "1234"
#-- Solucion 1: Alinear la etiqueta v1
.align 2
v1: .byte 0xAA
.byte 0xBB
.byte 0xCC
.byte 0xDD
.text
la t0, v1
lw t1, 0(t0)
li a7,10
ecall
Otra solución sería sustituir los cuatro .byte por un .word, inicializado con el valor 0xDDCCBBAA
#-- Solución ejercicio 5
.data
.string "1234"
v1: .word 0xDDCCBBAA
.text
la t0, v1
lw t1, 0(t0)
li a7,10
ecall
- Otra posibilidaad es que el programador en realidad sólo quería leer el byte situado en v1, pero hay una errata y puso lw en lugar de lb. En ese caso hay que sustutir lw por lb y ya no se producirá el error de alineamiento
#-- Solución ejercicio 5
.data
.string "1234"
v1: .byte 0xAA
.byte 0xBB
.byte 0xCC
.byte 0xDD
.text
la t0, v1
lb t1, 0(t0)
li a7,10
ecall
En este ejericicio se nos pide que modifiquemos el cuarto carácter de una cadena definida en tiempo de compilación. Y es que aunque la cadena esté definida a priori, al estar en memoria, nuestros programas pueden acceder a ellas y modicarlas
Este es el programa:
#-- Solucion al ejercicio 6
#-- Código de los servicios del S.O
.include "servicios.asm"
.data
#-- Cadena definida en tiempo de compilacion
hola: .string "Hola\n"
.text
#-- Imprimir la cadena original
la a0, hola
li a7, PRINT_STRING
ecall
#-------- Modificar la 'a' por una 'i'
li t1, 'i' #-- Nuevo caracter
#-- La 'a' está 3 bytes adelante
sb t1, 3(a0)
#-- Imprimir la nueva cadena
la a0, hola
li a7, PRINT_STRING
ecall
#-- Terminar
li a7, EXIT
ecall
La solución general se haría usando un bucle, pero todavía no los hemos visto. Así que se hace carácter a carácter. El objetivo del ejericicio es practicar con la manipulación de cadenas sencillas. Cambiando el desplazamiento (offset) accedemos fácilmente a los diferentes caracteres, manteniendo el mismo puntero al comienzo de la cadena
#-- Solucion del ejercicio 7
#-- Cifrado sencillo de una cadena de 4 bytes,
#-- Simplemente se suma 1 a cada caracter
#-- Códigos de los servicios del S.O
.include "servicios.asm"
.data
msg: .string "Hola\n"
.text
#-- Puntero a la cadena
la a0, msg
#-- Imprimir el mensaje original
li a7, PRINT_STRING
ecall
#---------- CIFRADO
#-- Leer cada byte de la cadena, incrementarlo y guardarlo
lb t0, 0(a0)
addi t0, t0, 1
sb t0, 0(a0)
lb t0, 1(a0)
addi t0, t0, 1
sb t0, 1(a0)
lb t0, 2(a0)
addi t0, t0, 1
sb t0, 2(a0)
lb t0, 3(a0)
addi t0, t0, 1
sb t0, 3(a0)
#-- Imprimir el mensaje cifrado
li a7, PRINT_STRING
ecall
#-- Terminar
li a7, EXIT
ecall
Este es el programa:
#-- Solucion al ejercicio 8
#-- Código de servicios del S.O
.include "servicios.asm"
.data
#-- Definir una palabra
v1: .word 0xCADACAFE
v2: .half 0xBACA
v3: .byte 0xEA
.text
#-- Incrementar la palabra
la t0, v1
lw t1, 0(t0)
addi t1,t1,1
sw t1, 0(t0)
#-- Incrementar la media palabra
la t0, v2
lh t1, 0(t0)
addi t1,t1,1
sh t1, 0(t0)
#-- Incrementar el byte
la t0, v3
lb t1, 0(t0)
addi t1,t1,1
sb t1, 0(t0)
#-- Terminar
li a7, EXIT
ecall
Al ensamblarlo, el segmento de datos contiene los valores iniciales:
Al ejecutarlo, se incrementan las tres variables, y lo vemos en la memoria:
El acceso a ambos displays lo tenemos que hacer usando sb, porque son puertos de salida de byte. No nos piden sacar dígitos, sino simplemente escribir el valor de dos contadores a los puerto de salida, por lo que se encenderán diferentes segmentos, sin formar dígitos necesariamente
#-- Solucion al ejercicio 9
#-- Se tienen dos contadores, uno empieza en 0 y el otro en 1
#-- que se van incrementando en cada pasada de un bucle
#-- infinito. Estos valores se deben escribir en los puertos
#-- de salida de los displays Derecho e izquierdo, respectivamente
#-- Direccion base de acceso a los displays
.eqv BASE 0xFFFF0010
#-- Desplazamientos de acceso a los displays
.eqv DISP_R 0
.eqv DISP_L 1
.text
#-- Registro t0 para acceder a los displays de 7 segmentos
li t0, BASE
#-- Contador 1 en registro t1. Inicializado a 0
li t1, 0
#-- Contador 2 en registro t2. Inicializado a 1
li t2, 1
bucle: #-- Escribir contadores en los puertos de salida de los displays
sb t1, DISP_R(t0)
sb t2, DISP_L(t0)
#-- Incrementar los contadores
addi t1, t1, 1
addi t2, t2, 1
#-- Repetir
b bucle
Lo ensamblamos y lo ejecutamos a baja velocidad, para ver los segmentos de los displays. En esta animación lo vemos en funcionamiento:
Se leen las teclas de la primera fila y su código se saca por el display izquierdo. No se pide que salgan dígitios, sino que simplemente se escriba el código de la tecla en el puerto de salida del display izquierdo
#-- Solucion al ejercicio 10
#-- Leer las teclas de la primera fila del teclado hexadecimal
#-- y escribir su código en el puerto de salida del display
#-- izquierdo
#-- Direccion base de acceso a perifericos
.eqv BASE 0xFFFF0010
#--- Offset para accdeder a los diferentes perifericos
#-- Display izquierdo
.eqv DISP_L 01 #-- BASE + 1
#-- Seleccion de la fila
.eqv KEY_ENA 02 #-- BASE + 2
#-- Lectura del codigo de tecla
.eqv KEY_RD 04 #-- BASE + 4
.text
#-- Puntero base de acceso a perifericos
li t0, BASE
#-- Bucle infinito que está constntemente leyendo la
#-- primera fila
bucle:
#-- Seleccionar la fila 1
li t1, 01
sb t1, KEY_ENA(t0)
#-- Leer la tecla
lb t2, KEY_RD(t0)
#-- Escribir el código en el display izquierdo
sb t2, DISP_L(t0)
b bucle
En esta animación se muestra en funcionamiento
- 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