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

Entradas relacionadas: