MIPS Recursion Errors - mips

Can anybody tell me what is wrong with my recursion code below. It is supposed to be a recursive function of a decimal to binary function. I just can not see what is wrong. I am new to MIPS so I do not fully understand everything but from my understanding this is what I got.
I hardcoded a number in and I am supposed to get the output 101000 but it would not load anything beyond the message.
.data
msg1:.asciiz "Output (40) = "
.text
.globl main
la $a0,msg1 # load string as parameter
li $v0, 4 # load operation "print string"
syscall # request "print string" for msg1
addi $t0, $zero, 40
move $a0, $t0
li $t2, 2
jal d2b
add $a0, $v0, $zero # load the value of $v0 into $a0
li $v0, 1 # load operation "print integer"
syscall # request "print integer"
d2b: li $t1, 0 # t1 = 0
bgt $a0, $t1, skip # if a0 > t1 no
li $v0, 0 # load v0 as 0
jr $ra # print this shit out
skip: subu $sp, $sp, 32 # sp down 32
sw $ra 20($sp) # save $ra
sw $fp, 16($sp) # save $fp
addiu $fp, $sp, 28 # set up $ fp
sw $a0, 0($fp) # save n
divu $a0, $t2 # divide n / 2
mflo $t3 # quota
mfhi $t4 # rem
move $a1, $t4 # rem keep
move $a2, $t3 # quota keep
addi $a1, 10 # adding rem + 10
jal d2b # call recursive —> d2b(n/2)
lw $a0, 0($fp) # restore n
multu $v0, $a2 # rem+10 *d2b(n/2)
lw $ra, 20($sp) # load $ra
lw $fp, 16($sp) # load $fp
addiu $sp, $sp, 32 # pop stack
jr $ra # return

Related

Assembly MIPS: Cannot debug floating-point power function

I have been trying to implement a floating-point function in Assembly MIPS 32-bits, and I have not been able to pinpoint the exact fault. It seems to be in the mul.s $fd, $fsrc1, $fsrc2 command, since the contents of the specific floating-point register remain unchanged (I have checked this with syscalls as well, printing the contents in each case) but I seem to be unable to find the fix. Anyone got any ideas? Full code below:
.align 2
.data
number: .float 0.5
.text
.globl main
main:
li $a0, 3
l.s $f12, number
jal power
li $v0, 2
mtc1 $a0, $f0
syscall
li $v0, 17
syscall
power:
#Build stack
subu $sp,$sp,56 # Stack frame is 56 bytes long
sw $a0, 12($sp) # Save Argument 0 ($a0)
swc1 $f12, 8($sp) # Save Argument 1 ($a1) (integer arg)
sw $s0, 56($sp) # Save $s0
sw $s1, 52($sp) # Save $s1
swc1 $f20, 48($sp) # Save $f20
swc1 $f21, 44($sp) # Save $f21
sw $ra, 16($sp) # Save return address
sw $fp, 20($sp) # Save frame pointer
addiu $fp, $sp, 52
#-----------------------------------------------------------------------#
move $s0, $a0 #stores value of n
mov.s $f22, $f12 #stores value of x
li $s1, 0 #initialize counter with 0
powerLoop:
mul.s $f20, $f20, $f20 #y=y*y
addi $s1, $s1, 1 #increase counter
bgtu $s0, $s1, powerLoop #continue loop as long as counter<n
mov.s $f0, $f20 #return the results
#-----------------------------------------------------------------------#
#Pop stack
lw $a0, 12($sp) #Load back $a0
lwc1 $f12, 8($sp) #Load back $f12
lw $s0, 56($sp) # Load $s0
lw $s1, 52($sp) # Load $s1
lwc1 $f20, 48($sp) # Load $f20
lwc1 $f21, 44($sp) # Load $f21
lw $ra, 16($sp) # Restore old value of $ra
lw $fp, 20($sp) # Restore old value of $fp
addiu $sp, $sp, 56 # Pop stack
jr $ra
SOLVED:
Despite some errors in registers, the main error is in the
li $v0, 2
mtc1 $a0, $f0
syscall
FIX:
li $v0, 2
mov.s $f12, $f0
syscall
REASON: $f12 IS ALWAYS, due to convention, the floating-point argument, even for syscalls. It will not print the contents of $a0 but rather $f12!

MIPS Stack Segment can't be Expanded

