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.
Related
.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
I'm new on this site and in mips.I am trying to make the sum of the squares of a number without it, for example, f(4) = 9 + 4 + 1 = 14. This is a part of my code, the recursive function exactly.
RecursiveFunction:
subu $sp, $sp, 8
sw $ra, ($sp)
sw $s0, 4($sp)
li $v0, 1
beq $a0, 0, Done
move $s0 $a0
sub $a0, $a0, 1
jal RecursiveFunction
move $t0, $v0
sub $t0, $t0, 1
mul $v0, $t0, $t0
add $v0, $s0, $v0
Done:
lw $ra, ($sp)
lw $s0, 4($sp)
addu $sp, $sp, 8
jr $ra
Can u help me guys? I try to solve it for 3 days.
It always helps to have high-level pseudocode before attempting to translate it to MIPS.
In this case, the pseudocode that you are looking for is -
RecursiveFunction(n): // return 1*1 + 2*2 + .. + n*n
if n == 0 return 0
else return n*n + RecursiveFunction(n-1)
To compute RecursiveFunction(4), simply call RecursiveFunction(3). The task remains to translate this to MIPS. The key idea is using the MIPS stack ($sp) to 'remember' return address ($ra) and 'interim' values (n*n) in this case.
Following is the MIPS code with comments describing what each line does:
.text
li $a0, 3
jal RecursiveFunction # compute RecursiveFunction(3)
move $a0, $v0
li $v0, 1
syscall # and print the result
exit:
li $v0, 10
syscall
# input : $a0 = n
# output: $v0 = 1*1 + 2*2 + .. + n*n
RecursiveFunction:
addi $sp, $sp, -4 # create space on stack
sw $ra, 0($sp) # and remember the return address ($ra)
beqz $a0, return0 # if n == 0 goto return0
mul $s0, $a0, $a0 # else, $s0 = n*n
addi $sp, $sp, -4 # create space on stack
sw $s0, 0($sp) # and save n*n on it
addi $a0, $a0, -1
jal RecursiveFunction # compute $v0 = RecursiveFunction(n-1)
lw $s0, 0($sp) # $s0 = restore n*n from stack
addi $sp, $sp, 4 # and reset the stack
add $v0, $v0, $s0 # $v0 += n*n (it earlier had RecursiveFunction(n-1))
j exitFn # and jump to exitFn
return0: # base case (n = 0)
move $v0, $zero # $v0 = 0 (the return value)
j exitFn # and jump to exitFn
exitFn:
lw $ra, 0($sp) # at exit, restore the return address in $ra
addi $sp, $sp, 4 # restore stack
jr $ra # and jump to caller
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.
I trying to write a MIPS program that gets an unsigned integer as argument and returns the sum of all decimal digits in the integer recursively. For example if the argument is 75080 then the sum to be returned is 20 (7+5+0+8+0). Here is my code so far. Any help would be appreciated.
My way of thinking was to divide the number by 10 leaving me with the last integer in the number, add the reminder using mfhi.
.data
prompt: .asciiz "Enter a string of integer: "
output: .asciiz "\nThe total sum is: "
.text
.globl main
main:
la $a0, prompt
li $v0, 4
syscall
li $v0, 5
syscall
move $t2, $v0
la $a0, output
li $v0, 4
syscall
Loop:
div $t2, $t2, 10
mflo, $t1
mfhi, $t3
beqz $t1, Exit
add $t1, $t1, 0
b additive
additive:
add $t0, $t1, $t1
j Loop
Exit:
la $a0, output
li $v0, 4
syscall
la $v0, 10
syscall
What's this supposed to be doing? Adding 0 to the register won't change its value:
add $t1, $t1, 0
After dividing and copying to $t1 and $t3, the quotient is in $t1 and the remainder is in $t3. You're treating it the other way around when you add to the total.
This is actually going to give you $t0 = 2 * $t1: you're adding $t1 to itself and storing the result in $t0.
add $t0, $t1, $t1
You probably actually want:
add $t0, $t0, $t3
You're checking for $t1 == 0 before adding the remainder to the total, so the most significant digit will never get added. You don't really need a subroutine for adding to the total either. You can also use bnez Loop instead of beqz Exit -> b Loop. Lastly, you don't even need $t1, because the quotient is already in $t2.
Get rid of additive and replace Loop with this:
Loop:
div $t2, $t2, 10
mfhi, $t3
add $t0, $t0, $t3
bnez $t2, Loop
Your Exit is weird: you're printing the output string a second time instead of printing the integer.
Change it to this:
Exit:
move $a0, $t0
la $v0, 1
syscall
la $v0, 10
syscall
The approach is quite simple. You need recursive function, I named it SumDigits that will take the last digit and repeat procedure for all digits in the argument. After the recursive call returns you'll add digit to the previous result. The code is commented for easier understanding. The code follows:
.text
#calculates sum of digits recursively
SumDigits:
sub $sp, $sp, 12 #alloocate 12B on stack
sw $ra 0($sp) #save return address
sw $a0, 4($sp) #save argument
beq $a0, $0, exit_sumdigits #when there is no more digits return 0
rem $t0, $a0, 10 #get last digit
sw $t0, 8($sp) #save it on stack
div $a0, $a0, 10 #divide argument by 10
jal SumDigits #repeat procedure
lw $t0, 8($sp) #read digit from stack
add $v0, $v0, $t0 #add digit to previous result
lw $ra, 0($sp) #load return address
addi $sp, $sp, 12 #free stack
jr $ra #return
exit_sumdigits:
li $v0, 0 #there are no more digits, return 0
lw $ra, 0($sp) #load return address
addi $sp, $sp, 12 #free stack
jr $ra #return
main:
li $a0, 75080 #load number in $a0
jal SumDigits #call SumDigits
move $a0, $v0 #set a0 = result of SumDigits
li $v0, 1 #set $v0 for print int system call
syscall
li $v0, 10 #set $v0 for exit system call
syscall
.data
For a homework assignment in school, I need to use a MMIO LED display where each led is exactly 2 bits stored within a byte. For the assignment I need to "move" these LEDs up, down, left, and right. I also need to set the color (I will be using 0x40 for this). Here's my issue:
When I click the "right" arrow to move the LED over 1 column, it remains in the current column when it should be returning to black (0x00). If I click right 4 times (moving over exactly 1 byte), I get another lit LED, leaving the original one there.
Here is my MIPS code:
getLedPattern:
move $t2, $s2
andi $t1, $t2, 0x3 #remainder of x / 4 is in $t0
sll $t0, $t2, 2 #x / 4 is in $t0
beq $t0, 0, case0
beq $t0, 1, case1
beq $t0, 2, case2
case3:
andi $a0, 0xFFFFFFFC
#insert $a1 into bits 0 and 1 of $a0 into $v0
or $v0, $a0, $a1
jr $ra
case2:
andi $a0, 0xFFFFFCFF
#insert $a1 into bits 2 and 3 of $a0 into $v0
#srl $a1, $a1, 2
or $v0, $a0, $a1
jr $ra
case1:
andi $a0, 0xFFFCFFFF
#insert $a1 into bits 4 and 5 of $a0 into $v0
#srl $a1, $a1, 4
or $v0, $a0, $a1
jr $ra
case0:
andi $a0, 0xFCFFFFFF
#insert $a1 into bits 6 and 7 of $a0 into $v0
#srl $a1, $a1, 6
or $v0, $a0, $a1
jr $ra
setLED:
addi $sp, $sp, -20
sw $ra, 0($sp)
sw $t0, 4($sp)
sw $t1, 8($sp)
sw $t2, 12($sp)
sw $t3, 16($sp)
move $t5, $a0
sll $t6, $a1, 5 # y*32
srl $t2, $a2, 2 # x/4
add $t5, $t5, $t6
add $t5, $t5, $t2
lb $a0, 0($t5)
move $a1, $a3
jal getLedPattern
sb $v0, 0($t5)
move $s3, $t5
lw $ra, 0($sp)
lw $t0, 4($sp)
lw $t1, 8($sp)
lw $t2, 12($sp)
lw $t3, 16($sp)
addi $sp, $sp, 20
jr $ra
The logic is that it starts out at at memory location 0xFFFFOOO8 (top left LED), moves down one row (+32 bytes) and over x columns (plus x*bits). However, I can't seem to unset the current LED and move it over one. Any help would be appreciated. I believe that my or in getLedPattern: is wrong, but not 100% sure.
Hopefully, getting this correct I will be able to get this correct in a general sense (no LED display).
I guess that your constants for clearing bits are wrong.
try the following instead:
0xfffffffc // or ~0x03
0xfffffff3 // or ~0x0C
0xffffffcf // or ~0x30
0xffffff3f // or ~0xC0
There are other oddity in your code:
s2 is used, but never set
s3 is set, but never used
case1 and case2 will never be reached because $t0 can hold nor 1 neither 2