Programación en MIPS: Operaciones con Matrices y Cálculo de Potencia

Enviado por Andres y clasificado en Informática

Escrito el en español con un tamaño de 10,94 KB

Implementación de Algoritmos Fundamentales en Ensamblador MIPS

Este documento presenta ejemplos de código en ensamblador MIPS para diversas operaciones comunes, incluyendo el cálculo de la suma de la diagonal principal de una matriz, el acceso a un elemento específico (i,j) en una matriz, y la implementación de una función para calcular la potencia de un número.

1. Suma de la Diagonal Principal de una Matriz

Este segmento de código MIPS calcula la suma de los elementos de la diagonal principal de una matriz cuadrada de 3x3.

Sección de Datos (.data)


.data
matriz:    .word 1, 2, 3
           .word 4, 5, 6
           .word 7, 8, 9
dimension: .word 3

Sección de Código (.text)


.globl inicio
.text
inicio:
    lw   $s0, dimension      # Carga la dimensión de la matriz.
    la   $t0, matriz         # Carga la dirección de la matriz.
    addi $s1, $s0, 1        # Suma uno a la dimensión que nos servirá de desplazamiento.
    li   $s2, 4              # Carga en $s2 el tamaño de cada posición de la matriz.
    mul  $s2, $s2, $s1       # Multiplica el tamaño de la posición de la matriz por el desplazamiento y tenemos el desplazamiento para la diagonal.

while:
    lw   $t1, 0($t0)         # Carga el primer elemento de la matriz. # Nota: El registro $t2 (acumulador de suma) no está inicializado.
    add  $t2, $t2, $t1       # Suma los elementos de la diagonal.
    add  $t0, $t0, $s2       # Desplaza el registro para acceder al siguiente elemento de la diagonal.
    add  $a0, $a0, 1         # Suma 1 al contador. # Nota: El registro $a0 (contador) no está inicializado.
    beq  $a0, 4, fin         # Cuando el contador llega al último elemento de la diagonal, el bucle termina. # Nota: La condición de fin de bucle usa un valor fijo (4) en lugar de la dimensión de la matriz ($s0).
    j    while               # Salta al inicio del bucle.

fin:
    li   $v0, 10             # Código de servicio para finalizar el programa.
    syscall                  # Ejecuta la llamada al sistema.

2. Acceso a un Elemento Específico (i,j) en una Matriz

Este código demuestra cómo acceder a un elemento particular en una matriz bidimensional, dado su índice de fila (i) y columna (j).

Sección de Datos (.data)


.data
array:    .word 1, 2, 3
          .word 4, 5, 6
          .word 7, 8, 9
numfil:   .word 3
numcol:   .word 3
elemento: .word 2, 3      # Fila 2, Columna 3 (índices base 1)

Sección de Código (.text)


.globl inicio
.text
inicio:
    la   $a0, array        # Carga la dirección base del array.
    lw   $a1, numfil       # Carga el número de filas.
    lw   $a2, numcol       # Carga el número de columnas.
    la   $a3, elemento     # Carga la dirección de los índices (fila, columna).

    sub  $sp, $sp, 36      # Reserva espacio en la pila.
    sw   $a0, 0($sp)       # Guarda $a0.
    sw   $a1, 4($sp)       # Guarda $a1.
    sw   $a2, 8($sp)       # Guarda $a2.
    sw   $a3, 12($sp)      # Guarda $a3.

    jal subrutina          # Llama a la subrutina.

    move $t7, $v0          # Mueve el valor de retorno ($v0) a $t7.

    lw   $a0, 0($sp)       # Restaura $a0.
    lw   $a1, 4($sp)       # Restaura $a1.
    lw   $a2, 8($sp)       # Restaura $a2.
    lw   $a3, 12($sp)      # Restaura $a3.
    add  $sp, $sp, 36      # Libera el espacio de la pila.

    li   $v0, 10           # Código de servicio para finalizar el programa.
    syscall                # Ejecuta la llamada al sistema.

subrutina:
    sub  $sp, $sp, 28      # Reserva espacio en la pila.
    # ... (código omitido para brevedad)
    sw   $ra, 32($sp)      # Guarda $ra. # Nota: Offset 32($sp) es inconsistente con la reserva de 28 bytes.
    sw   $fp, 36($sp)      # Guarda $fp. # Nota: Offset 36($sp) es inconsistente con la reserva de 28 bytes.

    move $s0, $a0          # Mueve $a0 a $s0.
    move $s1, $a1          # Mueve $a1 a $s1.
    move $s2, $a2          # Mueve $a2 a $s2.
    move $s3, $a3          # Mueve $a3 a $s3.

bucle:
    lw   $t0, 0($s3)       # Carga el valor de la fila (índice i).
    lw   $t1, 4($s3)       # Carga el valor de la columna (índice j).
    li   $t5, 4            # Carga el tamaño de palabra (4 bytes).

    sub  $t1, $t1, 1       # Ajusta el índice de columna a base 0 (j-1).
    mul  $t2, $s2, $t5     # Calcula el tamaño de una fila en bytes (num_columnas * 4).
    mul  $t2, $t2, $t1     # Calcula el desplazamiento horizontal (fila_size * (j-1)).

    sub  $t0, $t0, 1       # Ajusta el índice de fila a base 0 (i-1).
    mul  $t0, $t0, $t5     # Calcula el desplazamiento vertical ((i-1) * 4).

    add  $t2, $t2, $t0     # Suma los desplazamientos horizontal y vertical para obtener el offset total.
    add  $a0, $a0, $t2     # Calcula la dirección del elemento: (dirección_base + offset_total).
    lw   $v0, 0($a0)       # Carga el valor del elemento en $v0 (valor de retorno).

    lw   $s0, 16($sp)      # Restaura $s0. # Nota: Offset 16($sp) es inconsistente con la reserva de 28 bytes.
    # ... (código omitido para brevedad)
    lw   $ra, 32($sp)      # Restaura $ra.
    lw   $fp, 36($sp)      # Restaura $fp.
    add  $sp, $sp, 36      # Libera el espacio de la pila. # Nota: La liberación de 36 bytes es inconsistente con la reserva inicial de 28 bytes.
    jr   $ra               # Retorna al programa principal.