I'm writing a function that should return the square root of a perfect square recursively as part of a longer assignment.
I was following this mathematical method before I reverted to an even simpler algorithm to see if the error would repeat itself and it did.
The following code:
.data
prompt: .asciiz "num2sqrt: "
.text
.globl main
sqrt:
# save return address & t0
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $t0, 4($sp)
# t0 = n
move $t0, $a0
# a0 = n/2
srl $a0, $t0, 1
jal sqrtRecursor
#restore return address & t0
lw $t0, 4 ($sp)
lw $ra, 0 ($sp)
addi $sp, $sp, 8
jr $ra
sqrtRecursor:
# save return address & t1
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $t1, 4($sp)
# square test
mult $a0, $a0
mflo $t1
beq $t1, $t0, returnAnswer
bne $t1, $t0, newGuess
#restore return address & t1
lw $t1, 4 ($sp)
lw $ra, 0 ($sp)
addi $sp, $sp, 8
jr $ra
returnAnswer:
move $v0, $a0
newGuess:
# t1 = (((x+1)*guess)/x)/2
# x+1
addi $t1, $t0, 1
# *guess
mult $a0, $t1
mflo $t1
# /x
div $t1, $t0
mflo $t1
# /2
srl $t1, $t1, 1
move $a0, $t1
jal sqrtRecursor
main:
#print "Enter num2sqrt: "
la $a0, prompt
li $v0, 4
syscall
#input num2sqrt
li $v0, 5
syscall
move $s1, $v0
move $a0, $s1
jal sqrt
# print result
move $a0, $v0
li $v0, 1
syscall
# end
li $v0, 10
syscall
returns the following error on QTSpim:
Can't expand stack segment by 12 bytes to 524288 bytes. Use -lstack # with # > 524288
which then hangs the app for a minute or so.
I've double checked that I'm saving and returning all my return addresses and used variables, and also attempted implementing the same algorithm in Java separately (which worked), but have yet been unable to figure out what I need to fix and where.
I've been able to implement a power function before this so I'm not a complete novice and am asking after putting in approximately 5 hours of research and debugging on this.
It could be a stack management problem or an if/else implementation error from the intuition I have about my own code.

I keep getting 0 as an answer for my mips code where I'm supposed to find the gcd of two numbers

.data
n1:.asciiz"Enter the first number:"
n2: .asciiz"Enter the second number:"
.text
.globl main
main:
li $v0,4
la $a0,n1
syscall
li $v0, 5 # get input from user
syscall
move $a0,$s0
li $v0,4
la $a0,n2
syscall
li $v0, 5 # get second input from user
syscall
move $a0,$s1
jal calcGCD # call function calcGCD
add $a0,$v0,$zero
li $v0,1
syscall # print result
li $v0, 10 # exit program
syscall
calcGCD:
#GCD(n1, n2)
# n1 = $a0
# n2 = $a1
addi $sp, $sp, -12
sw $ra, 0($sp) # save function into stack
sw $s0, 4($sp) # save value $s0 into stack
sw $s1, 8($sp) # save value $s1 into stack
add $s0, $a0, $zero # s0 = a0 ( value n1 )
add $s1, $a1, $zero # s1 = a1 ( value n2 )
addi $t1, $zero, 0 # $t1 = 0
beq $s1, $t1, return # if s1 == 0 return
add $a0, $zero, $s1 # make a0 = $s1
div $s0, $s1 # n1/n2
mfhi $a1 # reminder of n1/n2 which is equal to n1%n2
jal calcGCD
exitGCD:
lw $ra, 0 ($sp) # read registers from stack
lw $s0, 4 ($sp)
lw $s1, 8 ($sp)
addi $sp,$sp , 12 # bring back stack pointer
jr $ra
return:
add $v0, $zero, $s0 # return $v0 = $s0 ( n1)
j exitGCD
The main issue with your code is with the part where you store the user input in the registers. In move $a0,$s0, you are moving the value at $s0 into $a0 when the user input is stored in $v0, therefore, it should be move $a0,$v0, and from your function, you seem to have stored the second input in $a1 but in your code, both the inputs are being stored in the same register so the next command should be move $a1,$v0. Here is one version of your code.
.data
n1:.asciiz"Enter the first number:"
n2: .asciiz"Enter the second number:"
.text
.globl main
main:
li $v0,4
la $a0,n1
syscall
li $v0, 5 # get input from user
syscall
move $t0,$v0 #temporarily store the user input in another register because $a0 is having another value stored in it in the next command
li $v0,4
la $a0,n2
syscall
li $v0, 5 # get second input from user
syscall
move $a1,$v0
move $a0,$t0 #transfer the first user input into $a0 to be used in the function
jal calcGCD # call function calcGCD
add $a0,$v0,$zero
li $v0,1
syscall # print result
li $v0, 10 # exit program
syscall
calcGCD:
#GCD(n1, n2)
# n1 = $a0
# n2 = $a1
addi $sp, $sp, -12
sw $ra, 0($sp) # save function into stack
sw $s0, 4($sp) # save value $s0 into stack
sw $s1, 8($sp) # save value $s1 into stack
add $s0, $a0, $zero # s0 = a0 ( value n1 )
add $s1, $a1, $zero # s1 = a1 ( value n2 )
addi $t1, $zero, 0 # $t1 = 0
beq $s1, $t1, return # if s1 == 0 return
add $a0, $zero, $s1 # make a0 = $s1
div $s0, $s1 # n1/n2
mfhi $a1 # reminder of n1/n2 which is equal to n1%n2
jal calcGCD
exitGCD:
lw $ra, 0 ($sp) # read registers from stack
lw $s0, 4 ($sp)
lw $s1, 8 ($sp)
addi $sp,$sp , 12 # bring back stack pointer
jr $ra
return:
add $v0, $zero, $s0 # return $v0 = $s0 ( n1)
j exitGCD

