Recursive program in RISC-V assembly - recursion

I am trying to create a recursive program in RISC-V but I can't get it to get me the right result. It looks like it is calling itself only two times max, but I tried running it on paper and everything seems correct:
addi x31, x0, 4
addi x30, x0, 2
addi x2, x0, 1600 //initialize the stack to 1600, x2= stackpointer
ecall x5, x0, 5 //read the input to x5
jal x1, rec_func
ecall x0, x10, 2 //print the result
beq x0, x0, end
rec_func:
addi x2, x2, -16 //make room in stack
sd x1, 0(x2) //store pointer and result in stack
sd x10, 8(x2)
bge x5, x31, true // if i > 3, then go to true branch
addi x10, x0, 1 // if i <= 3, then return 1
addi x2, x2, 16 // reset stack point
jalr x0, 0(x1)
true:
addi x5, x5, -2 // compute i-2
jal x1, rec_func // call recursive func for i-2
ld x1, 0(x2) // load the return address
ld x10, 8(x2) // load result from last function call
addi x2, x2, 16 // reset stack point
mul x10, x10, x30 // multiply by 2
addi x10, x10, 1 // add 1
jalr x0, 0(x1) // return
end:
This is the original program logic:
if i<= 3 return 1
else return 2 * rec_func(i-2) +1

I don't have enough reputation to add a comment but have you tried running this with a debugger (GDB ?) instead of on paper? That should show what's actually in the registers and why it's not branching as you might expect. I'm not familiar enough with these instructions (learning x86 assembly) to figure the source out at the moment.

I got it working now. The changes that I made were following:
In the part where I was returning 1, I wasn't loading the stack pointer of the return call
I removed the storing of x10 into the memory as #Michael pointed it out that I was returning it and I didn't need it.
The final code looks like this:
addi x31, x0, 4
addi x30, x0, 2
addi x2, x0, 1600 // initialize the stack to 1600, x2= stackpointer
ecall x5, x0, 5 // read the input to x5
jal x1, rec_func
ecall x0, x10, 2 // print the result
beq x0, x0, end
rec_func:
addi x2, x2, -8 // make room in stack
sd x1, 0(x2) // store pointer and result in stack
bge x5, x31, true // if i > 3, then go to true branch
ld x1, 0(x2)
addi x10, x0, 1 // if i <= 3, then return 1
addi x2, x2, 8 // reset stack point
jalr x0, 0(x1)
true:
addi x5, x5, -2 // compute i-2
jal x1, rec_func // call recursive func for i-2
ld x1, 0(x2) // load the return address
addi x2, x2, 8 // reset stack point
mul x10, x10, x30 // multiply by 2
addi x10, x10, 1 // add 1
jalr x0, 0(x1) // return
end:

Related

How to reverse an array recursively using RISC-V?

