Array indexing in a for-loop in MIPS assembly - arrays

I need to implement this code in the MARS emulator:
int x[10] = { /* initial values */ } ;
int i;
for(i=0; i<10; i++){
print i;
}
for (i=0; i<10; i++){
x[i] = 2*i+1;
print x[i];
}
Heres what I have:
.data
i: .word 0
x: .word 1,2,3,4,5,6,7,8,9,10
.align 2
.text
.globl main
main:
lw $t0, i
lw $t1, x
li $t4, 4
jal L0
li $t0, 0
jal L1
li $v0, 10 # terminate
syscall
L0:
li $v0, 1
la $a0, ($t0)
syscall
addi $t0, $t0, 1
bge $t0,10, RETURN #goto L1 if NOT n<0
b L0
L1:
li $v0, 1
la $a0, ($t1)
syscall
mul $t2, $t0, $t4
lw $t1, x + ($t2) #########this line#########
addi $t0, $t0, 1
bge $t0,10, RETURN
b L1
RETURN:
jr $ra
I commented next to the line that I believe to be the source of my problem. That is essentially the line that is referencing x[i]. I multiplied i by 4 and added that value to x, in attempt to reference the appropriate word in the array. I don't know how to properly implement this concept.
Thanks for the help.

You need to do something like this:
L1:
la $a1,x # $a1 = &x
L2: # do {
addu $a0,$t0,$t0 # $a0 = i*2
addiu $a0,$a0,1 # $a0 = i*2 + 1
sw $a0,($a1) # x[i] = i*2 + 1
addiu $a1,$a1,4 # a1 = &x[i+1]
li $v0,1 # print_int
syscall # print_int(i*2 + 1)
addiu $t0,$t0,1 # i++
bne $t0,10,L2 # } while (i != 10)
jr $ra
And stuff like la $a0, ($t0) looks really weird. Please use the much clearer move $a0, $t0 instead.

Related

(C to MIPS)I dont know why I cant printf all of the output like C code do

I had tried my best to turn the C code to mips code.
I cant find why I cant printf all of the output like C code do.
I think problem is about $ra, but I cant fix it.
I need help.
thanks for the nice guy like you.
I need output like this
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5 *
2 3 4
2 3 5
2 4 5
3 4 5
but MIPS code will exit at *.
C
#include <stdio.h>
static int cl[3];
static int n=5;
static int k=3;
void dfs(int cur, int s ){
int i;
if (cur==k) {
for (i=0; i<k; i++){
printf("%d ",cl[i]);
}
printf("\n");
}
else{
int p=n-k+cur+1;
for (i=s; i<=p; i++){
cl[cur]=i;
dfs(cur+1,i+1);
}
}
}
int main(){
dfs(0,1);
}
ASM
.data
cl: .word 0,0,0 #cl[3]
n: .word 5 #n=5
k: .word 3 #k=3
space: .asciiz " "
enter: .asciiz "\n"
.text
main: li $s0, 0 #cur = 0
li $s1, 1 #s = 1
jal dfs
j exit
dfs: addi $sp, $sp, -12
sw $ra, 0($sp)
li $t3, 0 #i=0
lw $t0, k #k=3
if: bne $s0, $t0, else #if(cur==k)
la $t0, cl #get address of cl[i]
loop:
lw $a0, ($t0) #printf
li $v0, 1
syscall
la $a0, space # load address of spacer for syscall
li $v0, 4 # specify Print String service
syscall
addi $t3, $t3, 1 # i++
addi $t0, $t0, 4 # cl[i++]
lw $t1, k
blt $t3, $t1,loop #i<k
la $a0, enter # load address of enter for syscall
li $v0, 4 # specify Print String service
syscall
j done
else: lw $s2, n # n
lw $t0, k # k
sub $s2, $s2, $t0 #n-=k
add $s2, $s2, $s0 #+=cur
addi $s2, $s2, 1 # +=1
move $t0, $s1 #i=s
loop2: la $t1, cl #load address from cl
sll $t2, $s0, 2 #t2=cur*4
add $t1, $t1, $t2 #t1=*cl+cur*4
sw $t0, ($t1) #cl[cur]=i
addi $s0, $s0, 1 #cur++
addi $s1, $t0, 1 #s=i+1
sw $t0, 4($sp)
sw $s2, 8($sp)
jal dfs
addi $s0, $s0, -1
addi $s1, $s1, -1
addi $t0, $t0, 1
ble $t0, $s2, loop2 #i<=s2
done:
addi $sp, $sp, 12
lw $ra, 0($sp)
lw $t0, 4($sp)
lw $s2, 8($sp)
jr $ra #return void
exit:
You are incrementing the stack pointer — popping it — too early in the function epilogue. To reverse the prologue we change the sign of the immediate in adding to the stack pointer and move it to the end and otherwise change sw's to lw's.
done:
addi $sp, $sp, 12 <--- this is too early
lw $ra, 0($sp)
lw $t0, 4($sp)
lw $s2, 8($sp)
<--- it belongs here
jr $ra #return void

