Organización de computadoras
22/03/2018
Proyecto 1
Antecedentes:
Para realizar este proyecto se utilizaron pseudo instrucciones de MIPS que SPIM las
implementa, por lo tanto estas no fueron analizadas en clase. A continuación, se va a dar una
pequeña explicación de estas y de cómo se utilizan.
Por lo general se utilizan estos códigos para hacer que una variable sea igual a un número
y posteriormente utilizar esta variable con los system calls, que se usaran para imprimir y guardar
los inputs del usuario.
Además, para la realización de este proyecto se realizó una investigación sobre diferentes
formas de aplicar las funciones en código assembly.
Serie de Fibonacci
El código funciona con dos data type para poner los strings que se van a imprimir en consola. Además, el
código tiene una estructura lineal en la que se hacen los system calls y se llama a la función Fibonacci.
Dentro de esta función se realizan las llamadas recursivas. En Fibonacci al principio de su sección se
aumenta el tamaño de la pila y se vuelve a llamar a sí misma la misma función, al final de la función
cuando se terminan las llamadas recursivas se llama a otra función en la que se liberan las posiciones de
la pila.
Codigo
.data
string1: .asciiz "Ingresa el numero para realizar fibonaci\n"
string2: .asciiz "El valor de fibonaci es:\n"
.text
# Imprimir string1
main:li $v0, 4
la $a0, string1
syscall
# leer input
li $v0, 5
syscall
# Imprimir string2
li $v0, 4
la $a0, string2
syscall
# Imprimir resultado
li $v0, 1
addiu $a0, $a1, 0
syscall
# Exit
li $v0, 10
syscall
fibonacci:
addi $sp, $sp, -12
sw $ra, 8($sp)
sw $s0, 4($sp)
sw $s1, 0($sp)
addiu $s0, $a0, 0
li $v0, 1
fibonacciExit:
# liberamos los espacios ocupados en el heap
lw $ra, 8($sp)
lw $s0, 4($sp)
lw $s1, 0($sp)
addi $sp, $sp, 12
jr $ra
#Termina función Fibonacci
Resultado:
Analizando los datos encontrados anteriormente encontramos que el valor más pequeño que tiene $sp
es 0x7ffff284, ya que la pila crece de forma descendente el valor más pequeño será en el punto en el
que este más grande. Por lo tanto, el tamaño máximo de la pila es: 6010 o 0x3c
Para este código se basó en un código hecho en c para entender el funcionamiento y luego transferirlo a
MIPS.
# codigo en c
# if (num_of_disks == 1)
# move disk to end_peg
# else
# hanoi(num_of_disks-1, start_peg, extra_peg, end_peg)
# move disk from start_peg to end_peg
# hanoi(num_of_disks-1, extra_peg, end_peg, start_peg)
Como se ve en el código anterior se observa que las llamadas recursivas son a la misma pero los
argumentos cambian. Por lo tanto, en el codigo se van cambiando los valores de $a0, $a1, $a2, $a3
antes de hacer las llamadas recursivas.
Además se tiene dos data types string , Move, y A, también ponemos al label mande forma global.
Después se realizan una serie de system calls para imprimir y recibir los valores de input. Se tienen dos
funciones una llamada Hanoi y otra llamada Else que implementan la misma lógica que el código en C
presentado anteriormente. Dentro de estas funciones se manipula constantemente los valores de las
variables de tipo $a y también se cambian las posiciones de la pila; con los valores de la pila se van
actualizando los datos de $a en las llamadas recursivas. Finalmente se tiene un control permanente
sobre el valor de $ra. El programa termina cuando se termina la primera llamada a hanoi.
Además, en este código se utiliza la pseudo instrucción “move” que equivale a addiu $s, $a,0. Utilizar
move es más intuitivo para entender el funcionamiento.
Código
.data
string:
Move:
A:
.ascii "a"
.globl main
.text
main:
#Print string
li $v0, 4
la $a0, string
syscall
li $v0, 5
syscall
#llamamos a hanoi
jal hanoi
li $v0, 10
syscall
hanoi:
# codigo en c
# if (num_of_disks == 1)
# else
# if (num_of_disks == 1)
#imprimo move
li $v0, 4
la $a0, Move
syscall
li $v0, 1
syscall
#imprimo A
li $v0, 4
la $a0, A
syscall
li $v0, 1
syscall
#reinicio $a0
#regreso
jr $ra
else:
sw $ra, 16($sp)
#torre extra
sw $a3, 12($sp)
#torre final
sw $a2, 8($sp)
#torre de origen
sw $a1, 4($sp)
sw $a0, 0($sp)
#hanoi(num_of_disks-1, start_peg, extra_peg, end_peg)
#n--
jal hanoi
lw $ra, 16($sp)
lw $a3, 12($sp)
lw $a2, 8($sp)
lw $a1, 4($sp)
lw $a0, 0($sp)
# print move
li $v0, 4
la $a0, Move
syscall
# imprimo torre origen
li $v0, 1
syscall
#imrimo A
li $v0, 4
la $a0, A
syscall
li $v0, 1
syscall
jal hanoi
#Cambio el ra
lw $ra, 16($sp)
#Limpiamos el stack
#return
jr $ra
Resultado
Inicial 0x 7ffff2d4
2 0x 7ffff2c0
3 0x 7ffff2ac
4 0x7ffff2c0
5 0x7ffff2ac
Final 0x7ffff2c0
Analizando los datos encontrados anteriormente encontramos que el valor más pequeño que tiene $sp
es 0x7ffff2ac, ya que la pila crece de forma descendente el valor más pequeño será en el punto en el
que este más grande. Por lo tanto, el tamaño máximo de la pila es: 4010 o 0x28
Para la siguiente pregunta analizo los dos programas al mismo tiempo ya que de esa manera
se ven los datos relevantes de mejor manera.
1. Cualquier información relevante sobre los segmentos de código y datos del kernel.
Kernel data
Con los datos recolectados podemos ver que los datos de kernel siempre empiezan en el mismo
lugar y tienen el mismo tamaño. Por lo tanto, sin importar que tipo de código se realice y de qué
tamaño tenga el mismo, el kernel data nos quitara 0x1f0 de posiciones disponibles para trabajar.
Datos de usuarios:
Realizando el código de Fibonacci tuve un error en la sitanxis del nombre donde primero escribí
como fibonaci y no Fibonacci. Pero esto me hizo darme cuenta de algo interesante en la forma
en la que guardan los user data en los registros del mips.
Registro 1 posición 2 posición 3 posición 4 posición
10010020
Como se puede ver en el grafico anterior y en los dos screenshots, el cambio de una “C” parece
pequeño, pero es significativo. En la segunda posición se puede ver la primera diferencia la cual
es de 0x0600000. Pero en la siguiente posición ya existe un cambio de dos posiciones en el valor
hexadecimal ma63616e s significativa. Y en las demás posiciones siguen apareciendo cambios.
Además, se observa que en mips los datos se los analiza no en base a su posición en el registro
es decir 10010020 o 10010040 sino en los bytes de los que están compuestos estos registros, ya
que en el registro 10010020 hay dos tipos de “.data” en la misma posición. Es decir, “Fibonacci”
es del string1 y “El va” es del string2.
Referencias
AaronFoltz. (9 de Agosto de 2011). Towers-of-Hanoi. Obtenido de
https://github.com/AaronFoltz/Tower-of-Hanoi/blob/master/hanoi.s