I really have absolutely no idea how to do this, seems like the only solution online is behind a paywall. This is all I have:
.data
array: .word 1 2 3 4 5 6 7
.text
main:
la x12, array
addi x13, x0, 7
addi x13, x13, -1
slli x13, x13, 2
add x13, x13, x12
jal x1, reverse
beq x0, x0, END
##### the function would start here #####
reverse: jalr x0, 0(x1)
##### and end here #####
END: add x1, x0, x10
The procedure receives two memory locations, the start position and the end position of the array.
My guess was something like using srli, but I'm 99.9% sure it's wrong.
(this is not for a college assignment btw, just an unnecessarily long revision exercise that's been haunting me for a week and now my brain freezes every time I look at a single line of assembly code)

Recursive program in RISC-V (procedure call)

I'm trying to implement the recursive equation here, but I have no idea what's going wrong with my code.
It keeps output 1 no matter what input I gave.
The function is as follows:
T(n) = T(n-100) + 2*T(n/2) + 5 if n > 1
= 1 otherwise
.globl __start
.text
__start:
# read from standard input a0 = n
addi a0, zero, 5
ecall
################################################################################
# Recursive function #
# T(n) = T(n-100)+2*T((n/2))+5 if n>1 #
# = 1 otherwise #
################################################################################
addi s2,x0,1 #for base case
addi s3,x0,2 #for comparison
blt a0,s3,result
recur:
addi a2,a2,5
addi a3,a3,9
addi sp,sp,-8 #store 2 registers into stack
sw x1,4(sp)
sw a0,0(sp)
bge a0,s3,L1
bge a0,s3,L2
addi s2,x0,1
addi sp,sp,8
jal x0,result
L1: #to do T(n-100)
addi a0,a0,-100
jal x1,recur
addi x6,x10,0 #T(n-100) stored in x6
lw x10,0(sp)
lw x1,4(sp)
addi sp,sp,8
jalr x0,0(x1)
L2: #to do T(n/2)
div a0,a0,s3
jal x1,recur
addi x7,x10,0 #T(n/2) stored in x7
lw a0,0(sp)
lw x1,4(sp)
addi sp,sp,8
mul x7,x7,s3
add s2,x6,x7
addi s2,s2,5
jalr x0,0(x1)
################################################################################
result:
# prints the result in s2
addi a0, zero, 1
addi a1, s2, 0
ecall
# ends the program with status code 0
addi a0, zero, 10
ecall

RISC-V Recursive Factorial Function Debugging

Im trying to create a recursive factorial function in RISCV but having some problems.
Here's what we have so far:
.globl factorial
.data
n: .word 8
.text
main:
la t0, n
lw a0, 0(t0)
jal ra, factorial
addi a1, a0, 0
addi a0, x0, 1
ecall # Print Result
addi a1, x0, '\n'
addi a0, x0, 11
ecall # Print newline
addi a0, x0, 10
ecall # Exit
factorial:
la t1, n
beq x0, t1, finish
addi t0, t1, -1
mul a0, t0, a0
j factorial
finish:
ret
ecall
We tried adding and changing around the registers to use, but its still not loading the correct values to the correct registers. We're also kinda stuck on how to do this recursively. Would love some help!
Your main code looks fine. All of the issues I see are in the factorial function. First, there are four clear issues with your factorial function:
factorial:
# This loads the address of n not the value at label n
# You need to additionally lw t1, 0(t1) to get the value
la t1, n
# t1 is never getting modified so why would this loop ever terminate?
beq x0, t1, finish
# You should do these two operations in the opposite order
# if t1 = 1, a0 would become 0
addi t0, t1, -1
mul a0, t0, a0
j factorial
finish:
ret
# Why ecall here? You have already returned. This is unreachable.
ecall
However, you can't just fix those and expect it to work. Your current implementation is lacking a plan of how to actually compute the factorial. I assume you were trying to make an implementation like the following:
int factorial_recursive(int n) {
if (n == 0) {
return 1;
}
int recursive = factorial_recursive(n-1);
return n * recursive;
}
A direct translation of that C code would need to use the stack to save n and the return address and properly follow calling convention. I am not prepared to write out a complete explanation of that though, so I will explain how to convert the looping version of factorial to get you started in the right direction.
The C code I will implement is RISC-V assembly:
int factorial_loop(int n) {
int out = 1;
while (n > 0) {
out *= n;
n -= 1;
}
return out;
}
For this code, n will start out in a0, but eventually it will need to be moved out so we can return out so we will allocate our registers so the function will look like:
int factorial_loop(int a0) {
int a1 = 1;
while (a0 > 0) {
a1 *= a0;
a0 -= 1;
}
a0 = a1;
return a0;
}
From here it is pretty easy to do a direct conversion.
factorial_loop:
li a1, 1 # int a1 = 1;
loop:
beq a0, x0, finish # while (a0 > 0) {
mul a1, a1, a0 # a1 *= a0;
addi a0, a0, -1 # a0 -= 1;
j loop # }
finish:
mv a0, a1 # a0 = a1;
ret # return a0;

"(error) attempting to write to an invalid memory address" When trying to store stack pointer

I'm trying to learn RISC-V under the Jupiter environment (risc32) and I came across a problem asking me to write a recursive program with RISC-V. I can't seem to get the sw instruction to work, as it always gives an error: invalid address
I've tried different offsets, different registers etc. nothing seems to work
.globl __start
.rodata
msg_input: .string "Enter a number: "
msg_result: .string "The result is: "
newline: .string "\n"
.text
__start:
# prints msg_input
li a0, 4
la a1, msg_input
ecall
#read from standard input
li a0, 5
ecall
#initialize stack
addi x31, x0, 2
addi sp, x0, 800
mv x5, a0
jal x1, recfunc
mv t0, x5
recfunc:
addi sp, sp, -8
sw x1, 0(sp)
bge x5, x31, true
lw x1, 0(sp)
addi x10, x0, 1
addi sp,sp, 8
jalr x0, 0(x1)
true:
div x5, x5, x31
jal x1, recfunc
lw x1, 0(sp)
addi sp,sp,8
mul x10, x10, x31
addi x10, x10, 1
jalr x0, 0(x1)
result:
#prints msg_result
li a0, 4
la a1 msg_result
ecall
#prints the result in t0
li a0, 1
mv a1, t0
ecall
#ends the program with status code 0
li x5, 10
ecall
Error occurs at:
sw x1, 0 (x2)
(error) attempting to write to an invalid memory address 0x00000318

Recursive Fibonacci in ARM

I'm trying to convert this recursive Fibonacci code to arm assembly language. I'm new to this and not really sure how to do it. I have some code snippets of things that I've played with below.
Fib (n) {
if (n == 0 || n == 1) return 1;
else return Fib(n-2) + Fib(n-1);
}
Here is my attempt so far:
RO = 1
CMP RO #1
BGT P2
MOV R7 #1
B END
P2:
END LDR LR [SO,#0]
ADD SP SP, #8
MOV PC, LR
Help would be much appreciated
For the sake of avoiding spoon-feeding, I wrote a LEGv8 program that finds Fibonacci sequence using recursion. LEGv8 is slightly different than ARMv8, however the algorithm remains.
Please review the code, and change the commands / registers to their corresponding values in ARMv8.
I assumed that n (the range of the Fibonacci sequence) is stored in register X19.
I also assumed that we ought to store the Fibonacci sequence in an array, which has its base address stored in X20.
MOV X17, XZR // keep (previous) 0 in X17 for further use
ADDI X18, XZR, #1 // keep (Current) 1 in X18 for further use
ADDI X9, XZR, #0 // Assuming i = 0 is in register X9
fibo:
SUBI SP, SP, #24 // Adjust stack pointer for 3 items
STUR LR, [SP, #16] // save the return address
STUR X17, [SP, #8] //save content of X17 on the stack
STUR X18, [SP, #0] //save content of X18 on the stack
SUBS X10, X9, X19 // test for i==n
CBNZ X10, L1 // If i not equal to n, go to L1
MOV X6, XZR // keep 0 on X6
ADDI X5, XZR, #1 // keep 1 on X5
ADDI X2, X9, #1 //X9 increased by 1 for further use
STUR X6, [X20,#0] //store 0 in the array
STUR X5, [X20, #8] //store 1 in the array
ADDI SP, SP, #24 // pop 3 items from the stack
BR LR // return to the caller
L1:
ADD X16, X17, X18 // Next_Num = previous + Current
MOV X17, X18 // Previous = Current
MOV X18, X16 // Current= Next_Num
ADDI X9, X9, #1 // i++
BL fibo // call fibo
LDUR X18, [SP, #0] // return from BL; restore previous
LDUR X17, [SP, #8] // restore current
LDUR LR, [SP, #16] // restore the return address
ADDI SP, SP, #24 // adjust stack pointer to pop 3 items
ADD X7, X18, X17 // keep (previous + current) value on register X7
LSL X2, X2, #3 // Multiplying by 8 for offset
ADD X12, X20, X2 // address of the array increase by 8
STUR X7, [X12, #0] // store (previous + current) value on the array
SUBI X2, X2, #1 // X9 decreased by 1
BR LR // return

Resources