My assembler code has this error: "invalid program counter value: 0x00000000 Go: execution terminated with errors"

.data
prompt2: .asciiz "please enter the elements one by one:"
prompt3: .asciiz "the array is ordered as follows: "
prompt4: .asciiz "-- Program is finished running --"
str1: .asciiz ","
newLine: .asciiz "\n"
.text
addi $sp,$sp,-24
sw $ra,0($sp)
sw $s4,4($sp)
sw $a2,8($sp)
sw $s3,12($sp)
sw $s0,16($sp)
sw $s2,20($sp)
main:
# read n from console
li $v0 5
syscall
move $a2 $v0 #tagghiir t0 be a2 (n)
# allocate dynamic memory
sll $a0 $v0 2 # sll performs $a0 = $v0 x 2^2
li $v0 9 #9 is the system code for service(sbrk) whoes work is
syscall #to allocate dynamic memory
move $a1 $v0 #t2 saved address of heap #taghiir t2 to a1
#saved for printing
li $v0, 4 # $system call code for print_str
la $a0, prompt2 # $address of string to print
syscall
move $t1 $zero
move $t4,$a1
inputLoop:
bge $t1 $a2 exit1
# read in and store int
li $v0 5
syscall
sw $v0 0($t4)
addi $t1 $t1 1
addi $t4 $t4 4
li $v0, 4 # $system call code for print_str
la $a0, newLine # $address of string to print
syscall
j inputLoop
exit1:
jal sort
li $v0, 4 # $system call code for print_str
la $a0, prompt3 # $address of string to print
syscall
move $t3,$zero
move $t4 ,$a1
outputLoop:
bge $t3 $a2 exit2
#inaro azoon yki copy krdm
lw $t6, 0($t4)
li $v0, 1
move $a0, $t6
syscall
# read in and store int
addi $t3 $t3 1
addi $t4 $t4 4
blt $t4,$a1 ,comma
# bne $t5,$zero,comma
comma:
li $v0, 4 # $system call code for print_str
la $a0, str1 # $address of string to print
syscall
j outputLoop
exit2:
li $v0, 10
syscall #for finishing the program
swap:
move $a3,$a3
move $a1,$s4
# move $t5,$zero # its for our temp variable in c code
move $t4 ,$a1 #t4 is now the base address of heap
sll $t6 , $a3,2 # s1 is the given k
add $t6,$t4,$t6 # heap address + k*4
lw $t3,0($t6) #khoone k e heap
lw $t5,4($t6) #khoone k+1 heap
sw $t5,0($t6)
sw $t3,4($t6)
jr $ra
sort:
# move $s0,$zero #i=t0
move $s4,$a1 #base address of heap
addi $t5,$a2,-1 # meghdare i
move $s2,$zero #its the flag
while:
addi $s2,$s2,1
move $a3,$zero #j #taghiir s1 be a3 (haman j va k
forLoop:
bge $a3,$t5,outOfLoop
sll $t6,$a3,2 #j
add $t1,$t6,$a1 #v+j
lw $t7,0($t1) #t7=heap[j]
lw $t8,4($t1) #t8=heap[j+1]
blt $t7,$t8,outOfIf
move $s4,$a1
move $s3,$a3
jal swap
addi $s2,$s2,-1
outOfIf:
addi $a3,$a3,1 #j++
outOfLoop:
addi $t5,$t5-1 #i--
bgt $s2,$zero,exit_outter #if a>=b break
ble $t5,$zero,exit_outter #if b=< c break
j while
exit_outter:
lw $ra,0($sp)
lw $s4,4($sp)
lw $a2,8($sp)
lw $s3,12($sp)
lw $s0,16($sp)
lw $s2,20($sp)
addi $sp,$sp,24
jr $ra
Where am I going wrong?