3. Implementación de la Función Potencia (Base^Exponente)

Este programa MIPS solicita al usuario una base y un exponente, y luego calcula la potencia (base^exponente) utilizando una subrutina.

Sección de Datos (.data)


.data
base:      .space 4
exponente: .space 4
resultado: .space 4
cadena:    .asciiz "Introduce la base: "
cadena2:   .asciiz "Introduce el exponente: "
cadena3:   .asciiz "El resultado es: "

Sección de Código (.text)


.text
    li   $v0, 4              # Código de servicio para pedir cadena.
    la   $a0, cadena         # Carga la dirección de la cadena.
    syscall                  # Ejecuta la llamada al sistema.

    li   $v0, 5              # Código de servicio para leer entero.
    syscall                  # Ejecuta la llamada al sistema.
    sw   $v0, base           # Guarda el valor leído en la variable 'base'.

    li   $v0, 4              # Código de servicio para pedir cadena.
    la   $a0, cadena2        # Carga la dirección de la cadena.
    syscall                  # Ejecuta la llamada al sistema.

    li   $v0, 5              # Código de servicio para leer entero.
    syscall                  # Ejecuta la llamada al sistema.
    sw   $v0, exponente      # Guarda el valor leído en la variable 'exponente'.

main:
    lw   $t0, base           # Carga en $t0 el contenido de la variable 'base'.
    lw   $t1, exponente      # Carga en $t1 el contenido de la variable 'exponente'.
    sub  $t2, $t1, 1         # Resta 1 al exponente para la condición del bucle.
    move $t3, $t0           # Copia la base.
    li   $t4, 0              # Carga 0 para el contador.

    sub  $sp, $sp, 28        # Reserva espacio para la pila.
    sw   $t0, 24($sp)        # Guarda $t0. # Nota: Offset 24($sp) es inconsistente con la reserva de 28 bytes.
    sw   $t1, 28($sp)        # Guarda $t1. # Nota: Offset 28($sp) es inconsistente con la reserva de 28 bytes.

    jal rutina_potencia      # Llama a la subrutina.

    sw   $v0, resultado      # Guarda el resultado de la subrutina en la variable 'resultado'.

    lw   $t0, 24($sp)        # Restaura $t0.
    lw   $t1, 28($sp)        # Restaura $t1.
    add  $sp, $sp, 28        # Libera el espacio de la pila.

    li   $v0, 4              # Código de servicio para imprimir cadena.
    la   $a0, cadena3        # Carga la dirección de la cadena.
    syscall                  # Ejecuta la llamada al sistema.

    li   $v0, 1              # Código de servicio para imprimir entero.
    lw   $a0, resultado      # Carga el resultado a imprimir en $a0.
    syscall                  # Ejecuta la llamada al sistema.

    li   $v0, 10             # Código de servicio para finalizar el programa.
    syscall                  # Ejecuta la llamada al sistema.

rutina_potencia:
    sub  $sp, $sp, 28        # Reserva espacio en la pila.
    sw   $s0, 0($sp)         # Guarda $s0.
    sw   $s1, 4($sp)         # Guarda $s1.
    sw   $s2, 8($sp)         # Guarda $s2.
    sw   $s3, 12($sp)        # Guarda $s3.
    sw   $fp, 16($sp)        # Guarda $fp.
    sw   $ra, 20($sp)        # Guarda $ra.

    move $s0, $t3           # Mueve $t3 a $s0.
    move $s1, $t0           # Mueve $t0 a $s1.
    move $s2, $t4           # Mueve $t4 a $s2.
    move $s3, $t2           # Mueve $t2 a $s3.

    bnez $t1, bucle          # Si el exponente ($t1) no es cero, salta al bucle.
    li   $s0, 1              # Si el exponente es cero, el resultado es 1.
    b    sigue               # Salta al final de la rutina.

bucle:
    mul  $s0, $s0, $s1       # Multiplica el resultado actual ($s0) por la base ($s1).
    addi $s2, $s2, 1         # Suma 1 al contador.
    bgt  $s3, $s2, bucle     # Si (exponente - 1) es mayor que el contador, continúa el bucle.

sigue:
    move $v0, $s0           # Mueve el resultado final ($s0) a $v0.

    lw   $s0, 0($sp)         # Restaura $s0.
    # ... (código omitido para brevedad)
    lw   $ra, 20($sp)        # Restaura $ra.
    lw   $fp, 36($sp)        # Restaura $fp. # Nota: Offset 36($sp) es inconsistente con la reserva de 28 bytes.
    add  $sp, $sp, 28        # Libera el espacio de la pila.
    jr   $ra                 # Retorna al programa principal.

Entradas relacionadas: