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).
Related
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
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.
I have a doubt on one exercise that my professor did during a seminar. It's basically a translation from C to MIPS. The C code is as follows:
void subr1(char *a, int v[]) {
int i;
char c[12];
for (i=11; i >= 0; i--) {
v[i] = subr2(c[i], *a);
}
}
And the translation of my professor was the following (I've written comments about what each instruction does and what I don't understand):
addiu $sp,$sp,-28 #Activation block
sw $ra, 24($sp) #Space for $ra (4 bytes)
sw $s0, 20($sp) #Space for *a (32-bit address = 4 bytes)
sw $s1, 16($sp) #Space for c (Q1: Shouldn't this be 12 bytes? c is an array of 12 chars = 12*1Byte=12Bytes)
sw $s2 12($sp) #Space for i (4 bytes)
(Q2: Why is he stopping at 12? Doesn't he need to save space for int v[]?)
move $s0,$a0 #Save 'a' in stack
move $s1,$a1 #Save 'c' in stack
li $s2, 11 #i=11
For:
blt $s2, $zero, End #if i<0, then go to 'End'
addu $t0, $s2, $sp (Q3: I'm not sure, but I think he's trying to access v[i] by summing $sp and 'i'. Can you do that, without initialising any register at the beginning like we did for $s0 and $s1?)
lb $a0, 0($t0) #$a0 = v[i] (Q4: Isn't this wrong? It should access c[i], not v[i])
lb $a1, 0($s0) #$a1 = *a
jal sub2 #Jump to sub2
sll $t1, $s2, 2 #$t1 = 4*i
addu $t1,$t1,$sp #$t1 = 4*i + $sp (By this, I guess he's accessing v[i])
sw $v0,0($t1) #v[i] = $v0 (returned value from sub2)
addiu $s2, $s2, -1 #i--
b For
end:
#Close the activation block
lw $s2,12($sp)
lw $s1,16($sp)
lw $s0,20($sp)
lw $ra,24($sp)
addiu $sp,$sp,28
jr $ra #Jump to register address
Could somebody help me?
Thank you in advance.
so my professor put this problem in his slides and this was his answer, not understanding how he converted it into MIPS so if anyone could help explain this that would be great.
Variable i is in $s3, k is in $s5, and the base address of save[] is in $s6
He gave us this C code:
while( save[i] == k ) {
i += 1;
}
And gave us this MIPS code in response:
Loop: sll $t1, $s3, 2
add $t1, $t1, $s6
lw $t0, 0($t1)
bne $t0, $s5, Exit
addi $s3, $s3, 1
j Loop
Exit:
Loop: sll $t1, $s3, 2 # $t1 = 4*i (this is the offset to get to the ith element in your array)
add $t1, $t1, $s6 # $t1 = 4*i + base addr of save (getting the address of save[i])
lw $t0, 0($t1) # $t0 = save[i] (actually loading 4B from address of save[i], so getting the actual number here)
bne $t0, $s5, Exit # branch to Exit if save[i] != k
addi $s3, $s3, 1 # i++
j Loop
Exit:
Things to note here:
save is an int array, so each element is 4B. That's why the offset is 4*i.
I was trying to convert C code to MIPS assembly. There are these two following C code snippets. The problem is that my solution differs from the standard solution. Also, I don't understand the standard solution. I hoped, someone could explain me the two following mips assembly code snippets.
First of all some additional information for the task. Only the following MIPS instructions are allowed: lw, add, beq, bne and j.
The register:
$s3 contains i
$s4 contains j
$s5 contains k
A is an array of 32-Bit-Integer and the initial address of A is in $s6
$t0 and $t1 can be used for storing temporary variables
The first one is a simple do-while loop:
do {
i = i + j;
} while(A[i] == k);
MIPS Assembly
loop: add $s3, $s3, $s4 // this is i = i+j
add $t1, $s3, $s3 // from now on
add $t1, $t1, $t1 // I cant follow anymore
add $t1, $t1, $s6 // What happens in these three lines?
lw $t0, 0($t1) // 0($t1) is new for me. What does this zero do?
beq $t0, $s5, loop
Now the second C code:
if ( i == j )
i = i + A[k];
else if( i == k )
i = i + A[j];
else
i = i + k;
Here is the MIPS assembly code:
bne $s3, $s4, Else1 // this line is if(i==j)
add $t1, $s5, $s5 // from here on
add $t1, $t1, $t1 // till
add $t1, $t1, $s6 //
lw $t0, 0($t1) //
add $s3, $s3, $t0 // here I don't understand
j done
ELSE1: bne $s3, $s5, Else2 // this line is if(i==k)
add $t1, $s4, $s4 // The same game as above
add $t1, $t1, $t1
add $t1, $t1, $s6
lw $t0, 0($t1)
add $s3, $s3, $t0 // till here
j done
ELSE2: add $s3, $s4, $s5
Could anyone explain me what really goes on? That would be very helpful
O.k. the most interesting and not-understandable piece of code is the following:add $t1,
add $t1, $s5, $s5
add $t1, $t1, $t1
add $t1, $t1, $s6
this code multiplies $s5 by four, and stores it in $t1, then adds to $t1 $s6. That is equivalent to:
$t1 = A[k]
after you understand this, the code looks much clearer.
about the lw $t0, 0($t1):
you can use an offset point in the address. Here the offset is 0.
lw is load. The mode here is indirect addressing, the most common is:
lw $t2, ($t0)
But you can also include a byte offset,
lw $t2, 4($t0) # load word at RAM address ($t0 + 4) into register $t2
The compiler is just putting the 0 placeholder in the non-offset version.
So, to load A[i] you need to do two things. Take the base address of A[] and then add i times the sizeof(A[0]). I am guessing that the values in A are 32 bit.
add $t1, $s3, $s3
$t1 = j + j or 2 * j
add $t1, $t1, $t1
$t1 = $t1 + $t1 or j +j +j +j or 4 * j
So why did it do it this way? Well, doing a straight multiply is slow in terms of clock cycles. The next choice would be a shift operation, but in this case, the compiler designers decided that two adds beat a shift.
add $t1, $t1, $s6
I would guess that $s6 is the base address of A[]. So ultimately '$t1 = A[] + 4 * j`
I have a answer.The loop, a is array of elements have basic address :0x0FE3B128.
Thanks all so much..
and this is my homework, I don't sure that it is correct.
for(i=1; i!=20;i+=3){
a[i]= a[5]+1;
}
lui $s0, 0x0FE3
ori $s0, $0, B128
lw $t1, 20($s0)
addi $s1, $0, 1
addi $s2, $0, 20
LOOP beq $s1, $s2, DONE
add $t1, $t1, $s1
sll $t1, $t1, 2
sw $t2, 0($t1)
addi $s1, $0, 3
j LOOP
DONE