Getting address out of range in MIPS assembly? - arrays

I am trying to reverse an array using only one array. When the index of high is less than or equal to low, I am supposed to keep switching the content of high and low. However, I am getting address out of range and am having trouble finding resources on how to fix it.
I'm supposed to only use one array while reversing the array. What am I doing wrong? Starred is where I am getting the error.
reverseArray:
li $t6, 0 #head = first index of array
la $s0, array
li $t5, 4
mult $s0, $t5
mflo $t7 #tail = last index of array
swap:
lw $t6, 0($s0)
**lw $t4, 0($t7)**
sw $t4, 0($s0)
sw $t6, 0($t7)
add $t7, $t7, -4
add $s0, $s0, 4
sle $t1,$t7,$s0
beq $t1,$0,swap

I assume what you want in $t7 is the address of the last element of the array. Multiplying the base address by 4 is not going to give you that address. What you need to calculate is array + (length-1)*4.
So you need to know the length of the array. The code you've posted doesn't indicate that you know the length of the array, but let's say that you've got the length in register $t6. The calulation you need to perform then is:
addiu $t7,$t6,-1 # $t7 = length-1
sll $t7,$t7,2 # $t7 = (length-1)<<2 == (length-1)*4
addu $t7,$t7,$s0 # $t7 = (length-1)*4 + array
swap:
lw $t6, ($s0)
lw $t4, ($t7)
... etc ...

Related

MIPS Assembly why are these registers loading the same array values?

I'm trying to load in array values in the first and second position but for some reason it's loading in only the value in the first position? Been trying to figure it out for an hour but no luck. This is the code I have. I set $t1 to 0 and $t3 to 4 so I should be loading in the first and second value, yet it only loads in the first value for both $t1 and $t3?
addi $t1, $zero, 0
addi $t3, $zero, 4
FindLessThenLoop:
la $t1, myArray # Load first number
addu $t1, $zero, $t1 # add offset and base together
lw $t1, ($t1) # fetch the data
la $t3, myArray # Load second number
addu $t3, $zero, $t3 # add offset and base together
lw $t3, ($t3) # fetch the data
The code for the first and the second are essentially the same except using a different register, so, we would expect the same results: the value from array position/index 0.
To get the second element, you can do either:
la $t3, myArray # Load second number
addiu $t3, $t3, 4 # add offset and base together
lw $t3, ($t3) # fetch the data
-or-
la $t3, myArray # Load second number
lw $t3, 4($t3) # fetch the data with offset 4
You'll prefer a variation of the first form if you're going to do variable indexing (e.g. a[i]), say in a loop, whereas the second form is for constant indexing (e.g. a[1]).
If you have an integer index, then the following is useful:
# usually done outside of and before a loop:
la $t3, myArray # Load second number
# this part done inside a loop:
sll $t4, $t2, 2 # scale the integer index by 4
addu $t4, $t3, $t4 # add base and offset
lw $t1, ($t4) # fetch the data
Note the following:
there is pre-loop setup of $t3
inside the loop we preserve $t3 so it can be used each iteration
we scale the simple integer index by size of the elements (4x)
An alternative is pointers, which are fairly easy in assembly, but suggest to convert your algorithm to pointers in C first, then take to assembly.
A pointer combines into one variable the notion of base + scaled offset.  A pointer can be incremented to refer to the next element.
Here's a simple illustrative loop that does max value of array, assuming elements are positive:
li $t0, array # t0 is the base array address: &array[0]
li $t1, 0 # t1 is min value variable, initially zero
li $t2, 0 # t2 is the index, aka loop control variable call it "i"
li $t3, 10 # where to stop with "i"
loop1:
beq $t2, $t3, loop1End # if "i" == 10 we're done
sll $t4, $t2, 2 # scale index by 4 due to word-sized elements
add $t4, $t0, $t4 # add base and scaled offset
lw $t4, 0($t4) # fetch element from a[i]
ble $t4, $t1, if1End
move $t1, $t4 # capture the new max, if larger
if1End:
addi $t2, $t2, 1 # next index position
j loop1
loop1End:
... # t1 holds max value from the array

Bad Addressing in MIPS - Matrix Multiplication

A followup from my post yesterday,
I'm working on a matrix multiplication assignment in MIPS Assembly. The following is the code from my inner most 'k' loop where I compute A[i][k]*B[k][j].
# compute A[i][k] address and load into $t3
# A[i][k] = A+4*((4*i) + k)
sll $t3, $t5, 2 # Store 4*i in $t3
addu $t3, $t3, $t7 # Adds $t3 to k
sll $t8, $t3, 2 # Computes 4*($t3) = 4*(4*i+k) by temporarily storing the product in $t8
move $t3, $t8 # Stores 4*($t3) into $t3
addu $t3, $t3, $a0 # Adds A to $t3
lw $t3, 0($t3)
# compute B[k][j] address and load into $t4
# B[k][j] = B+4*((4*k) + j)
sll $t4, $t7, 2 # Stores 4*k in $t4
addu $t4, $t4, $t6 # Adds $t4 to j
sll $t8, $t4, 2 # Computes 4*($t4) = 4*(4*k+j) by temporarily storing the product in $t8
move $t4, $t8 # Stores 4*($t4) into $t4
addu $t4, $t4, $a1 # Adds B to $t4
lw $t4, 0($t4)
# multiply
multu $t3, $t4
mflo $t9
# insert the multiplied value into $a2
sll $t1, $t5, 2 # Multiplies $t5 by 4 and stores the value in $t1
addu $t1 $t1, $t6 # Adds $t1 and $t6 (j) for the final bit offset
move $t2, $a2 # Stores $a2's base register in $t2 temporarily
addu $a2, $a2, $t1 # Adds bit offset to $a2
sw $t9, 0($a2) # Store $t9 into its respective location in with offset from $a2
move $a2, $t2 # Restores base address back into $a2
# increment k and jump back or exit
addi $t7, $t7, 1
j kLoop
From what I can see, the multiplying works as it should. For reference, my $t5 - $t7 are for my i, j, and k.
My next step is to insert the result, stored in $t9, into my result array, situated at register $a2. In order to store $t9 at its proper location in $a2, I need to compute the offset. I know the offset is $a2 * the row + the column. However, when I run my code, I get Bad Addressing errors. I know something has to be wrong with this offset computation, because when I remove it, the program continues normally but there's an issue with my output. This issue stems from the lack of offset calculation. If anyone can help me out here, it would be much appreciated. Stackoverflow has helped me out so much with understanding MIPS, so I'm grateful for everyone's assistance! Thanks
So it turns out I wasn't calculating the bit offset properly - I wasn't multiplying the 4*i+j by 4 to get a multiple of 4 that can be addressed. After making that change, my multiplying part of my k loop now looks like this:
# multiply
multu $t3, $t4
mflo $t9
# insert the multiplied value into $a2
sll $t1, $t5, 2 # Multiplies $t5 (i) by 4 and stores the value in $t1
addu $t1 $t1, $t6 # Adds $t1 and $t6 (j) for the col offset
sll $t1, $t1, 2 # Multiplies $t1 by 4 and stores value back into $t1 for final bit offset
move $t2, $a2 # Stores $a2's base register in $t2 temporarily
addu $t2, $t2, $t1 # Adds bit offset to $t2 / $a2's temp alias
lw $t1, 0($t2) # Overwrites $t1 with the value currently at $t2
addu $t9, $t9, $t1 # Adds the current $t2 val ($t1) to $t9
sw $t9, 0($t2) # Store $t9 into its respective location in with offset from $a2
I figured I might as well share this with people so if anyone else has this issue, it can be resolved with relative ease. Thank you to everyone who assisted me with this problem!

How to compare elements of array in mips assembly?

I know how to iterate through an array in mips. However I can't seem to figure out how to compare two elements in the same array? Can anybody point me in the right direction here?
if(array[i] > array[i - 3])
I believe it would be a branch if greater than comparing two registers but how would I get the data into the two registers? Thanks!
You cant just iterate an array... You have to add a multiple of 4 (=> index * 4) to the memory address of the array. Then you can load the value at this modified memory addres and compair it to a diffrent moddified addres...
.data
array: .word 1,2,3
#Index's you want to compair
i1: .word 0
i2: .word 1
.text
MAIN:
lw $a0 i1
lw $a1 i2
li $t5 4 #load multiplier
mul $a0 $a0 $t5
mul $a1 $a1 $t5
la $t0 array
la $t1 array
add $t0 $t0 $a0
add $t1 $t1 $a1
lw $t0 ($t0)
lw $t1 ($t1)
beq $t0 $t1 TRUE

How do I avoid hard coding array index/indices within a loop in MIPS?

