问题描述
我正在尝试在 RISCV 中创建递归阶乘函数,但遇到了一些问题。
这是我们目前所拥有的:
.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,'\n'
addi a0,11
ecall # Print newline
addi a0,10
ecall # Exit
factorial:
la t1,n
beq x0,t1,finish
addi t0,-1
mul a0,t0,a0
j factorial
finish:
ret
ecall
我们尝试添加和更改要使用的寄存器,但仍然没有将正确的值加载到正确的寄存器中。我们也有点坚持如何递归地做到这一点。希望得到一些帮助!
解决方法
您的 main
代码看起来不错。我看到的所有问题都在阶乘函数中。首先,您的阶乘函数有四个明显的问题:
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,-1
mul a0,t0,a0
j factorial
finish:
ret
# Why ecall here? You have already returned. This is unreachable.
ecall
但是,您不能仅仅修复这些并期望它起作用。您当前的实现缺乏如何实际计算阶乘的计划。我假设您正在尝试进行如下实现:
int factorial_recursive(int n) {
if (n == 0) {
return 1;
}
int recursive = factorial_recursive(n-1);
return n * recursive;
}
该 C 代码的直接翻译需要使用堆栈来保存 n 和返回地址,并正确遵循调用约定。不过,我不准备写出完整的解释,所以我将解释如何转换 factorial 的循环版本以帮助您朝着正确的方向开始。
我将实现的 C 代码是 RISC-V 汇编:
int factorial_loop(int n) {
int out = 1;
while (n > 0) {
out *= n;
n -= 1;
}
return out;
}
对于此代码,n
将从 a0
开始,但最终需要将其移出,以便我们可以返回 out
,以便我们分配寄存器,以便函数看起来像:
int factorial_loop(int a0) {
int a1 = 1;
while (a0 > 0) {
a1 *= a0;
a0 -= 1;
}
a0 = a1;
return a0;
}
从这里可以很容易地进行直接转换。
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;