What is the problem with this quick sort in MIPS?

This is the C code i am using to make the quick sort on the MIPS, on the Mars editor i am having issues when running these code
#include <stdio.h>
void QuickSort(int *array, int first, int last){
int q;
if (first<last){
int value = array[last];
int i = first-1;
int tmp;
int j = first;
while(j<=last){
if (array[j] <= value) {
i++;
tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
j++;
}
q = i;
QuickSort(array,first,q-1);
QuickSort(array,q+1,last);
}
}
And this is my MIPS translation so far, i am getting an infinite loop
.data
numArray: 30, 15, 11, 40, 75, 80, 70, 60
first: 0
last: 7
.text
main:
la $a0, numArray
lw $a1, first
lw $a2, last
jal quick_sort
li $v0, 10
syscall
quick_sort:
subi $sp, $sp, 4 #reserving memory in the stack
sw $ra, 4($sp) #storing the return adress in the stack
xor $t0, $t0, $t0 #int q
bge $a1, $a2, label1 #if (first<last)
sll $t1, $a2, 2 #int value = array[last];
add $t1, $t1, $a0 #callculating array[last] in $t1
lw $t1, 0($t1) #array[last] = array direction + 4 * last
or $t2, $t1, $zero #$t2 will be value
subi $t3, $a1, 1 #int i = first-1;
xor $t4, $t4, $t4 #int tmp
or $t5, $a1, $zero #int j=first
j label2 #while(j<=last)
label3: sll $t6, $a2, 2 #calculating array[j] adress
add $t6, $t6, $a0
lw $t7, 0($t6) #calculating array[j] value
bgt $t7, $t1, label4 #if (array[j] <= value)
addi $t3, $t3, 1 #i++
sll $s0, $t3, 2 #calculating array[i] adress
add $s0, $s0, $a0
lw $s1, 0($s0) #calculating array[i] value
or $t4, $s1, $zero #tmp = array[i]
sw $t7, 0($s0) #array[i] = array[j];
sw $t4, 0($t6) #array[j] = tmp;
label4: addi $t5, $t5, 1 #end if; j++
label2: ble $t5, $a2, label3 #while condition
or $t0, $t3, $zero #q = i
lw $a1, first #first value on the second parameter
subi $a2, $t0, 1 #q-1
jal quick_sort #QuickSort(array,first,q-1)
addi $a1, $t0, 1 #q+1
lw $a2, last #last value on the third parameter
jal quick_sort #QuickSort(array,q+1,last);
label1: lw $ra, 4($sp) #Recovering the return address from the stack
addi $sp, $sp, 4 #releasing memory
jr $ra #going to the return address
Maybe i need to store something more on the stack or something that i am missing, thanks for your help, anything that you see strange there please let me know to check it.
EDIT:
As pointed out by Minn in a comment, I missed the two lines following:
sll $t1, $a2, 2 #int value = array[last];
So while this single line does not match the comment in it, the loading of the value seems correct.
END EDIT
I am not familiar with this specific assembly, but the problem seems to be what is known as "register clobbering" :
According to documentation jal only stores the return address, but does not store any of the registers.
lw $a1, first #first value on the second parameter
subi $a2, $t0, 1 #q-1
jal quick_sort #QuickSort(array,first,q-1)
addi $a1, $t0, 1 #q+1
lw $a2, last #last value on the third parameter
jal quick_sort
You are using $t0 as q local variable, but you never save it on the stack.
After the first call jal quick_sort #QuickSort(array,first,q-1) the value of $t0 would be different, but you use it immediately in the line addi $a1, $t0, 1 #q+1 as if it never changed, and then pass the result to the second call to QuickSort.
The C equivalent to this error would be to make q global and add q = 0; at the beginning of the function.
You must remember, that when working in assembly and using registers for local variables, you must save their state to the stack before calling any other function from your current function, otherwise you will lose state and your code will not work as expected!
To be honest, this is my first time seeing this particular assembly language, so there might be other errors I missed, but these are the most obvious ones so they were easy to spot.

mips string copy: error in spim

Q1. In my class ppt, that codes are written, but the MIPS code does not work in SPIM. How can I revise the MIPS code?
Q2. Assume that address of x and y are 100 and 200, respectively, and i = 10 and sp = 500. How can I revise MIPS code with that MIPS source code?
//strcpy C code
void strcpy (char x[], char y[])
{
int i;
i = 0;
while ((x[i]=y[i])!='\0')
i += 1;
}
//strcpy MIPS code
.data
Array: .space 10
.text
strcpy:
addi $sp, $sp, -4
sw $s0, 0($sp)
add $s0, $zero, $zero
L1:
add $t1, $s0, $a1
lbu $t2, 0($t1)
add $t3, $s0, $a0
sb $t2, 0($t3)
beq $t2, $zero, L2
addi $s0, $s0, 1
j L1
L2:
lw $s0, 0($sp)
addi $sp, $sp, 4
jr $ra
you undefined "main" symbols, and you should pass arguments for strcpy.
for example:
main:
la $a0, str1 # first args
la $a1, str2 # second args
jal strcpy # jump and save return address
li $v0, 4 # print_string
add $a0, $a0, $zero
syscall
li $v0, 4
add $a0, $a1, $zero
syscall
li $v0, 10 # exit program

C to MIPS conversions

int MyArray[30];
int n = 2;
MyArray[0] = 1;
MyArray[1] = 1;
do{
MyArray[n] = MyArray[n-1] + MyArray[n-2];
n++;
}
while(n < 30);
While I was doing this I got stuck on how i can recursively call the function without the use of return address $ra or $sp since the code doesn't actually return anything.
This is my work so far :
#s1= Myarray[0]
addi $s0, $0, 2 #$s0=n=2
addi $t0, $s1,0
addi $t1,$0,1
sw $t1, 0 ($t0) #Myarray[0]=1
addi $t0,$t0,4
sw $t1, 0 ($t0) #Myarray[1]=1
add $t0,$s0,$s1 #MyArray[n]= Myarray[0] +n
Loop:
addi $t2,$t0,-4
addi $t3,$t0,-8
lw $t4,0 ($t2)
lw $t5,0 ($t3)
add $t5,$t4,$t5
sw $t5, 0 ($t0)
addi $t0, $t0 ,4
addi $s0,s0,4
slti $s6,$s0,30
beq #s6,$0,Exit
j loop
Exit
This code
sw $t1, 0 ($t0) #Myarray[0]=1
addi $t0,$t0,4
sw $t1, 0 ($t0) #Myarray[1]=1
add $t0,$s0,$s1 #MyArray[n]= Myarray[0] +n
should be
sw $t1, 0 ($t0) #Myarray[0]=1
addi $t0,$t0,4 #update 't0' to point to Myarray[1]
sw $t1, 0 ($t0) #Myarray[1]=1
addi $t0,$t0,4 #update 't0' to point to Myarray[2]
The error is in the last line. Note that $s1 points to the array, and $s0 has the value 2, so t0=s1+s0 points t0 to the wrong address. You really want t0=s1+(s0*4) since each int is four bytes.
However, since you've already updated t0 to point to Myarray[1] (in the second line), you can just update it again (in the fourth line).

MIPS Assembler trouble - Arrays

I have an assembly code containing an array, and I simply cannot understand what actually the result in the $s2 register shows. If someone could help and explain or simplify it for me that would be great.
Here's the code:
.data arr: .word 3 2 -6 1 4 10 530 115 2231 1422
arrSize: .word 10
.text
.global main
main:
la $s0, arr
la $t0, arrSize
lw $s1, 0($t0)
add $s2, $zero, $zero
loop:
lw $t1, 0($s0)
andi $t2, $t1, 1
bne $t2, $zero, skip
addi $s2, $s2, 1
skip:
addi $s0, $s0, 4
addi $s1, $s1, -1
bne $s1, $zero, loop
end:
add $v0, $zero, $s2
I've added some pseudo-code comments to the code:
.data arr: .word 3 2 -6 1 4 10 530 115 2231 1422
arrSize: .word 10
.text
.global main
main:
la $s0, arr ;; s0 = arr // init s0 = pointer to start of arr
la $t0, arrSize ;; t0 = &arr_size // get no of elements in arr
lw $s1, 0($t0) ;; s1 = arr_size = 10
add $s2, $zero, $zero ;; s2 = 0 // init count of even elements = 0
loop: ;; do { // for all elements in arr do
lw $t1, 0($s0) ;; t1 = *s0 // get element from arr
andi $t2, $t1, 1 ;; t2 = t1 & 1 // test element for odd/even-ness
bne $t2, $zero, skip ;; if (t2 != 0) // if not odd (i.e. even) then
addi $s2, $s2, 1 ;; s2++ // increment count in s2
skip:
addi $s0, $s0, 4 ;; s0++ // increment pointer to next element in arr
addi $s1, $s1, -1 ;; s1-- // decrement count of elements to process
bne $s1, $zero, loop ;; } while (s1 != 0) // end of do loop
end:
add $v0, $zero, $s2 ;; v0 = s2 // return result in v0
It seems that this just iterates through the elements of arr, testing each element to see if it is even, and incrementing a count of even elements found. The final result (in v0 and s2) will be 6, since there are 6 even elements in the array.

Resources