Ejemplos de Programación en Ensamblador MIPS
Enviado por Chuletator online y clasificado en Informática y Telecomunicaciones
Escrito el en español con un tamaño de 14,53 KB
Conversión y Empaquetado de Entero
Este fragmento de código parece intentar procesar un número entero y realizar operaciones bit a bit y aritméticas. La descripción original sugiere una conversión a un formato empaquetado, posiblemente decimal, aunque la lógica específica puede variar.
# Convierte el entero en "palabra" a un formato procesado
.data
palabra: .word 1492
.text
.globl main
main:
lw $t0, palabra
li $t5, 0 # Vale 0 si palabra >= 0, 1 en caso contrario
beqz $t0, siga
li $t5, 1
mul $t0, $t0, -1
siga:
li $t1, 0 # Luego valdrá 4, 8 y así... para el shift variable
li $t1, 0 # Contador vale 0, 1, 2, 3, 4, 5, 6, 7
li $t3, 0
loop:
div $t0, $t0, 10
mfhi $t4
sllv $t4, $t4, $t1
or $t3, $t3, $t4
addi $t1, $t1, 4
ori $t3, $t3, 0x0d
beq $t5, 1, siga2
ori $t5, $t3, 0x0f
siga2:
addi $t2, $t2, 1
ble $t2, 6, loop
ori $t3, $t3, 0x0f
li $v0, 10
syscall
Contador de Vocales en una Cadena
Este código cuenta la cantidad de vocales en una cadena de texto utilizando una tabla de búsqueda.
# CONTADOR DE VOCALES
.data
cadena: .asciiz "RAPIDO CORREN LOS CARROS DEL FERROCARRIL"
mensaje: .asciiz "La cantidad de vocales es ... "
tabla: .space 65
.byte 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0
.space 165
.text
.globl main
main:
li $t0, 0 # Registro apuntador a los diversos elementos de cadena
li $t1, 0 # Contador de vocales
loop:
lb $t2, cadena($t0)
beqz $t2, termina
lb $t3, tabla($t2)
add $t1, $t1, $t3
addi $t0, $t0, 1
b loop
termina:
la $a0, mensaje
li $v0, 4
syscall
move $a0, $t1
li $v0, 1
syscall
li $v0, 10
syscall
Definición de Macros
Este segmento define varias macros reutilizables para tareas comunes como finalizar el programa, sumar y mostrar un valor.
.macro done # POTENCIA (Comentario original, la macro solo finaliza)
li $v0, 10
syscall
.end_macro
.macro sumar
add $t1, $t2, $t1
.end_macro
.macro mostrar
move $a0, $t1
li $v0, 1
syscall
.end_macro
Cálculo de Potencia (Base^Exponente)
Este código calcula la potencia de un número base elevado a un exponente, solicitando ambos valores al usuario.
.data
msj: .asciiz "Numero base: "
msj2: .asciiz "Numero exponente: "
.text
main:
la $a0, msj
li $v0, 4
syscall
li $v0, 5
syscall
move $t1, $v0 # $t1 = base
add $t3, $zero, $t1 # $t3 = acumulador (inicializado con la base)
# Lectura de la base
la $a0, msj2
li $v0, 4
syscall
li $v0, 5
syscall
# Lectura del exponente
move $t2, $v0 # $t2 = exponente
jal loop # Llama a la rutina de cálculo de potencia
# Estas líneas parecen código de prueba o remanente, no se ejecutan después del jal
# li $t1, 2
# li $t2, 2
# ##sumar
# ##mostrar
# done # La macro 'done' finaliza el programa
# inicio loop # $t2 almacena el exponente, $t3 acumulador (precargado con $t1), $t1 base
loop:
sub $t2, $t2, 1 # Decrementa el exponente (control de loop)
mul $t3, $t3, $t1 # Multiplica acumulador por la base
bgt $t2, 1, loop # Continúa si el exponente es mayor que 1
# fin loop
# Imprime el resultado ($t3)
move $a0, $t3
li $v0, 1
syscall
# Retorna al punto de llamada (main)
jr $ra
Suma de los Elementos de un Vector
Este código calcula la suma total de todos los elementos en un vector de enteros predefinido.
.data # SUMA DE UN VECTOR
x: .word 1, 2, 3, 4, 5, 6, 7, 456, 9, 10
i: .word 0
tamaño: .word 9 # El tamaño real del vector es 10, el índice final es 9
mensaje: .asciiz "La suma total del vector es: "
.text
main:
la $s0, mensaje # Carga la dirección del mensaje (no usado para imprimir el mensaje)
la $t0, x # Carga la dirección base del vector x
lw $t1, i # Carga el índice inicial (0)
lw $t2, tamaño # Carga el tamaño límite del índice (9)
li $s7, 0 # Inicializa el registro acumulador de la suma ($s7)
loop:
bgt $t1, $t2, exit # Si índice > tamaño (9), sale del loop
sll $t3, $t1, 2 # Calcula el offset: índice * 4 (bytes por word)
addu $t3, $t3, $t0 # Calcula la dirección del elemento: dirección base + offset
lw $t6, 0($t3) # Carga el elemento del vector en $t6
addu $s7, $s7, $t6 # Suma el elemento al acumulador
addi $t1, $t1, 1 # Incrementa el índice
j loop # Salta al inicio del loop
exit:
li $v0, 4 # Servicio para imprimir cadena
la $a0, mensaje # Carga la dirección del mensaje
syscall
li $v0, 1 # Servicio para imprimir entero
move $a0, $s7 # Mueve el resultado de la suma ($s7) a $a0 para imprimir
syscall
li $v0, 10 # Servicio para finalizar programa
syscall
Imprimir los Elementos de un Vector (usando .space)
Este código demuestra cómo inicializar un vector en la sección .data
usando .space
y luego imprimir sus elementos.
.data # IMPRIMIR UN VECTOR
mivector: .space 12 # Se reserva espacio para 3 enteros (3 * 4 bytes = 12)
C1: .asciiz "["
C2: .asciiz "]"
.text
main:
# Inicializa el vector con valores
addi $s0, $zero, 4
addi $s1, $zero, 10
addi $s2, $zero, 12
addi $t0, $zero, 0 # Índice/Offset inicial (0)
sw $s0, mivector($t0) # Guarda el primer valor
addi $t0, $t0, 4
sw $s1, mivector($t0) # Guarda el segundo valor
addi $t0, $t0, 4
sw $s2, mivector($t0) # Guarda el tercer valor
# Imprime los elementos del vector
addi $t0, $zero, 0 # Reinicia el índice/offset (0)
while:
beq $t0, 12, exit # Sale del loop cuando el offset llega a 12 (después del último elemento)
lw $t2, mivector($t0) # Carga el elemento actual del vector
addi $t0, $t0, 4 # Incrementa el offset al siguiente elemento
li $v0, 4 # Servicio para imprimir cadena
la $a0, C1 # Imprime "["
syscall
li $v0, 1 # Servicio para imprimir entero
move $a0, $t2 # Mueve el elemento cargado a $a0
syscall
li $v0, 4 # Servicio para imprimir cadena
la $a0, C2 # Imprime "]"
syscall
j while # Salta al inicio del loop
exit:
li $v0, 10 # Servicio para finalizar programa
syscall
Imprimir los Elementos de Otro Vector (usando .word value:n)
Este código muestra cómo inicializar un vector con múltiples copias de un valor usando .word value:n
y luego imprimir sus elementos.
.data # IMPRIMIR OTRO VECTOR
mivector: .word 100:10 # Define un vector de 10 palabras (40 bytes) inicializadas a 100
C1: .asciiz "["
C2: .asciiz "]"
.text
main:
addi $t0, $zero, 0 # Índice/Offset inicial (0)
while:
beq $t0, 40, exit # Sale del loop cuando el offset llega a 40 (después del último elemento)
lw $t2, mivector($t0) # Carga el elemento actual del vector
addi $t0, $t0, 4 # Incrementa el offset al siguiente elemento
li $v0, 4 # Servicio para imprimir cadena
la $a0, C1 # Imprime "["
syscall
li $v0, 1 # Servicio para imprimir entero
move $a0, $t2 # Mueve el elemento cargado a $a0
syscall
li $v0, 4 # Servicio para imprimir cadena
la $a0, C2 # Imprime "]"
syscall
j while # Salta al inicio del loop
exit:
li $v0, 10 # Servicio para finalizar programa
syscall
Imprimir un Vector de Cadenas ASCIIZ
Este código demuestra cómo definir un vector de punteros a cadenas ASCIIZ e imprimir cada cadena iterando sobre el vector.
.data # IMPRIMIR VECTOR DE ASCIIZ
carlos: .asciiz "carlos\n"
andres: .asciiz "andres\n"
pedro: .asciiz "pedro\n"
luis: .asciiz "luis\n"
nombres: .word carlos, andres, pedro, luis # Vector de punteros a cadenas
mensaje: .asciiz "La suma total del vector es: " # Mensaje no usado en este ejemplo
i: .word 0
tamaño: .word 3 # El índice final es 3 (para 4 elementos)
.text
main:
la $t0, nombres # Carga la dirección base del vector de punteros
lw $t1, i # Carga el índice inicial (0)
lw $t2, tamaño # Carga el tamaño límite del índice (3)
loop:
bgt $t1, $t2, exit # Si índice > tamaño (3), sale del loop
sll $t3, $t1, 2 # Calcula el offset: índice * 4 (bytes por word, que es el tamaño de un puntero)
addu $t3, $t3, $t0 # Calcula la dirección del puntero actual: dirección base + offset
li $v0, 4 # Servicio para imprimir cadena
lw $a0, 0($t3) # Carga el puntero a la cadena en $a0
syscall
addi $t1, $t1, 1 # Incrementa el índice
# Las siguientes líneas parecen código remanente de otro ejemplo
# lw $t6, 0($t3)
# addu $s7, $s7, $t6
# addi $t1, $t1, 1
j loop # Salta al inicio del loop
exit:
li $v0, 10 # Servicio para finalizar programa
syscall
Manipulación de Bytes y Direcciones
Este fragmento define macros y manipula un vector de bytes, mostrando la diferencia de direcciones entre dos puntos en la sección .data
.
.macro End
li $v0, 10
syscall
.end_macro
.macro ver
# Macro vacía
.end_macro
.data
ve: .byte 68, 65, 82, 90 # Bytes ASCII para "DARZ"
.space 1000 # Espacio reservado
ve3:
.space 5 # Espacio reservado
ve2: .byte 48, 48, 48, 48 # Bytes ASCII para "0000"
.text
main:
li $t2, 0 # Índice/Offset inicial (0)
lb $t1, ve($t2) # Carga el primer byte de 've'
add $t1, $t1, 3 # Suma 3 al valor del byte (68 + 3 = 71, ASCII 'G')
sb $t1, ve($t2) # Guarda el nuevo valor en el primer byte de 've'
la $t4, ve # Carga la dirección de 've'
la $t5, ve3 # Carga la dirección de 've3'
move $t6, $t5 # Copia la dirección de 've3' a $t6
sub $t5, $t5, $t4 # Calcula la diferencia de direcciones: ve3 - ve
move $a0, $t5 # Mueve la diferencia a $a0 para imprimir
li $v0, 1 # Servicio para imprimir entero
syscall
End # Finaliza el programa
# El siguiente loop y etiqueta 'salto' no se ejecutan ya que el programa finaliza antes
loop:
lb $t1, ve($t2)
beqz $t1, salto
move $a0, $t1
li $v0, 11
syscall
add $t2, $t2, 1
b loop
salto:
End
Manipulación e Impresión de Bytes
Este código manipula un vector de bytes, modifica su primer elemento y luego intenta imprimir los bytes como caracteres hasta encontrar un byte nulo (0).
.macro End
li $v0, 10
syscall
.end_macro
.macro ver
# Macro vacía
.end_macro
.data
ve: .byte 48, 48, 48, 48 # Bytes ASCII para "0000"
ve2: .byte 0 # Byte nulo para terminar la "cadena"
.text
main:
li $t2, 0 # Índice/Offset inicial (0)
lb $t1, ve($t2) # Carga el primer byte de 've'
add $t1, $t1, 3 # Suma 3 al valor del byte (48 + 3 = 51, ASCII '3')
sb $t1, ve($t2) # Guarda el nuevo valor en el primer byte de 've'
loop:
lb $t1, ve($t2) # Carga el byte actual de 've'
# move $t3, $t1 # Línea comentada
beqz $t1, salto # Si el byte es nulo (0), salta a 'salto'
move $a0, $t1 # Mueve el byte a $a0
li $v0, 11 # Servicio para imprimir carácter
syscall
add $t2, $t2, 1 # Incrementa el índice/offset
b loop # Salta al inicio del loop
salto:
End # Finaliza el programa
Ejemplo de Salto con Enlace (JAL)
Este código demuestra el uso de la instrucción jal
(Jump and Link) para llamar a una subrutina y cómo retornar utilizando el registro $ra
.
.data
msj: .asciiz "Inicio programa \n"
msj1: .asciiz "salto JUMP and LINK. SUMANDO T3 y T2 \n" # El comentario indica suma, pero la operación es OR
res: .asciiz "Resultado: "
.text
main:
la $a0, msj # Carga mensaje de inicio
li $v0, 4 # Servicio para imprimir cadena
syscall
li $t2, 55 # Carga valor en $t2
li $t3, 10 # Carga valor en $t3
jal Saludar # Llama a la subrutina 'Saludar'. La dirección de retorno se guarda en $ra.
# Después de retornar de Saludar
la $a0, res # Carga mensaje de resultado
li $v0, 4 # Servicio para imprimir cadena
syscall
move $a0, $t1 # Mueve el resultado de la subrutina ($t1) a $a0
li $v0, 1 # Servicio para imprimir entero
syscall
li $v0, 10 # Servicio para finalizar programa
syscall
Saludar:
la $a0, msj1 # Carga mensaje dentro de la subrutina
li $v0, 4 # Servicio para imprimir cadena
syscall
or $t1, $t2, $t3 # Realiza la operación OR entre $t2 y $t3, guarda el resultado en $t1
# move $a0, $t1 # Esta línea imprimiría el resultado dentro de la subrutina, pero no es necesaria aquí
jr $ra # Salta a la dirección almacenada en $ra (retorna a main)
Cálculo de Factorial
Este código calcula el factorial de un número ingresado por el usuario.
.data # FACTORIAL
saludo1: .asciiz "Indique un numero pequeño: ..."
saludo2: .asciiz "El factorial de dicho numero es: ... "
saludo3: .asciiz " | EL pointer vale: ..." # Mensaje no usado en este ejemplo
.text
.globl main
main:
la $a0, saludo1 # Carga mensaje de solicitud de número
li $v0, 4 # Servicio para imprimir cadena
syscall
li $v0, 5 # Servicio para leer entero
syscall
move $t0, $v0 # Guarda el número ingresado en $t0
li $t1, 1 # Inicializa el acumulador del factorial a 1
loop:
mul $t1, $t1, $t0 # Multiplica el acumulador por el número actual
addi $t0, $t0, -1 # Decrementa el número
bgt $t0, 1, loop # Si el número es mayor que 1, continúa el loop
la $a0, saludo2 # Carga mensaje de resultado
li $v0, 4 # Servicio para imprimir cadena
syscall
li $v0, 1 # Servicio para imprimir entero
move $a0, $t1 # Mueve el resultado del factorial ($t1) a $a0
syscall
# Las siguientes líneas parecen código remanente o incorrecto
# la $a0, saludo3
# li $v0, 4
# syscall
# la $v0, saludo2 # Carga dirección de saludo2 en $v0 (incorrecto para imprimir entero)
# li $v0, 1 # Servicio para imprimir entero (pero $v0 ya tiene la dirección)
# syscall
li $v0, 10 # Servicio para finalizar programa
syscall
Contar Bits Encendidos (Set Bits)
Este código cuenta cuántos bits están establecidos (valor 1) en una palabra (entero de 32 bits).
.data
saludo1: .asciiz "El numero de bits prendidos es "
palabra: .word 105 # Número a analizar (105 en binario es 01101001)
.text
.globl main
main:
la $a0, saludo1 # Carga mensaje introductorio
li $v0, 4 # Servicio para imprimir cadena
syscall
lw $t0, palabra # Carga la palabra a analizar en $t0
li $t1, 0 # Inicializa el contador de bits encendidos ($t1)
li $t2, 0 # Inicializa el contador de iteraciones (para 32 bits)
loop:
andi $t3, $t0, 0x0001 # Aísla el bit menos significativo de $t0
add $t1, $t1, $t3 # Suma el bit aislado (0 o 1) al contador $t1
srl $t0, $t0, 1 # Desplaza $t0 un bit a la derecha (prepara el siguiente bit)
addi $t2, $t2, 1 # Incrementa el contador de iteraciones
blt $t2, 32, loop # Repite 32 veces para revisar todos los bits
move $a0, $t1 # Mueve el contador de bits encendidos ($t1) a $a0
li $v0, 1 # Servicio para imprimir entero
syscall
li $v0, 10 # Servicio para finalizar programa
syscall