Brianna Drew
Brianna Drew

Reputation: 109

How can I properly multiply two 4x4 arrays in MIPS assembly in row-major order?

for an assignment in my assembly programming course, I am to multiply two 4x4 matrices and store the result in row-major order and then column-major order. I have coded the functions for the row-major order, but I am not sure why the result isn't being stored in $t7. I also believe that another issue is the jr $ra in rowMulInLoop2 is going back to main rather than it's place in rowMulInLoop1, but again, I am not sure how to fix this issue. I am fairly new to MIPS, but once I am able to figure out this, I should be able to do the column-major on my own. And yes, I have tried debugging but am still confused on how to solve the issues. (P.S. I would like to keep my code as similar to this as possible, unless it's COMPLETELY wrong. Also, I have excluded the functions rowSum and colSum as they are not relevant). Any help would be greatly appreciated. Thanks!

.data

newline: .asciiz "\n"

array1:     .word 2,1,9,2
                .word 7,9,10,10  
                    .word 3,4,4,4
                        .word 2,5,4,4

array2:     .word 8,7,1,2
                .word 2,7,8,6
                    .word 7,5,6,8
                        .word 9,4,8,9

rowMulArray: .space 64
size: .word 4
.eqv DATA_SIZE 4

.text

main:
    lw $a1, size # size of array stored at $a2
    jal rowSum
    la $a0, newline
    li $v0, 4
    syscall
    jal rowMul
    la $a0, newline
    li $v0, 4
    syscall
    jal colSum
    li $v0, 10
    syscall

    rowMul:
        li $t7, 0 # product
        li $t0, 0 # row index for product array
        li $t1, 0 # column index for product array
        move $s0, $zero # row index for array1
        move $s1, $zero # column index for array1
        move $s2, $zero # row index for array2
        move $s3, $zero # column index for array2

        rowMulOutLoop:
            mul $t2, $t0, $a1
            add $t2, $t2, $t1
            mul $t2, $t2, DATA_SIZE

            rowMulInLoop1:
                mul $s4, $s0, $a1
                add $s4, $s4, $s1
                mul $s4, $s4, DATA_SIZE

                mul $s5, $s2, $a1
                add $s5, $s5, $s3
                mul $s5, $s5, DATA_SIZE

                sw $t4, array1($s4)
                sw $t5, array2($s5)

                mul $t6, $t4, $t5
                add $t7, $t7, $t6

                addi $t4, $t4, 4
                addi $s1, $s1, 1
                addi $s2, $s2, 1
                bne $s1, $a1, rowMulInLoop1
                jal rowMulInLoop2
                move $s1, $zero
                move $s2, $zero 
                addi $s0, $s0, 1
                addi $s3, $s3, 1
                bne $s0, $a1, rowMulInLoop1

        rowMulInLoop2:
            sw $t7, rowMulArray($t2)

            move $a0, $t7
            li $v0, 1
            syscall

            addi $t1, $t1, 1
            bne $t1, $a1, rowMulOutLoop
            li $t1, 0
            addi $t0, $t0, 1
            bne $t0, $a1, rowMulOutLoop
        jr $ra
    jr $ra  

Upvotes: 0

Views: 1381

Answers (1)

Peter Cordes
Peter Cordes

Reputation: 363970

After calculating indices for your source data, you're storing instead of loading.

              sw $t4, array1($s4)
              sw $t5, array2($s5)

That overwrites your input with garbage, and doesn't update $t4 or $t5. You probably want lw.

There might be other bugs, but this is the first obvious one I see, and is a total showstopper. Use your debugger to single-step your code and watch registers change. It should have been obvious that $t4 and $t5 didn't get the right values from the source data at that point.


Also, you should normally avoid the $s registers because they're call-preserved. main's caller might crash if you return with them modified. If you run out of other registers, you can save/restore some $s registers and/or $lr to use them as scratch, otherwise there's $t0..9, $v0..1, and $a0..3 which are all call-clobbered in the normal MIPS calling convention.

Also $at (the assembler temporary), if you avoid any pseudo-instructions that use it as a temporary when they expand to real MIPS instructions.

Upvotes: 1

Related Questions