I am currently writing c program that can translate my own language grammar into mips code.
int i;
int b;
int add() {
if (i < 10) {
i = i + 1;
return add();
}
return i;
}
i = 0;
b = add();
But my issue is in mips where I am running into memory address issues on how to properly handle recursion functions.
I know my C code isn't optimizing mips but please ignore that.
How can I fix this small mips program so I can handle other types of recursive functions.
.text
.globl main
main:
li $t0, 0
sw $t0, i
subu $sp, $sp, 0
jal add
addu $sp, $sp, 0
move $t0, $v1
sw $t0, b
li $v0, 10
syscall
add:
subu $sp, $sp, 4
sw $ra, ($sp)
lw $t0, i
li $t1, 10
slt $t2, $t0, $t1
beq $t2, 0, L1
lw $t0, i
li $t1, 1
add $t3, $t0, $t1
sw $t3, i
subu $sp, $sp, 4
sw $t2, 4($sp)
jal add
lw $t2, 4($sp)
addu $sp, $sp, 4
move $t0, $v1
move $v1, $t0
L1:
lw $t0, i
move $v1, $t0
lw $ra, ($sp)
addu $sp, $sp, 4
jr $ra
.data
.align 4
i: .word 0
b: .word 0
Any suggestions or answers would be much appreciated!
Related
I am trying to pratice how recursion works in Mips. So I tried to write a fibonacci function fib.
At first I had addi $a0, $a0, n to write a general solution, but I thought that if I want to check my results in Qtspim , maybe i need to add a real number as an argument. I do not want a full answer , if the thought behind the code is wrong, but some help in order to run it in Qtspim, and find my mistakes (logic mistakes) on my own
This is my code:
.globl main
.text
main:
addi $a0, $a0, 4
fib:
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $a0, 0($sp)
slti $t0, $a0, 1
beq $t0, 1, L2 #if n<1
beq $a0, 1, L2 # if n=1
beq $t0, 0, L1 # if n>1
#what to do when n<=1
L2:
addi $v0, $v0, 1
jr $ra
#what to do when n>1
L1:
addi $a0, $a0, -1
jal fib
lw $a0, 0($sp)
lw $ra, 4($sp)
addi $sp, $sp, 8
lw $t1, 0($v0)
add $v0, $t1, $v0
jr $ra
li $v0,10
syscall
I get an error message as such:
Bad address in data/stack read: 0x00000000
.text
main:
addi $a0, $a0, 4
#### you've place fib inline inside main,
#### you should have all of main here, and "call" fib using jal instruction
#### and the syscall for exit goes up here as well
fib:
addi $sp, $sp, -8 # you will want one more word of stack space
sw $ra, 4($sp)
sw $a0, 0($sp)
slti $t0, $a0, 1 # i would have use 2 here instead of 1
beq $t0, 1, L2 #if n<1 # this is ok, but better to use bne $t0, $0, L2
beq $a0, 1, L2 # if n=1 # and then this would not be needed
beq $t0, 0, L1 # if n>1 # this doesn't need to be conditional, if the program reaches here then L1 is the thing to do next.
#what to do when n<=1
L2:
addi $v0, $v0, 1 # here you want to return just 1 not v0+1
jr $ra
#what to do when n>1
L1:
addi $a0, $a0, -1
jal fib # fib(n-1), good
lw $a0, 0($sp) # this reloads $a0 the original n
lw $ra, 4($sp)
addi $sp, $sp, 8
lw $t1, 0($v0) # after a call to fib $v0 holds fib(n)
# an integer value but you're treating it like a pointer and dereferencing it
add $v0, $t1, $v0 # here doing fib(n-1) + n
# you want fib(n-1) + fib(n-2) instead
# so you're missing a fib(n-2)
jr $ra
li $v0,10 # this is part of main, so move it to where main is
syscall # realize that code located here is unreachable (aka dead)
# anything after an unconditional branch (here the jr $ra just above)
# and without a label is very suspicious as unreachable
update , some improved (i hope ) code
.globl main
.text
main:
addi $a0, $a0, 4
jal fib
li $v0, 10
syscall
fib:
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $a0, 0($sp)
slti $t0, $a0, 2
beq $t0, 1, L2
#what to do when n<=1
L2:
addi $v0, $v0, 1
jr $ra
#what to do when n>1
L1:
addi $a0, $a0, -1 # a0 -> n-1
jal fib # fib(n-1)
lw $a0, 0($sp) #load word from memory adress 0($sp) to register $a0
lw $ra, 4($sp) #load word from memory adress 4($sp) to register $ra
addi $sp, $sp, 8
add $t1, $zero, $v1 # in register $t1 store current $v1
add $v0, $t2, $v0 # v0_ n+1 =v0 _n + v0_n-1
add $t2, $t1, $zero # in $t2 save the previous value of v1
.data
prompt: .ascii "Fibonacci Program\n"
.asciiz "Enter N value: "
results: .asciiz "\nFibonacci of N = "
n: .word 0
answer: .word 0
.text
.globl main
.ent main
main:
# Read n value from user
li $v0, 4 # print prompt string
la $a0, prompt
syscall
li $v0, 5 # read N (as integer)
syscall
sw $v0, n
# Call Fibonacci function.
lw $a0, n
jal fib
sw $v0, answer
# Display result
li $v0, 4 # print prompt string
la $a0, results
syscall
li $v0, 1 # print integer
lw $a0, answer
syscall
# Done, terminate program.
li $v0, 10 # terminate
syscall # system call
.end main
# Fibonacci function
# Recursive definition:
# = 0 if n = 0
# = 1 if n = 1
# = fib(n-1) + fib(n-2) if n > 2
# Arguments
# $a0 - n
# Returns
# $v0 set to fib(n)
.globl fib
.ent fib
fib:
subu $sp, $sp, 8
sw $ra, ($sp)
sw $s0, 4($sp)
move $v0, $a0 # check for base cases
ble $a0, 1, fibDone
move $s0, $a0 # get fib(n-1)
sub $a0, $a0, 1
jal fib
move $a0, $s0
sub $a0, $a0, 2 # set n-2
move $s0, $v0 # save fib(n-1)
jal fib # get fib(n-2)
add $v0, $s0, $v0 # fib(n-1)+fib(n-2)
fibDone:
lw $ra, ($sp)
lw $s0, 4($sp)
addu $sp, $sp, 8
jr $ra
.end fib
I am trying to code a Assembly program that will ask for an integer and perform a recursive function: if n>5 f(n) = n*f(n-1)-f(n-3)+n-23 else n<=5 f(n)=15-2n I managed to get the first instance of recursion of the n*f(n-1)but when it goes for the second recursion of f(n-3) it performs the second portion improperly.
During the calculations, if I input 8 as the integer, the result should be 20 which I get but, when I input anything greater than 8 because then the second recursion hits an integer larger than 5 (the base case) I get an incorrect answer. Basically any input larger than 8 doesn't work
For example the correct answers are:
f(9) = 162
f(10) = 1602
f(11) = 17590
The answers I get
f(9)= 27
f(10)=22
f(11)=23
Here is my code:
```#data declarations: declare variable names used in program, storage allocated in RAM
.data
prompt1: .asciiz "\nEnter an Integer:\n" #Ending Index
message1: .asciiz "\nThe Solution is:\n"
answer: .word 0
#program code is contained below under .text
.text
.globl main #define a global function main
# the program begins execution at main()
main:
la $a0, prompt1 #load address of prompt1
li $v0, 4 #prepare print string
syscall
li $v0, 5 #prepare receive int
syscall
move $a0, $v0
addi $sp, $sp, -4
sw $ra, 0($sp)
jal Function
sw $v0, answer #move returned answer to a new memory
lw $ra, 0($sp)
addi $sp, $sp, 4
la $a0, message1 #load address of message1
li $v0, 4 #prepare print string
syscall
lw $a0, answer
li $v0, 1
syscall
jr $ra
############################################################################
# Procedure/Function Function1
# Description: recursive math function
# parameters: $a0 = value of n,
# return value: $v0 = answer
# registers to be used: $s3 and $s4 will be used.
############################################################################
Function:
addi $sp, $sp, -12 #adjust stack pointer
sw $ra, 8($sp) #save return address
sw $a0, 4($sp) #save n
sw $s0, 0($sp) #save immediate value (used for storing function(n-1))
li $t2, 15
slti $t0, $a0, 6
beq $t0, $zero, GreaterThanFive
LessThanFive:
add $t1, $a0, $zero
add $t1, $t1, $a0
sub $t2, $t2, $t1
move $v0, $t2
j Conclusion
GreaterThanFive:
addi $a0, $a0, -1
jal Function
move $s0, $v0
lw $a0, 4($sp)
addi $a0, $a0, -3
jal Function
lw $a0, 4($sp)
mul $t3, $a0, $s0
sub $t4, $t3, $v0
add $t5, $t4, $a0
addi $t6, $t5, -23
move $v0, $t6
Conclusion:
lw $s1,0($sp) # restore intermediate value
lw $a0,4($sp)
lw $ra,8($sp)
addi $sp,$sp,12 # restore stack
jr $ra #return to caller```
having some trouble with an assignment, not looking for solution code, just some answers to why I keep encountering this error.
The program asks the user for 10 digits and then displays the resulting sum (using the stack and recursion).
I know from debugging that the read: portion works fine, but I get the error "Runtime exception at 0x0040005c: fetch address not aligned on word boundary 0x00000001". The error refers to the line in summation: lw $t0, 0($a0)
Not sure what is wrong since I only ever increment by 4 bytes. I've checked other similar questions but couldn't find any clarification. Any help would be greatly appreciated.
.data
A1: .space 40
input: .asciiz "please enter a number: "
Str: .asciiz "the sum is: "
.text
main:
li $s1, 0
la $t0, A1
addi $s0, $zero, 0
read:
beq $s1, 10, prep
li $v0, 4
la $a0, input
syscall
li $v0, 5
syscall
sw $v0, ($t0)
addi $t0, $t0, 4
addi $s1, $s1, 1
j read
prep:
la $a0, A1
addi $a1, $a0, 40
jal summation
summation:
subi $sp, $sp, 8
sw $ra, 4($sp)
lw $t0, 0($a0)
sw $t0, 0($sp)
sgt $t1, $a0, $a1
beq $t1, $zero, L1
addi $v0, $zero, 0
addi $sp, $sp, 8
jr $ra
L1:
addi $a0, $a0, 4
jal summation
lw $a0, 0($sp)
lw $ra 4($sp)
addi $sp, $sp, 8
add $v0, $a0, $v0
jr $ra
I must implement a recursive series in MIPS, here is the high level code:
int suite(n)
{
if (n == 0) return 0;
else
return (suite(n-1) + 4*n);
}
I have several problems with my assembly code. The first one is that it doesn't give the expected result, as it adds 4 each time.
My second problem is that it doesn't end. I've used a recursive textbook example for a factorial.
Here's the assembly code:
.data
msg: .asciiz "Entrer un nombre : "
.text
.globl main
main:
#print msg
li $v0,4
la $a0,msg
syscall
#input prompt
li $v0,5
syscall
addi, $a0, $v0, 0
jal suite
suite:
addi $sp, $sp,-12
sw $a1, 8($sp)
sw $a0, 4($sp)
sw $ra, 0($sp)
addi $t0, $0, 1
slt $t0, $a0, $t0
beq $t0,$0 else
addi $sp, $sp, 12
li $v0, 1
syscall
add $v0, $0, $0
jr $ra
else:
add $a1, $a0, $a0
add $a1, $a1, $a1
addi $a0, $a0, -1
jal suite
lw $ra, 0($sp)
lw $a0, 4($sp)
lw $a1, 8($sp)
addi $sp, $sp, 12
add $a0, $v0, $a1
print:
li $v0, 1
syscall
add $v0, $0, $0
jr $ra
end:
Any help would be helpful.
Okay Im trying to do C(n, k) = C(n - 1, k - 1) + C(n - 1, k).
So far I have:
$a0 - n
$a1 - k
$v0 - C(n, k)
addi $sp, $sp, 8
sw $ra, 4($sp)
sw $s0, 0($sp)
addi $a0, $a0, -1
addi $a1, $a1, -1
lw $ra, 0($sp)
lw $s0, 4($sp)
Now Im lost on what to do next please help me out.
If I look right, it's about the binomial coefficient. Yes, the first steps into MIPS can be kinda confusing, but practice is the key to get better. I don't know if you are in any course or anything. I wrote up something for you, here with the extra feature of getting the input values for n and k. In the end, it prints out the result of C(n, k).
.TEXT
.GLOBL __MAIN
__MAIN:
LI $V0, 4 // print1 asking you for number (n).
LA $A0, PRINT1
SYSCALL
LI $V0,5 // do a syscall that reads an integer.
SYSCALL
MOVE $T0, $V0
LI $V0, 4 // print2 asking you for number (k).
LA $A0, PRINT2
SYSCALL
LI $V0,5 // do a syscall that reads an integer.
SYSCALL
MOVE $A0, $T0
MOVE $A1, $V0
JAL BINOMIALVAL
// this marks the end of procedure call. woo.
MOVE $T0, $V0
LI $V0, 4 // prints print3.
LA $A0, PRINT3
SYSCALL
MOVE $A0, $T0
LI $V0,1 // this prints your c(n,k)
SYSCALL
LI $V0,4 // this will print an eol. (end of line)
LA $A0, CR
SYSCALL
LI $V0,10 // exit here.
SYSCALL
// will display the result and exit.
BINOMIALVAL:
SLT $T0, $A0, $A1 // if n < k, then set t0 to 1.
BNE $T0, $ZERO, END1 // if t0 != 0, then branch to end1.
BEQ $A0, $A1, END2 // if n == k, then branch to end2
BEQ $A1, $ZERO, END2 // if n == 0, then branch to end2.
SW $FP, -4($SP)
ADDI $FP, $SP, 0
ADDI $SP, $SP, -12
SW $RA, 4 ($SP)
SW $A0, 0 ($SP)
ADDI $SP, $SP, -4
SW $T1, ($SP)
ADDI $A0, $A0, -1
JAL BINOMIALVAL
MOVE $T1, $V0
ADDI $SP, $SP, -4
SW $A1, ($SP)
ADDI $SP, $SP, -4
SW $RA, ($SP)
ADDI $A1, $A1, -1
JAL BINOMIALVAL
ADD $V0, $T1, $V0
LW $RA, ($SP)
ADDI $SP, $SP, 4
LW $A1, ($SP)
ADDI $SP, $SP, 4
LW $T1, ($SP)
ADDI $SP, $SP, 4
LW $A0, ($SP)
ADDI $SP, $SP, 4
LW $RA, ($SP)
ADDI $SP, $SP, 4
LW $FP, ($SP)
ADDI $SP, $SP, 4
J COMPLETE
END1: MOVE $V0, $ZERO
J COMPLETE
END2: ADDI $V0, $ZERO, 1
COMPLETE: JR $RA // return to normal routine.
.DATA
PRINT1: .asciiz "Enter your value for n "
PRINT2: .asciiz "Enter your value for k "
PRINT3: .asciiz "Value of c(n,k) = "
CR: .asciiz "\n"