Traversing through a 2D array in MIPS - arrays

Hey guys I am required to do C[i][j] = A[i][j] + B[j][i] for all i and j, size is 16 x 16 in a 2D array.
This is the main part of my code (shown below).
When I run this code in SPIM, I received an exception at line "lw $t4, 0($t4) # value of B[j][i]", which says bad address at data/stack read
When I checked the value stored in each registers, I realized that i == 0x1, but j reaches 0xbf0! (That's 3056)
I have no idea why this happened since my j is supposed to only increase from 0 to 15. Help me out!
la $t0, A # $t0 represents start address of A[i][j]
la $t1, B # $t1 represents start address of B[i][j]
la $t2, C # $t2 represents start address of C[i][j] displacement of A will be the same as C
addi $t3, $zero, 16 # set maximum iteration to be 16
addi $t5, $zero, 0 # set i = 0
addi $t6, $zero, 0 # set j = 0
loopi:
jal loopj # starts inner loopj
addi $t5, $t5, 1 # i++
bne $t3, $t5, loopi # continue loopi if i < 16
j finish
loopj:
sll $t7, $t5, 4
add $t7, $t7, $t6
sll $t7, $t7, 2 # 4 * ((i * 16) + j)
add $t9, $t7, $t0 # address of A[i][j]
lw $t9, 0($t9) # value of A[i][j]
sll $t4, $t6, 4
add $t4, $t4, $t5
sll $t4, $t4, 2 # 4 * ((j * 16) + i)
add $t4, $t4, $t1 # address of B[j][i]
lw $t4, 0($t4) # value of B[j][i]
add $t4, $t4, $t9 # A[i][j] + B[j][i]
add $t7, $t7, $t2 # address of C[i][j]
sw $t4, 0($t7) # store answer into C[i][j]
addi $t6, $t6, 1 # j++
bne $t3, $t6, loopj # continue loopj if j < 16
jr $ra
finish:

You forgot to reset j to zero every time you enter loopi, otherwise after the first loopj won't start at zero in loopj...
To fix it, you can move the addi which sets $t6 (which holds j) after the label loopi:
loopi:
addi $t6, $zero, 0 # set j = 0
jal loopj # starts inner loopj
...

Related

Function to find the MAX and its position on an array

I have to find the max element and its position on an array(the position starts with 1)( if the array doesn't contain any elements I have to return position=0 and max=smallest negative number). I think that my code is ok (apart from setting the max to the lowest number possible, that I have doubt about) but I have no idea what I need to start my code with, like save the last thing stored in the registers. Also I can't compile it (probably because of the pseudo-instructions).
I have tried writing my program in c and then compiling to MIPS but it still wouldn't work.
MaxAndArg:
li $v0, -2,147,483,648 # $v0(MAX) is the smallest negative number
li $v1, 0 # $v1(POSITION) starts from zero
li $t3, 0 # $t3(i in a normal language) will be used to loop
li $t4, 0 # $t4 will be used to show the position in the array
L2:
beq $t3, $a1, EXIT # if (i = array size) goto EXIT
sll $t4, $t4, 2 # $t4 = $t4 * 4
add $a0, $t4, $a0 # $a0 = $a0 + $t4 (next element in the array)
blt $v0, a0, L1 # if (max < a[j]) goto L1
addi $t3, $t3, 1 # i++
addi $t4, $t4, 1 # array_position++
j L2
L1:
addi $v0, $a0, 0 # $v0 = $a0
addi $v1, $t3, 1 # $v1 = i + 1 (probably works)
addi $t3, $t3, 1 # i++
addi $t4, $t4, 1 # array_position++
j L2
EXIT:
jr $ra #return

Arrays in nested for loops, MIPS assembly

I was given the following C code to implement in MIPS assembly.
for(i=0; i<16, i++){
for(i=0; j<16, j++){
C[i][j] = A[i][j] = B[j][i]
}
}
The arrays are already initialized for us, we only have to deal with the memory.
Here's how i made my nested loop.
First:
bge $t1, $t0, Exit
Second:
bge $t2, $t0, Continue
#do work here.
addi $t2, $t2, 1
j Second
Continue:
addi $t1, $t1, 1
j First
Exit:
Loading the counters:
addi $t0, $t0, 16
move $t1, $zero
move $t2, $zero
la $t3, A
la $t4, B
la $t5, C
And logic for A[i][j] using the formula Base + Word Length * (Row * Max size + Col):
sllv $t6, $t0, $t1 #Row, shift 16 by current counter -> 32 -> 64..
addu $t6, $t6, $t2 #Column, add column counter.
sll $t6, $t6, 2 #Shift entire count by word length.
addu $t6, $t6, $t3 #Add A base address.
lw $t7, ($t6) #Load word from that address.
Full code:
addi $t0, $t0, 16
move $t1, $zero
move $t2, $zero
la $t3, A
la $t4, B
la $t5, C
First:
bge $t1, $t0, Exit
Second:
bge $t2, $t0, Continue
###
#Zero out counters first.
move $t6, $zero
move $t7, $zero
move $t8, $zero
move $t9, $zero
sllv $t6, $t0, $t1 #Row, shift 16 by current counter -> 32 -> 64..
addu $t6, $t6, $t2 #Column, add column counter.
sll $t6, $t6, 2 #Shift entire count by word length.
addu $t6, $t6, $t3 #Add A base address.
lw $t7, ($t6) #Load word from that address.
sllv $t7, $t0, $t2 #Row, shift 16 by current counter -> 32 -> 64..
addu $t7, $t7, $t1 #Column, add column counter.
sll $t7, $t7, 2 #Shift entire count by word length.
addu $t7, $t7, $t4 #Add B base address.
lw $t8, ($t7) #Load word from that address.
addu $t9, $t7, $t8 #add A and B results.
addu $t7, $t6, $t5 #add C base address, reuses $t7, copies $t6 from *A* array.
sw $t9, 0($t7) #store above result to C.
###
addi $t2, $t2, 1
j Second
Continue:
addi $t1, $t1, 1
j First
Exit:
I'm getting a bad address error but I can't seem to figure out what is wrong.
There are at least three errors:
You are overwriting $t6 which should have the offset of A and C with the base address of A
You are overwriting $t7 which should hold the content of A[i][j] with the address of B[j][i]
You are miscalculating the row offset. Instead of shifting 16 row times, you should shift row 4 times (which effectively multiplies row by 16)
You may change
sllv $t6, $t0, $t1 #Row, shift 16 by current counter -> 32 -> 64..
...
addu $t6, $t6, $t3 #Add A base address.
lw $t7, ($t6) #Load word from that address.
...
sllv $t7, $t0, $t2 #Row, shift 16 by current counter -> 32 -> 64..
...
addu $t9, $t7, $t8 #add A and B results
with
sll $t6, $t1, 4 # Row
...
addu $t7, $t6, $t3 #Add A base address.
lw $t9, ($t7) #Load word from that address.
...
sll $t7, $t2, 4 # Row
...
addu $t9, $t9, $t8 #add A and B results.

Converting C to mips assembly, Unaligned address error

i'm doing an assignment now, it's almost done but i keep getting error saying
Unaligned address in inst/data fetch: 0x10010016
at line:
lw $t3,0($a1) # get the value of b[k] and save it into t3
I search online and i find an answer saying i have to use .align 2 to fix this, but that doesn't work for my problem.
can someone please give me a hint on this, I literally spend 6 hours on this..
thank you very much
Here is my code:
# a -> $a0
# b -> $a1
# n -> $a2
# j -> $a3
# k -> $s0
# i -> $t0
.data
.align 2
arra: .word 1,2,7,4,5
arrb: .word 3,4,7,2,9
.text
la $a0, arra # we have array a[] = { 1,2,7,4,5}
la $a1, arrb # we have array b[] = {3,4,7,2,9}
addi $a2,$zero,0 # n = 0
addi $a2,$zero,3 # n = 3
addi $a3,$zero,0 # j = 0
addi $a3,$zero,3 # j = 3
addi $s0,$zero,0 # k = 0
addi $s0,$zero,2 # k = 2
g:
addi $sp, $sp, -24
sw $ra, 20($sp) # save $ra on stack
sw $s0, 16($sp) # save $s0 (k) on stack
sw $a0, 12($sp) # save a0(a) on stack
sw $a1, 8($sp) # save a1(b) on stack
sw $a2, 4($sp) # save a2(n) on stack
sw $a3, 0($sp) # save a3(j) on stack
move $a3,$s0 # set j = k
jal f # f(a,b,n,k,k)
add $a1,$a1,$s0 # return the address of b[k]
lw $t3,0($a1) # get the value of b[k] and save it into t3
add $v0, $t3,$zero # return the value
lw $a3,0($sp)
lw $a2,4($sp)
lw $a1,8($sp)
lw $a0,12($sp)
lw $s0,16($sp)
lw $ra,20($sp)
addi $sp,$sp,24
jr $ra
f:
bne $a2, $zero, ELSE # if (n != 0) go to ELSE
addi $t0, $zero, 1 # set $t0 = 1
sw $t0, 0($a1) # then set b[0] = 1
addi $t0, $zero, 1 # set $t0 = 1
sw $t0, 0($a1) # then set b[0] = 1
addi $t0, $zero, 1 # set i = 1 for the loop
forLoop:
slt $t1,$s0, $t0 # if k < i, end the loop, use $t1 to store the boolean value
bne $t1, 1, forLoopDone
add $a1, $a1, $t0 # b[i] address
add $t2,$zero,$zero
sw $t2, 0($a1) # b[i] = 0
addi $t0, $t0, 1 # i = i + 1
j forLoop
ELSE:
bne $a3, $zero, updateJ # test if (j == 0), if not, j = j -1
j iteratef
updateJ:
addi $a3, $a3, -1 # j = j -1
j iteratef
iteratef:
addi $a2, $a2, -1 # iterate, n = n - 1
j f # f(b, a, n-1, j_update, k)
bne $a3, $zero, forLoop1Ini # if (j != 0), go to for_loop1_ini
lw $a0, 0($a0) # there might be sth wrong here
sw $a1, 0($a1) # set b[0] = a[0]
addi $a3, $a3, 1 # j++
forLoop1Ini:
addi $t0, $a3, 0 # set i = j
forLoop1Start:
slt $t1,$s0, $t0
bne $t1, 1, forLoop1Done
add $a0, $a0, $t0 # get a[i] address
lw $t1, 0($a0) # t1 = a[i]
lw $t2, -4($a0) # get b[i]
add $a1, $a1, $t0 # get b[i] address
add $t1, $t1, $t2 # t1 = a[i-1] + a[i]
sw $t1, 0($t1) # b[i] = a[i-1] + a[i]
addi $t0, $t0, 1 # i++
j forLoop1Start
forLoop1Done:
nop
forLoopDone:
nop
jr $ra
Your problem is that you are not taking into account the size of each element of the array. Each element occupies 4 bytes.
Therefore, instead of issuing
add $a1,$a1,$s0 # return the address of b[k]
you should multiply the index by 4 (which is the size of element) to get the effective offset:
sll $s1, $s0, 2 # Compute effective offset (i.e. multiply index by 4)
add $a1,$a1,$s1 # return the address of b[k]
lw $t3,0($a1) # get the value of b[k] and save it into t3

Array sorting in MIPS

So I am working on an assignment to sort an array in MIPS. The data to sort is given in a separate .asm file as follows:
.data
.word 3
.word 40
.word 30
.word 70
.text
I decided to use bubble sort. I am fairly certain that my algorithm is sound, and it appears to sort the data correctly. The fun thing about this project is that the values we sort will be played as MIDI notes as a means of testing the program (so, naturally, the notes should play in ascending order). This is working pretty well when I test my code, however, I'm hearing a few strange beats at the end of the MIDI notes. I stepped through my code and discovered that, at the end, $t1 (the value I use to compare to my loop iterator for completeness) holds a value of 7, when I expected it to hold a value of three. I assign $t1 as 0($t2), $t2 is 0x10010000 which I assume is still the base address of my array. The base address of the array should hold 3, shouldn't it?
I'm a little confused about why $t1 is 7 at all... any advice? I have included all of my code below.
#ec2.asm
.include "ec2_data.asm" #must be in the same directory as ec2.asm
#ec2_data.asm: puts some values in the "data segment"
#the first value is the number of values to sort (n)
#the remaining n word values are the data to sort
#the values will be stored in memory as word values starting
# address 0x10010000
j main
#$t2 is hasChanged
#$t3 is itemCount
#$t4 is i, our iterator in the for loop
#$t5 is array[i] (temp)
#$t6 is array[i+1] (temp)
while_label:
beq $t2, $zero, done_sorting #checks to see if the previous iteration switched any values. If not, we are done.
addi $t2, $zero, 0 #initialize hasChanged to 0
addi $t3, $t3, -1 #decrement itemCount by -1
addi, $t0, $t0, 4 #add 4 to the array offset
addi, $t4, $zero, 0 #set our for loop iterator to 0
for_label:
lw $t5, 0($t0) #set a temp value equal to array[i]
lw $t6, 4($t0) #set a temp value equal to array[i+1]
beq $t4, $t3, while_label #for loop: if i = itemcount, we have incremented all the way through our for loop
bge $t6, $t5, skip_swap #if array[i+1] is greater than or equal to array[i], we don't need to swap these values
#swap
sw $t6, 0($t0) #set array[i] equal to array[i+1]
sw $t5, 4($t0) #set array[i+1] equal to the temp value
addi $t2, $t2, 1 #set hasChanged to 1 to indicate that a swap has been made
skip_swap:
addi, $t4, $t4, 1 #increment i by 1 (for loop iterator)
j for_label #keep the for loop going!
main:
#read values
addi $t0, $zero, 0x10010000 #sets $t0 to be the base address of the array
addi $t2, $zero, 1
lw $t3, 0($t0) #stores n in $t3
j while_label
done_sorting:
# adapted from MIDI example
#duration 25 ms
#instrument (whichever)
#volume 64
addi $v0, $zero, 33 # midi out synchronous
addi $t2, $zero, 0x10010000 # address of original array (which should by now be sorted)
addi $a1, $zero, 250 # duration (ms)
addi $a2, $zero, 1 # instrument
addi $a3, $zero, 64 # volume
addi $t0, $zero, 0 # counter
lw $t1, 0($t2) # end of the loop (should be n)
addi $t1, $t1, 4 # adds four to the array offset in $t1
lw $a0, 0($t2) # stores the first sorted value ( 4($t1) ) in $a0
midi_loop:
beq $t0, $t1, done
addi $t2, $t2, 4
lw $a0, 0($t2)
syscall
addi $t0, $t0, 1
j midi_loop
done:
#addi $v0, $zero, 10 # syscall for exit
#syscall # clean exit
Your sorting algorithm is quite broken. You haven't noticed that because it happens to get the right answer with your test data. It will produce the wrong answer with other test data (e.g. I believe your algorithm will sort 70, 40, 30 to 40, 30, 70).
But your question was about why $t1 ends up with value 7. The answer is simple. You wrote this:
addi $t2, $zero, 0x10010000 # address of original array (which should by now be sorted)
addi $a1, $zero, 250 # duration (ms)
addi $a2, $zero, 1 # instrument
addi $a3, $zero, 64 # volume
addi $t0, $zero, 0 # counter
lw $t1, 0($t2) # end of the loop (should be n)
addi $t1, $t1, 4 # adds four to the array offset in $t1
We can see that you set $t2 to 0 + 0x10010000 = 0x10010000. Then you load the word at 0($t2) (= 0x10010000) into $t1. The word at 0x10010000 is 3, so at that point $t1 is 3. Then you add 4 to $t1, storing the result in $t1. At that point $t1 is 7. You never modify $t1 after that.
SO I really shouldn't have asked this question without giving my code another once-over. The errors were extremely simple. This appears to work.
#ec2.asm
.include "ec2_data.asm" #must be in the same directory as ec2.asm
#ec2_data.asm: puts some values in the "data segment"
#the first value is the number of values to sort (n)
#the remaining n word values are the data to sort
#the values will be stored in memory as word values starting
# address 0x10010000
j main
#$t2 is hasChanged
#$t3 is itemCount
#$t4 is i, our iterator in the for loop
#$t5 is array[i] (temp)
#$t6 is array[i+1] (temp)
while_label:
beq $t2, $zero, done_sorting #checks to see if the previous iteration switched any values. If not, we are done.
addi $t2, $zero, 0 #initialize hasChanged to 0
addi $t3, $t3, -1 #decrement itemCount by -1 WHY
addi, $t0, $zero, 0x10010000 #add 4 to the array offset
addi, $t4, $zero, 0 #set our for loop iterator to 0
for_label:
addi, $t0, $t0, 4
lw $t5, 0($t0) #set a temp value equal to array[i]
lw $t6, 4($t0) #set a temp value equal to array[i+1]
beq $t4, $t3, while_label #for loop: if i = itemcount, we have incremented all the way through our for loop
bge $t6, $t5, skip_swap #if array[i+1] is greater than or equal to array[i], we don't need to swap these values
#swap
sw $t6, 0($t0) #set array[i] equal to array[i+1]
sw $t5, 4($t0) #set array[i+1] equal to the temp value
addi $t2, $t2, 1 #set hasChanged to 1 to indicate that a swap has been made
skip_swap:
addi, $t4, $t4, 1 #increment i by 1 (for loop iterator)
j for_label #keep the for loop going!
main:
#read values
addi $t0, $zero, 0x10010000 #sets $t0 to be the base address of the array
addi $t2, $zero, 1
lw $t3, 0($t0) #stores n in $t3
j while_label
done_sorting:
# adapted from MIDI example
#duration 25 ms
#instrument (whichever)
#volume 64
addi $v0, $zero, 33 # midi out synchronous
addi $t2, $zero, 0x10010000 # address of original array (which should by now be sorted)
addi $a1, $zero, 250 # duration (ms)
addi $a2, $zero, 1 # instrument
addi $a3, $zero, 64 # volume
addi $t0, $zero, 0 # counter
lw $t1, 0($t2) # end of the loop (should be n)
lw $a0, 0($t2) # stores the first sorted value ( 4($t1) ) in $a0
midi_loop:
beq $t0, $t1, done
addi $t2, $t2, 4
lw $a0, 0($t2)
syscall
addi $t0, $t0, 1
j midi_loop
done:

C to MIPS translation

Trying to convert this c code into MIPS and run it in SPIM.
int A[100], B[100];
for(i=1; i<100; 1++){
A[i] = A[i-1] + B[i];
}
So far this is what I have.
# comments are delimted by has marks
.data
A: .word 0:100 # array of 12 integers
B: .word 0:100 # array of 12 integers
.text
main:
li $v0, 1 # load the value "1" into register $v0
li $t0, 1 # load the value "1" into register $t0
li $t1, 100 # load the value "100" into register $t1
blt $t0, $t1, loop # branches to Loop if $t0 < 100
la $t9, B
la $t8, A
loop:
sll $t0, $t0, 2
add $t2, $t9, $t0
lw $s4, 0($t9)
add $t3, $t0, -1
add $t4, $t8, $t3
lw $s5, 0($t4)
add $t5, $t2, $s5
add $t6, $s0, $t0
sw $t7, 0($t5)
addi $t0, $t0, 1
li $v0, 1 # system call for print_int
move $a0, $t0 # the sum to print
syscall # print the sum
When running in SPIM I get the following errors:
Exception occurred at PC=0x00400040
Bad address in data/stack read: 0x00000004
Exception occurred at PC=0x0040004c
Unaligned address in inst/data fetch: 0x00000003
Exception occurred at PC=0x00400058
Bad address in data/stack read: 0x00000000
Attempt to execute non-instruction at 0x0040006c
Some direction would be nice. Thanks
You are branching to loop (blt $t0, $t1, loop) before you initialize the pointers to A and B. You need to move the blt $t0, $t1, loop to the end of your code, not have it at the beginning.
I hate to do this, but there are too many things wrong to list them all. Try this:
.data
A: .word 0:100 # array of 100 integers
B: .word 0:100 # array of 100 integers
.text
main:
li $t0, 4 # load the value "1" into register $t0
li $t1, 400 # load the value "100" into register $t1
la $t9, B
la $t8, A
loop:
add $t2, $t9, $t0 # $t2 = B + i
lw $s4, 0($t9) # $s4 = B[i]
add $t3, $t0, -4 # $t3 = i - 1
add $t4, $t8, $t3 # $t4 = A + i - 1
lw $s5, 0($t4) # $s5 = A[i - 1]
add $t5, $t8, $t0 # $t5 = A + i
add $t6, $s4, $s5 # $t6 = B[i] + A[i - 1]
sw $t6, 0($t5) # A[i] = $t6
addi $t0, $t0, 4 # i++
li $v0, 1 # system call for print_int
move $a0, $t6 # the sum to print
syscall # print the sum
blt $t0, $t1, loop # branches to Loop if $t0 < 100
Right off the bat, s1 and s2 should be initialized to the stack-based (I assume) address of your arrays.

Resources