使用 RISC-V (RV32I) 编译器无需递归计算第 n 个斐波那契数
Calculate nth Fibonacci number using RISC-V (RV32I) compiler without recursion
我用RISC-V汇编语言写了一个计算第n个斐波那契数的代码。它有两部分 - fib.s
和 runtest.s
,它将 n
的值加载到 a0
并调用 fib
,计算第 n 个斐波那契数(没有递归), 将结果加载到 a0
本身和 return 中。这是我的代码:
.global fib # the runtest.s will give an a0 value as input n and call fib
fib:
li a1, 0 # This is a
li a2, 1 # This is b
li a3, 0 # This is c
li a4, 2 # This is i
li a6, 2 # dummy, just to check a0 with
ble a0, a6, cond1 # check if a0 <= 2
bgt a0, a6, head # if a0 > 2, proceed to loop
head: # start of loop
add a3, a1, a2 # Here I'm implementing the space optimized version of fibonacci series without recursion:
mv a1, a2 # for i in range(2, n+1): c = a + b; a = b; b = c; return b
mv a2, a3
addi a4, a4, 1
blt a4, a0, head
bge a4, a0, end # iterates n-1 times and goes to end
cond1:
li a0, 1 # if n==1 or n==2 return 1
li a7, 93
ecall
end:
mv a0, a2 # copying the value of a2 (which is b) to a0, since the testbench
li a7, 93 # runtest.s is setup that way.
ecall
这是我的测试台 (runtest.s
):
.global _start
_start:
# Load 'n' into a0 and call fib
# Test 1
li a0,1 # Check n'th Fib number
call fib
li a5,1 # Expected result
bne a0,a5,.FINISH
# Test 2
li a0,3
call fib
li a5,3
bne a0,a5,.FINISH
# Test 3
li a0,7
call fib
li a5,13
bne a0,a5,.FINISH
# Test 4
li a0,9
call fib
li a5,34
bne a0,a5,.FINISH
# Test 5
li a0,20
call fib
li a5,6765
bne a0,a5,.FINISH
# Test 6
li a0,30
call fib
li a5,832040
bne a0,a5,.FINISH
# Finished tests
li a5,0 # All passed
.FINISH:
mv a0, a5
li a7, 93
ecall
每次我 运行 这段代码我只得到一个 return 值 1。有人可以指出其中的错误吗?另外,如果有更好的方法来实现相同的逻辑,也请告诉我。
我能够让您所有的测试台案例通过 3 处更改的 RISC-V 模拟器:
(1) 你的第二个测试用例的预期结果是错误的。我假设您使用的是 0 索引的斐波那契数,因为这是您的大多数测试用例所做的(例如,测试用例 1 说斐波那契数 1 是 1,测试用例 3 说斐波那契数 7 是 13)。在那种情况下,斐波那契数 3 应该是 2,而不是 3。
(2) 为了获得正确的迭代次数,在你的循环中,你的“i”变量/寄存器 a4 应该开始设置为 1,而不是 2。
(3) 您通常不会从 RISC-V 中的函数使用 ECALL 到 return。根据 RISC-V 规范,“ECALL 指令用于向执行环境发出服务请求。”它会导致一个精确的陷阱,并在(例如)实现系统调用时使用。取而代之的是函数调用中的 return 伪指令(类似于 x86 的表示法)。 ret 等同于 jalr x0 0(ra)。 (话虽这么说,也许您已经定义了 ecall 行为,以便当 a7 为 93 时,执行相当于 ret 的操作。)
我用RISC-V汇编语言写了一个计算第n个斐波那契数的代码。它有两部分 - fib.s
和 runtest.s
,它将 n
的值加载到 a0
并调用 fib
,计算第 n 个斐波那契数(没有递归), 将结果加载到 a0
本身和 return 中。这是我的代码:
.global fib # the runtest.s will give an a0 value as input n and call fib
fib:
li a1, 0 # This is a
li a2, 1 # This is b
li a3, 0 # This is c
li a4, 2 # This is i
li a6, 2 # dummy, just to check a0 with
ble a0, a6, cond1 # check if a0 <= 2
bgt a0, a6, head # if a0 > 2, proceed to loop
head: # start of loop
add a3, a1, a2 # Here I'm implementing the space optimized version of fibonacci series without recursion:
mv a1, a2 # for i in range(2, n+1): c = a + b; a = b; b = c; return b
mv a2, a3
addi a4, a4, 1
blt a4, a0, head
bge a4, a0, end # iterates n-1 times and goes to end
cond1:
li a0, 1 # if n==1 or n==2 return 1
li a7, 93
ecall
end:
mv a0, a2 # copying the value of a2 (which is b) to a0, since the testbench
li a7, 93 # runtest.s is setup that way.
ecall
这是我的测试台 (runtest.s
):
.global _start
_start:
# Load 'n' into a0 and call fib
# Test 1
li a0,1 # Check n'th Fib number
call fib
li a5,1 # Expected result
bne a0,a5,.FINISH
# Test 2
li a0,3
call fib
li a5,3
bne a0,a5,.FINISH
# Test 3
li a0,7
call fib
li a5,13
bne a0,a5,.FINISH
# Test 4
li a0,9
call fib
li a5,34
bne a0,a5,.FINISH
# Test 5
li a0,20
call fib
li a5,6765
bne a0,a5,.FINISH
# Test 6
li a0,30
call fib
li a5,832040
bne a0,a5,.FINISH
# Finished tests
li a5,0 # All passed
.FINISH:
mv a0, a5
li a7, 93
ecall
每次我 运行 这段代码我只得到一个 return 值 1。有人可以指出其中的错误吗?另外,如果有更好的方法来实现相同的逻辑,也请告诉我。
我能够让您所有的测试台案例通过 3 处更改的 RISC-V 模拟器:
(1) 你的第二个测试用例的预期结果是错误的。我假设您使用的是 0 索引的斐波那契数,因为这是您的大多数测试用例所做的(例如,测试用例 1 说斐波那契数 1 是 1,测试用例 3 说斐波那契数 7 是 13)。在那种情况下,斐波那契数 3 应该是 2,而不是 3。
(2) 为了获得正确的迭代次数,在你的循环中,你的“i”变量/寄存器 a4 应该开始设置为 1,而不是 2。
(3) 您通常不会从 RISC-V 中的函数使用 ECALL 到 return。根据 RISC-V 规范,“ECALL 指令用于向执行环境发出服务请求。”它会导致一个精确的陷阱,并在(例如)实现系统调用时使用。取而代之的是函数调用中的 return 伪指令(类似于 x86 的表示法)。 ret 等同于 jalr x0 0(ra)。 (话虽这么说,也许您已经定义了 ecall 行为,以便当 a7 为 93 时,执行相当于 ret 的操作。)