Recursion RISC-V递归阶乘函数调试
我试图在RISCV中创建递归阶乘函数,但遇到了一些问题 以下是我们到目前为止的情况:Recursion RISC-V递归阶乘函数调试,recursion,assembly,factorial,riscv,Recursion,Assembly,Factorial,Riscv,我试图在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, x0, '\n' addi a0, x0, 11
.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
我们尝试添加和更改要使用的寄存器,但仍然无法将正确的值加载到正确的寄存器中。我们还被困在如何递归地完成这项工作上。我希望能得到一些帮助 您的
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, t1, -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;
如果要使用循环,可以通过将条件放在底部,将指令保存在循环体中<代码>bne a0,x0,循环而不是
j循环
。(要得到0!=1而不是0,您需要一个beq
跳过循环,但是顶部的beq可以在循环之外,而不是运行每个迭代)。这是一个很好的链接,可以解释为什么不像我那样编写循环。我用一个跳转来编写它,使其与提供的代码最为相似(并逐行匹配C)。我应该包括一个关于while-vs-if-do-while循环格式的注释,但是我认为这个注释现在可以达到这个目的。