For example,
$a0 is an index/pointer
$a1 is the address of the array base
I want to access each element of the array within a loop, perform an arithmetic operation to that element, then save it to the next. The index should increase +1 on each iteration.
For a simple example, I'm trying to square each previous element in the array. Initial hard coded values are INDEX[0]=0, ARRAY[0]=2. I've marked where I'm confused. I don't know how to make this variable for each loop.
.data
INDEX: .space 4
.align 2
ARRAY: .space 16
.align 2
.text
la $a0, INDEX
la $a1, ARRAY
li $t0, 0
sw $t0, ($a0) # set INDEX[0]=0
li $t0, 2
sw $t0, ($a1) # set ARRAY[0]=2
LOOP:
lw $t0, ($a0)
sll $t0, $t0, 2 # $a0 * 4 to get element offset
lw $t1, $t0($a1) # STUCK HERE (1)
add $t1, $t1, $t1 # square
lw $t0, ($a0)
add $t0, $t0, 1
sw $t1, $t0($a1) # AND HERE (2)
add $a0, $a0, 1
... keep looping if space remaining in $a1
(1) How do I save the element ARRAY[INDEX] to register $t1 without hardcoding the offset?
(2) How do I save the altered register $t1 to a specific element in the array: ARRAY[INDEX] = $t1
Since the indirect addressing will change on each loop, I want to avoid using 4($a1), 8($a1), etc.
Thank you.
You need to add the base address and index together. Something like this ought to work:
sll $t2, $t0, 2 # $a0 * 4 to get element offset
add $t2, $t2, $a1 # Add the array base address to the scaled index
lw $t1, ($t2) # $t1 = ARRAY[index]
add $t1, $t1, $t1 # square
add $t0, $t0, 1
sw $t1, ($t2)
Note that you're not actually squaring numbers - you're doubling them (t1 = t1 + t1). To square a number you'd multiply it by itself.

MIPS code broken

I'm working on some MIPS code for my Computer Organizations class, and well I just can't seem to get the MIPS to work correctly and there's not that many MIPS resources online. I'm running the code on PCSPIM. The code is supposed to add 10 to the contents of array2 and store them in array1 and then print array 1. Reworked the code works properly now.
.text
main:
la $t0, array1
la $t1, array2
la $s0, valuec
li $s2, 6
add $t6, $zero, 1 #i = 1
Loop:
addi $t6, $t6, 1 #i++
lw $t2, ($t0)
lw $t5, ($t1)
lw $s1, ($s0)
addu $t2, $t5, $s1
sw $t2, ($t0)
add $t0, $t0, 4
add $t1, $t1, 4
li $v0, 1
move $a0, $t2
syscall
blt $t6, $s2, Loop
li $v0, 10
syscall
.data
array1: .space 20
array2: .word 1,2,3,5,9
valuec: .word 10
PCSPIM prints 0 5 times and returns Exception 7 [Bad data Address] occured and ignored
This is homework so I'm only going to give you clues for now and add to it as you go. A couple of things:
1/ You need to tell us what it's supposed to do. That's the most important thing.
2/ You store array1 address into t0 then reuse t0 within the first loop.
3/ You appear to be confused about addresses and the contents of those addresses ("la $s0, valuec" and "addu $t0, $t1, $s0").
UPDATE:
Actually I have to sign off for a while, so I'll post my solution so as to not leave you in the lurch.
The confusion I referred to before was the fact that you're loading up two addresses into $t1 and $s0, then adding them together to get another address - this is likely to be well beyond your data area (you should really be adding an address and an offset).
That's basically the problem you have with your code (both the zeros being printed and the crash). Your best bet would be to fix that and refer to my code below only as a last resort to see how I would have done it. Copying code will not help you in the long term and you would be wise to assume your educator is also checking all web sites for plagiarism.
This is the code I've come up with (quickly, so you'll need to test it - it may have bugs). I suggest you read the comments in great detail to understand what it's doing.
I'll be back in a few hours to see how you're doing. Cheers.
.text
main:
# Initialization of array pointers and loop
la $t0, array1 # address of array 1
la $t1, array2 # address of array 2
li $t2, 1 # element number
li $t3, 6 # upper limit of elements
# Process each word in array 2, adding 10 and placing
# into array 1.
Loop:
lw $t3, 0($t1) # get word from array 2
addi $t3, $t3, 10 # add 10 to word
sw $t3, 0($t0) # store word into array 1
addi $t0, $t0, 4 # move to next entry in array 1 and 2
addi $t1, $t1, 4
addi $t2, $t2, 1 # increment element number
blt $t2, $t3, Loop # loop until all elements done
# Initialize printing loop by going back to start of array 1
la $t0, array1 # address of array 1
li $t2, 1 # element number
# Loop through array 1, printing each element.
pLoop:
lw $t2, 0($t0) # get word from array 1
li $v0, 1 # 'print' command code
move $a0, $t2 # needs value in $a0
syscall # print it
addi $t0, $t0, 4 # move to next entry in array 1
addi $t2, $t2, 1 # increment element number
blt $t2, $t3, Loop # loop until all elements done
li $v0, 10 # 'terminate' command code
syscall # exit
# Data arrays for array 1 and 2
.data
array1: .word 0,0,0,0,0
array2: .word 1,2,3,4,5
There's a number of possible issues, but the most obvious/likely is that you aren't returning from main before the start of your data section.
jr ra

Resources