01/03/2012 1 Ejemplo 2 Escriba un programa que realice las siguientes operaciones Lea 10 números Los almacene en memoria Proporcione la suma de los 10 números PROCEDIMIENTOS UNIDAD 3 PRIMAVERA 2012 .data array: .space 40 str1: .asciiz “Proporcione un numero: ” str2: .asciiz “Las suma total es : ” Arquitectura de computadoras .text .globl main main: loop: imprime: li li $s1,0 # Inicializa suma = 0 li $t0, 0 # inicializa el contador la la $s0, array $v0,4 # inicializa el apuntador syscall slti $t1, $t0, 10 # verifica si t0 < 10 li beq $t1,$zero, imprime # si t0 >= 10 sale del ciclo add $a0, $zero, $s1 li $v0,4 # Imprime la cadena 1 syscall la $a0,str1 li syscall li $v0,5 # Imprime la cadena 2 $a0,str2 $v0,1 $v0, 10 # Muestra el resultado # transfiere el resultado a a0 # Termina el programa syscall # Lee un numero entero syscall add $s1,$s1,$v0 # suma = suma + numero sw $v0,0($s0) # almacena el numero addi $s0,$s0,4 # incrementa el apuntador addi $t0,$t0,1 # incrementa el contador j 3 loop 4 .text Ejemplo .globl main main: 5 Escribe un programa que realice las siguientes operaciones Lea 10 números Almacene los números en memoria Verifique cuantos números son mayores que 20 Muestra todos los números que son mayores de 20 loop: .data array: .space 40 numeros: .space 40 str1: .asciiz “Proporcione un numero: ” str2: .asciiz “La cantidad de numeros mayores de 20 es: “ str3: .asciiz “Los numeros mayores de 20 son: ” str4: .asciiz “\n” str5: .asciiz “, “ li $s2,0 # Inicializa contador de numeros li $t0, 0 # inicializa el contador li $s3, 20 # almacena la constante 20 la $s0, array # inicializa el apuntador la $s1, numeros # inicializa el apuntador a > 20 slti $t1, $t0, 10 # verifica si t0 < 10 beq $t1,$zero, result # si t0 >= 10 sale del ciclo li $v0,4 # Imprime la cadena 1 la $a0,str1 syscall li $v0,5 # Lee un numero entero syscall 6 sw $v0,0($s0) # almacena el numero slt # compara el numero con 20 $t2, $s3, $v0 1 01/03/2012 update: result: beq $t2,$zero,update # lee le siguiente numero addi $s2,$s2,1 # incrementa el contador de num sw # almacena los numeros mayores $v0,0($s1) addi $s1,$s1,4 # incrementa el apuntador a num addi $s0,$s0,4 # incrementa el apuntador addi $t0,$t0,1 # incrementa el contador j loop li $v0,4 la $a0,str2 $v0,1 add $a0, $zero, $s2 $v0,4 la $a0,str4 $t0, 0 # inicializa el contador la $s1, numeros # inicializa el apuntador a > 20 lw $a0,0($s1) li $v0,1 li $v0,4 # Muestra el resultado la $a0,str5 # transfiere el resultado a a0 syscall # Imprime una alimento de linea exit: 8 addi $t0,$t0,1 # incrementa el contador addi $s1,$s1,4 # incrementa el apuntador j imprime li $v0, 10 .globl main Escriba un programa que realice las siguientes operaciones li $t0, 0 # inicializa el contador li $v0,4 # Imprime la cadena 1 la $a0,str1 syscall Lea una cadena Proporcione la longitud de la cadena li $v0,8 la $a0,cadena li $a1,50 la $s0,cadena lb $s1,0($s0) cadena: .space 50 str1: .asciiz “Proporcione una cadena: ” str2: .asciiz “La longitud de la cadena es : “ addi $s0,$s0,1 str3: .asciiz “\n” bne loop: addi $t0,$t0,1 $s1,$zero, loop addi $t0,$t0,-2 # Imprime la cadena 2 syscall li $v0,1 # Obtén el carácter de la cadena # incrementa el contador #Compruebo si es el final de la cadena # resto 2 uno por el alimento de línea (enter) # otro por el uno de mas para terminar el ciclo 10 $a0,str2 # Lee la cadena syscall .data $v0,4 # Imprime la cadena 1 syscall main: la # si t0 >= 10 sale del ciclo .text 9 li # verifica si t0 < s2 syscall Ejemplo # Imprime la cadena 3 li beq $t1,$zero, exit # Imprime la cadena 2 syscall 7 $a0,str3 imprime: slt $t1, $t0, $s2 syscall li $v0,4 la syscall syscall li li Ejercicio 12 # Imprime la longitud syscall Escriba un programa que realice las siguientes acciones: li add $a0,$zero,$t0 $v0,10 syscall Lea una cadena Imprima la cadena en orden inverso 11 2 01/03/2012 Solución 13 longitud: .space 50 reves: .space 50 str1: .asciiz “Proporcione una cadena: ” bne $s1,$zero, longitud addi $t0,$t0,-1 li .asciiz “La cadena al reves es: “ # Obtén el carácter de la cadena # incrementa el contador #Compruebo si es el final de la cadena # ajustar la longitud $t1,0 addi $s0,$s0,-2 .text imprime: .globl main la $s2,reves slt $t2, $t1, $t0 # incializa el apuntador a la cadena reves li $t0, 0 # inicializa el contador beq $t2, $zero, exit li $v0,4 # Imprime la cadena 1 lb $s1,0($s0) # obtén el último carácter la $a0,str1 sb $s1,0($s2) # almacenalo al principio de la cadena reves syscall li $v0,8 la $a0,cadena li $a1,50 # Lee la cadena sb $zero,0($s2) # almacena el fin de cadena li $v0,4 # Imprime la cadena 2 la $a0,str2 $v0,4 ls $a0,reves # incrementa el apuntador a la cadena reves addi $t1,$t1,1 # incrementa el contador imprime Procedimientos # Imprime la cadena al reves Convenciones de la llamada a procedimientos Convenciones seguidas por software pero no reforzadas por hardware Es una serie de reglas que nos indican que registros usar para el paso de parámetros La convención usada es la que el compilador gcc emplea. Otros compiladores pueden emplear reglas un poco diferentes Las letras de los registros representan el propósito de los registros dentro de la convención syscall li # decrementa el apuntador a la cadena original addi $s2,$s2,1 16 syscall li addi $s0,$s0,-1 j 14 syscall exit: $s1,0($s0) addi $s0,$s0,1 cadena: main: $s0,cadena lb addi $t0,$t0,1 .data str2: la $v0,10 syscall 15 17 Convenciones de la llamada a procedimientos Los registros $at, $k0 y $k1 son reservados para el ensamblador y el sistema operativo. Ninguno debe ser empleado en un programa 18 Convenciones de la llamada a procedimientos Registros $a0 – $a3 son usados para enviar los primeros 4 argumentos al procedimiento. (En caso de existir mas de 4 argumentos, se usará el stack para la transmisión de los argumentos restantes) Los registros $t0 – $t9 son registros temporales cuyos valores no deben ser preservados durante las llamadas a procedimiento Registros $s0 a $s7 son registros cuyos valores deben ser preservados durante llamadas a los procedimientos. En caso de usar registros $s0 – $s7 dentro de un registro, entonces sus valores deberán ser guardados en el stack antes de ser usados Registro $sp es el apuntador al stack Registro $ra guarda la dirección de regreso de un procedimiento 3 01/03/2012 Procedimientos 19 Llamadas a Procedimientos 20 Para llamar a un procedimiento se deben realizar las siguientes acciones main: syscall Pasar los valores por medio de los registros $a0 -$a3 En caso de ser necesario, el resto de los argumentos deben ser colocados en el stack Guardar registros $t0-$t9 y $a0-$a3 Esto solo se realiza si el programa principal usará estos valores después de la llamada al procedimiento Ejecutar la instrucción jal Esta instrucción es un salto incondicional que realiza la llamada a la subrutina li $v0,4 la $a0,str Pasar los argumentos Realiza la llamada a la subrutina y guarda la dirección de regreso en el registro $ra exit: imprime: slt $t2, $t1, $t0 beq $t2, $zero, exit lb $t3,0($t4) sb $t3,0($t5) add $a0,$zero,$t0 addi $t4,$t4,-1 la $a1,array addi $t5,$t5,0 jal imprime addi $t1,$t1,1 exit: li j imprime jr $ra $v0,10 syscall Pila (Stack) 21 Marco de Llamada al Procedimiento 22 La pila es un sección de memoria reservada para: Intercambio de argumentos entre procedimientos Guardar temporalmente valores de registros Guardar valores de registros específicos durante interrupciones Los procedimientos requiere de una sección del stack reservada para cada procedimiento que es llamada Marco de Llamada al Procedimiento Esta sección contiene: La pila consiste en una serie de locaciones de memoria manejadas como (LIFO) Last-input-FirstOutput. El primero en entrar es el ultimo en salir El valor de los argumentos que son pasados al procedimiento El valor de los registros que no se deben modificar Proveer espacio para las variables locales de un procedimiento Marco de Llamada al Procedimiento Marco de Llamada al Procedimiento 23 24 El procedimiento (función) debe establecer el marco por medio de las siguientes acciones: Reservar memoria para el marco por medio de restar el tamaño deseado del marco del valor del apuntador al stack ($sp) sp sp frame _ size Guardar los registros $fp $ra solo si la función llamara a otra función $s0 - $s7 solo si estos registros son usados dentro de la función Este marco esta delimitado por el frame pointer $fp y el stack pointer $sp. $sp marca el final del marco mientras que $fp marca el inicio del marco El ultimo paso para establecer el marco del procedimiento es establecer el valor de $fp fp sp frame _ size 4 4 01/03/2012 Procedimiento Ejemplo 25 26 El procedimiento debe ejecutar los siguientes pasos: Si el procedimiento es una función que regresa un valor, entonces el valor debe ser almacenado en el registro $v0 Restaurar todos los registros salvados antes del procedimiento Regresar el valor original de registro $sp Regresar a la dirección de retorno por medio de la instrucción jr $ra Los argumentos del procedimiento son: $a0 tendrá la cantidad de números que deberán ser leídos $a1 la dirección de memoria donde se almacenaran los números Un procedimiento llamado WRITE que lea N números de memoria y los imprima en pantalla Los argumentos del procedimiento son: $a0 tendrá la cantidad de números que serán impresos $a1 la dirección de memoria donde se encuentran almacenados los números # Función write # Esta función leerá N números almacenados en memoria y los desplegara en pantalla # Argumentos: a0 --- cantidad de números # a1 --- dirección donde se encuentran los números # a2 --- dirección de la cadena de separación entre números Write 27 28 write: # Función read # Esta función leerá N números y los almacenados en memoria # Argumentos: a0 --- cantidad de números # a1 --- dirección donde se almacenaran los números loop: Un procedimiento llamado READ que lea N números y los almacene en memoria Read read: Realice un programa que utilice dos procedimientos que hagan los siguiente li loop: # inicializa el contador # pasa el valor de a0 a t2 stl # compara si t0 < t2 $t1,$t0,$t2 # inicializa el contador beq $t1,$zero, exit add $t2,$zero,$a0 # pasa el valor de a0 a t2 lw $a0,0($a1) # obtiene el número de memoria stl # compara si t0 < t2 li $v0, 1 # imprimo el número en pantalla beq $t1,$zero, exit # si la condición no se cumple se sale syscall li $v0, 5 # lee un entero # imprime la cadena separador $v0,0($a1) # almacena el número en memoria li $v0,4 add $a0,$a2,$zero syscall addi $a1,$a1,4 # actualizo apuntador addi $t0, $t0,1 # incremento contador j loop # regreso a probar condición jr $ra li $t0, 0 $t1,$t0,$t2 syscall sw exit: $t0, 0 add $t2,$zero,$a0 addi $a1,$a1, 4 # actualizo apuntador addi $t0, $t0, 1 # incremento contador j loop # regreso a probar condición jr $ra exit: Programa principal li $v0, 4 # imprime la cadena 1 la $a0,str1 Programa principal# para pedir los números syscall li $a0,10 # pasa los argumentos, cantidad .data la $a1,array # y dirección array: .space 40 jal read # llama al procedimiento str1: .asciiz “ Proporciona 10 numeros” str2: .asciiz “Los numeros fueron:” # imprime la cadena 2 # los números fueron str3: .asciiz “, “ li $v0, 4 la $a0,str2 syscall li $a0,10 # pasa los argumentos, cantidad, la $a1,array # dirección y cadena de separación la $a2,str3 29 30 .text .globl main main: subu $sp,$sp,32 sw $ra, 20($sp) sw $fp, 16($sp) addiu $fp, $sp,28 # define le marco del programa jal write # llama al procedimiento lw $ra,20(sp) # restablece el stack lw $fp,16(sp) addiu $sp,$sp,32 jr $ra # regresa al sistema operativo 5 01/03/2012 # Función length # Esta función determina la longitud de una cadena # Argumentos: a0 --- dirección inicial de la cadena Ejemplo length: 31 Realice un programa que utilice los siguientes procedimientos argumentos del procedimiento son: longitud: $a0 la dirección inicial de la cadena min2may, cambie las letras minúsculas a mayúsculas Los argumentos del procedimiento son: $sp,$sp,32 sw $fp, 20($sp) sw $s0, 16($sp) # define le marco de la función addiu $fp, $sp,28 Length, determine la longitud de una cadena Los subu $a0 dirección inicial de la cadena add $s0,$a0,$zero li $v0,0 lb $t1,0($s0) # Obtén el carácter de la cadena addi $v0,$v0,1 # incrementa el contador addi $s0,$s0,1 bne $t1,$zero, longitud #Compruebo si es el final de la cadena addi $v0,$v0,-2 # ajustar la longitud lw $s0,16(sp) lw $fp,20($sp) addiu $sp,$sp,32 jr 32 for: Función min2may 33 # Función min2may # Esta cambia las letras minúsculas en mayúsculas # Argumentos: a0 --- dirección inicial de la cadena min2may: subu $sp,$sp,32 sw $fp, 20($sp) sw sw $s0, 16($sp) $ra, 12($sp) # define le marco de la función update: addiu $fp, $sp,28 $ra slt $t2,$t0,$v0 # compara si el contador es menor que v0 beq $t2,$zero,exit # Obtén el carácter de la cadena lb $t1,0($s0) # incrementa el contador slti $t2,$t1,123 # Es una letra menor que „z‟ beq $t2,$zero, update slt $t2,$t4, t1 beq $t2,$zero, update addi $t1,$t1,-32 # resta -32 para obtener letras mayusculas sb $t1,0($s0) # almacena el resultado addi $t0,$t0,1 # incrementa el contador addi $s0,$s0,1 # actualiza el apuntador j for add jal $s0,$a0,$zero length lw $ra,12(sp) #obten la longitud de la cadena en v0 lw $s0,16(sp) li $t0, 0 # inicializa contador lw $fp,20($sp) # Es una letra mayor que „a‟ addiu $sp,$sp,32 34 Programa principal jr $ra li $v0, 4 # imprime la cadena 1 # lee la cadena la $a0,str1 Programa principal# para pedir la cadena syscall li $v0,8 .data la $a0, cadena cadena: .space 50 li $a1,50 str1: .asciiz “ Proporciona una cadena” syscall str2: .asciiz “La cadena en mayusculas es :” la $a0, cadena str3: .asciiz “, “ jal min2may .text li $v0, 4 la $a0,str2 syscall # imprime la cadena 2 li $v0, 4 la $a0,cadena syscall # imprime la leída en mayúsculas lw $ra,20(sp) # restablece el stack lw $fp,16(sp) 35 36 .globl main main: subu $sp,$sp,32 sw $ra, 20($sp) sw $fp, 16($sp) addiu $fp, $sp,28 # define le marco del programa addiu $sp,$sp,32 jr $ra # regresa al sistema operativo 6