C language to MIPS. Fibonacci Number - c

I was trying to convert this piece of code into MIPS instruction. Lets say that a is in $a0, b is in $a1, n is in $a2, the result is in $v0, and to end the
program, call “jr $ra” to return to the subroutine caller
int fib_iter(int a, int b, int n) {
if (n == 0)
return b;
else
return fib_iter(a+b, a, n-1);
For the simplicity, we just ignore the stack frame for this one
And this is the MIPS code I converted:
bne $a1, $zero, ELISEIF // if b != 0 go to ELSEIF
lw $v0, $0($a1) // load b to result if n == 0
j DONE // done
ELSEIF:
lw $at, $0($a0) // temp = a
add $a0, $a0, $a1 // a = a + b
add $a1, $zero, $zero // clear b
lw $a1, $0($at) // b = a
sub $a2, $a2, $1 // n = n - 1
jr $ra // call the subroutine caller
Done:
what to put??
Please point out my errors(there might be a a lot since I am new to this)
Thanks for your time for helping me and I appreciate that

lw $v0 $0($a1) will do $v0 = $a1[0] instead of $v0 = $a1. To do the latter, use mv $v0 $a1.
Also $at is reserved for pseudoinstructions in MIPS. I means they get modified by pseudoinstructions. So, do not use it unless you are sure that you have not used any pseudoinstruction. $t1 to $t7 are temporary registers. Use any one of them.
Here is the correct code
FIB:
bne $a2, $zero, ELSE // if n != 0 go to ELSE
mv $v0, $a1 // load b to result if n == 0
jr $ra // end of recursion, so call the subroutine caller
ELSE:
mv $t0, $a0 // temp = a
add $a0, $a0, $a1 // a = a + b
mv $a1, $t0 // b = a
addi $a2, $a2, -1 // n = n - 1
j FIB // call FIB recursively

Related

Square Root MIPS assembly

Hi I need help in coding in MIPS. I have to find the Floor Square root of the n input. I have the C version of the code..
uint32_t isqrt(uint32_t n) {
if(n<2) return n;
uint32_t s = isqrt(n >> 2) << 1;
uint32_t l = s + 1;
if (l * l > n)
return s;
else
return l;
}
apparently it recurses itself..
Right now my function looks something like. Im not really sure what I am doing wrong
#isqrt
isqrt:
#prologue
subu $sp, $sp, 12
sw $ra, 8($sp)
sw $s0, 4($sp)
sw $s1, 0($sp)
#if(n<2) n Branch if Greater Than 2
blt $a0, 2, lt2 #if(n<2) return n;
#else uint32_t small = isqrt(n >> 2) << 1;
srl $s0, $a0, 2 # small = isqrt(n >> 2)
jal isqrt
sll $s0, $s0, 1 # then << 1
add $s1, $s0, 1 # large = small + 1
li $s3, 0
mul $s3, $s1, $s1 # large = large * large\
#if large * large > n return small else return large
bgt $s3, $s0, small # if l * l > n return small
move $v0, $t1 # else return large
lt2:
move $v0, $a0;
j end
small:
move $v0, $s0
j end
end:
lw $ra, 8($sp)
lw $s0, 4($sp)
lw $s1, 0($sp)
addi $sp, $sp, 12
jr $ra
Good effort, but many, many, many errors.  Suggest trying a more methodological approach.  Check your choices of registers, you register numbers, and prologue/epilogue code for proper handling of the various register kinds.
That code is doing if (n>=2) return n; — the exact opposite of the C code.
The called function isqrt expects a formal parameter in $a0, but that code is passing the actual argument in $t0, so there's a mismatch.
The called function isqrt provides the return value in $v0, but when calling that recursively, expects it to have been provided in $t0, another mismatch.
The function uses $s0, but fails to ensure its value is call-preserved as it should have been.
The following code:
li $t0, 2 # small = isqrt(n >> 2) << 1
srl $t0, $t0, 2
generates 2>>2, which is clearly different from the n>>2 in the C code.
The following code:
equal:
move $v0, $t1
j end
is doing return l*l; where the C code wants return l;
I'd suggest starting with an analysis of what registers to use for what variables — this analysis requires examining liveness across the (recursive) function call.  Start that analysis on the C version initially.  When you're finished with that, you'll have a mapping of register numbers for all the C variables.  Then write prologue/epilogue that handle those registers as required.  Then translate the C code line by line into assembly paying careful attention to what variables are in what registers, and what expressions you're trying to recreate in assembly.

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 nested function calls

I'm trying to convert a C Code to MIPS code.
int main() {
int a;
int b;
int result = 0;
if (a != b)
result = test(a, b);
else
result = a + b;
return result;
}
int test(int a, int b) {
if (a > b)
return multiply(a, b)
else
return subtract(a, b)
}
int multiply(int a, int b) {
return a * b;
}
int subtract(int a, int b) {
return a - b;
}
This code contains nested function calls inside test function.
I have put the return address of test function into stack and trying to return the subtracted or multiplied value to the main.
But in my case, my code executes both subtract and multiply functions.
I'm trying to put my result to s0. After running s0 always shows subtraction of values. If I put multiply result to s1, s1 shows true value.
I think subtract function overrides value at s0. But when case is multiply, why subtract method is called? I have an if/else block, but this part seems to be not working.
Here is my MIPS Code, what am I doing wrong?
.data
numberA: .word 4
numberB: .word 2
.text
.globl main
main:
addi $s0, $0, 0 # result = 0
lw $a0, numberA
lw $a1, numberB
bne $a0, $a1, L1
add $s0, $a0, $a1
L1: jal test
add $s0, $v0, $0
li $v0,10
syscall
test:
addi $sp, $sp, -4
sw $ra, 0($sp)
slt $s1,$a1,$a0
bne $s1, 1, ELSE
jal multiply
ELSE: jal subtract
lw $ra, 0($sp)
addi $sp, $sp, 8
jr $ra
subtract:
sub $s0, $a0, $a1
jr $ra
multiply:
mult $a0, $a1
mflo $s0
jr $ra
The problem is, that after you return from multiply, you still call subtract in the next line. You have to return from the function test after calling multiply.
However, since the function calls are both the last instruction of your function, you can use the following shortcut:
test:
slt $s1,$a1,$a0
bne $s1, 1, ELSE
j multiply
ELSE: j subtract
This way, you do not have to store the $ra in your stack, but you can directly use it to jump back to the caller of test in the jr $ra of subtract and multiply. This way it should work as intended.
Alternatively, skip over jal subtract after returning from multiply:
jal multiply
j OUT
ELSE: jal subtract
OUT: ...

Jump to Address after Branching in For Loop in MIPS

I am trying to code a program that checks if the 16 bits in an integer is a one or zero. I chose to implement this by shifting right one bit 15 times and checking if the first bit in each shift is a zero or non zero. Then, if the first bit is a 1, I increment an integer.
I made some code in C that represents a non-user input version of my code.
int j = 100;
int checker = 0;
int count = 0;
for (i=0; i<16; i++) {
checker = j & 0x1;
if (checker > 0)
count++;
j = (j >> 1);
}
My code in MIPS:
.data
userprompt: .asciiz "Enter positive integer: "
newline: .asciiz "\n"
.text
.globl main
main:
li $v0, 4 # System call: Display string
la $a0, userprompt # Load string userprompt for output
syscall
li $v0, 5 # System call: Read integer
syscall
move $s0, $v0 # Store integer from v0 to s0
move $s1, $s0 # s1 = s0
li $t0, 0 # t0 = 0
jal chk_zeros # Run function: chk_zeroes
li $v0, 1 # System call: Read integer
move $a0, $t2 # Store integer from t2 to a0
syscall
li $v0, 10 # System call: quit
syscall
chk_zeros:
bgt $t0, 15, exitchk # t0 <= 15
addi $t0, $t0, 1 # Add one to t0
andi $t1, $s1, 0x1 # Check if first bit is non-zero, store in t1
bgtz $t1, chk_zerosadd # If t1 >= 0
j chk_zeros
chk_zerosadd:
addi $t2, $t2, 1 # Add one to t2
jr $ra # Return to after the if statement (does not work!)
exitchk:
jr $ra
What I am having trouble with is making chk_zerosadd return to after the branching statement. jr $ra seems to return me to my main function in chk_zerosadd.
bgtz doesn't place the next PC address into the return address register, so jr $ra won't return to the instruction after the branching statement. You can either use bgtzal (branch if greater than zero and link), which will give you the behaviour you are looking for, or else you can re-arrange your code so that you branch over the add, instead of branching to it, like this:
andi $t1, $s1, 0x1 # Check if first bit is non-zero, store in t1
beq $t1, chk_zerosskipadd # Jump if $t1 is zerp
addi $t2, $t2, 1 # Add one to t2
chk_zerosskipadd:
# continue execution...
srl $s1, $s1, 1 # j = (j >> 1);
j chk_zeros

MIPS recursion call in loop, preserving loop variable

I'm converting the following recursive java program to MIPS asm. The algorithm computes all the possible ordering/permutations of the numbers. But the recursive call is in the for loop. I need to preserve the variable 'i' in my MIPS version but I don't know exactly where to add that. My algorithm is correct, it's just that my $t0 (which is 'i') never gets reset to 0. I just can't figure out how/where to preserve it on the stack or when to take it off the stack. Any help appreciated.
import java.util.Arrays;
public class Test
{
private static void swap(int[] v, int i, int j)
{
int t = v[i];
v[i] = v[j];
v[j] = t;
}
public void permute(int[] v, int n)
{
if (n == 1)
System.out.println(Arrays.toString(v));
else
{
for (int i = 0; i < n; i++)
{
permute(v, n-1);
if (n % 2 == 1)
swap(v, 0, n-1);
else
swap(v, i, n-1);
}
}
}
public static void main(String[] args)
{
int[] ns = {1, 2, 3, 4};
new Test().permute(ns, ns.length);
}
}
and the mips function
Note: I am permutating Strings, not integers but the algorithm is the same.
#----------------------------------------------
# anagram - Prints all the permutations of
# the given word
# a0 - the word to compute the anagrams
# s0 - n, the length of the word
# a1 - n - 1 (length-1)
#----------------------------------------------
anagram:
addi $sp, $sp, -16
sw $a0, 0($sp)
sw $a1, 4($sp)
sw $s0, 8($sp)
sw $ra, 12($sp)
add $s0, $a1, $zero # this is n
addi $a1, $s0, -1 # n-1
beq $s0, 1, printS
init: move $t0, $zero # t0 = i = 0
logic: slt $t1, $t0, $s0 # Set t1 = 1 if t0 < length
beqz $t1, endAnagram # if it's zero, it's the end of the loop
jal anagram
li $t2, 2
div $s0, $t2
mfhi $t3
beqz $t3, even # if even branch to even, otherwise it will go to odd
odd: # swap the n-1 char with the first
add $t4, $a0, $zero
add $t5, $a0, $a1
lb $t6, 0($t4) # first char
lb $t7, 0($t5) # n-1 char
sb $t7, 0($t4) # swap the two
sb $t6, 0($t5)
j inc # skip the even section
even: # swap the ith char with n-1 char
add $t4, $a0, $t0 # ith char
add $t5, $a0, $a1 # n-1 char
lb $t6, 0($t4) # ith char
lb $t7, 0($t5) # n-1 char
sb $t7, 0($t4) # swap the two
sb $t6, 0($t5)
inc: addi $t0, $t0, 1 # t0++;
j logic
endAnagram:
# reset stack pointers
lw $a0, 0($sp)
lw $a1, 4($sp)
lw $s0, 8($sp)
lw $ra, 12($sp)
addi $sp, $sp, 16 # adjust stack
jr $ra
printS: # print string and jump to return
jal printString # calls printString function which prints the string
j endAnagram
$t0 is not preserved accross subroutine calls according to convention, and you seem to follow that convention. As such, you have two choices:
you either store i in a register that is preserved, in which case
you need to preserve the register yourself in the prologue/epilogue. You already do this for $s0.
or you save $t0 yourself on the stack, around the subroutine call
In both cases, you will need additional space for your locals, so change addi $sp, $sp, -16 to addi $sp, $sp, -20 (along with the matching code in the epilogue too). If you choose option #1, use for example $s1 to store i. Add code to save and restore $s1 just like you do for $s0. If you choose option #2, add code around the jal anagram that writes $t0 to stack before the jal, and reloads it after.

Resources