A nested function in MIPS

My code has two parts; the first part is making a function that takes in two numbers and return their products. I believe I did this part right.
The second part is where I'm not sure what's the problem is. In this part I need to make a function that find the factorial number, and within this function, I have to use the multiplication function which I made in the first part. Please have a look at my code and tell me what am I doing wrong.
.data
Fa_message: .asciiz "\nFAIL TEST\n"
Pa_message: .asciiz "\nPASS TEST\n"
number1: .word 4
number2: .word 5
KnownAnswers: .word 20
START: .word 16
.text
main:
# taking in the numbers for calculation.
lw $a0, number1 # $a0 =4
lw $a1, number2 # $a1 =5
lw $t0, KnownAnswers # $t0 =20
jal func_multiply # calling the mulyiply function
move $t4,$v0 # store the product for any further comparisons
bne $t0, $t4, FailT # did it fail the test?
beq $t0, $t4, PassT # did it pass the test?
func_multiply: # the mulyiply function
mul $v0, $a0, $a1 # $v0 = number1 * number2
jr $ra
FailT: # print "\nFAIL TEST\n"
li $v0,4
la $a0, Fa_message
syscall
PassT: # print "\nPASS TEST\n"
li $v0,4
la $a0, Pa_message
syscall
###---------------------(PART-2)-------------------
lw $a0, number1 # load the number for the factorial procedure
beq $a0, $zero, factorialDone # (if the number = 0), !0 = 1
mul $a1, $a1, $zero # initializing $a1
mul $a2, $a1, $zero # initializing $a2
addi $a1, $a0, -1 # $a1 = (the entered number - 1)
addi $a2, $a0, 0 # $a2 = the entered number
jal findfactorial
###
#Stop
li $v0, 10
syscall
findfactorial:
jal func_multiply # calling the mulyiply function # mul $v0, $a0, $a1 # $v0 = number1 * number2
move $t4,$v0 # store the product in t4 for any further usage
addi $a0, $a0, -1 # $a1 = $a1-1
addi $a1, $a0, -1
bne $a1, $zero, findfactorial # enter a loop if $a1 does not equal 0
jr $ra
factorialDone:
addi $v0, $v0, 1
syscall
The jal instruction modifies the $ra register. So if function A calls a function B, then A has to save and restore the value that $ra had when entering A so that it can return to the correct place. This is typically done using the stack as temporary storage.
You can push a register on the stack (save it) like this:
addi $sp, $sp, -4
sw $ra, ($sp)
And pop a register off the stack (restore it) like this:
lw $ra, ($sp)
addi $sp, $sp, 4
Then there's your findfactorial loop. You're discarding the result of all the previous iterations, so your result will always be 1*2 == 2. The loop ought to look something like this:
findfactorial:
jal func_multiply
move $a0,$v0
addi $a1, $a1, -1
bne $a1, $zero, findfactorial
This way you first multiply 4 by 3, then 12 by 2, etc.
There are some other isues in your code. For example, if you jump to FailT you don't immediately exit the program after printing the message - you just keep executing the code after PassT.
Also I'm not sure what this is supposed to do:
factorialDone:
addi $v0, $v0, 1
syscall
If you wanted to execute syscall 1 (print_int), then this is incorrect because it doesn't set up $v0 properly (it should be li $v0,1). And if you wanted this to print the result of your factorial computation then that's not going to happen, because you have a jr $ra right before that, so the only time you end up at factorialDone is if number1 contained 0. Also, you'd have to set up $a0 with the value you want to print.