实验-使用递归计算阶乘-RISC-V(计算机组成原理)
目录
一、实验内容
二、实验步骤
三、实验效果
四、实验环境
五、实验小结和思考
一、实验内容
一个典型的计算阶乘的递归过程如下图所示:
在这个任务中,一份汇编代码的框架“task4-阶乘”你需要使用RISC-V或MIPS汇编程序以递归的形式解决这个问题。你可能会遇到的挑战包括:(1)如何使用栈保护某些重要的寄存器;(2)如何结合RISC-V的MIPS的jal分支跳转指令实现递归。当你进入测试阶段时,你可以在第4行代码修改n的值:
二、实验步骤
(1)我们利用a2这个寄存器来暂存阶乘的结果,所以在main函数中,我们在跳转前,先加入一条初始化a2为1的指令。
(2)在这里我们首先需要判断n是否为0,如果为0,直接跳到loop函数处,将a2的值赋给a0,再跳回A处(不用调用factorial函数),打印出结果。
(3)如果n不为0,则调用factorial函数,计算阶乘。
(4)首先先保护ra的值,先将sp指针的值减4,然后把ra的值写入当前sp指向的地址处。
(5)将a2和a0寄存器中的值相乘保存到a2寄存器中,然后a0寄存器中的值减一(加-1)。
(6)接着比较a0的值是否为0,不为0则继续递归,如果为0就出栈(把当前sp指向地址的值赋给ra,sp加4)。再把a2的值赋给ra,返回main函数。
(7)最后将a0的值打印出来。
三、实验效果
(1)输入0时的答案:
(2)输入6时的答案
(3)程序运行中栈的变化:
还未调用factorial函数时sp的值:
调用一次factorial函数时sp的值:
可以看到,调用一次factorial函数,sp的值减4。
四、实验环境
Venus仿真器(https://venus.cs61c.org/)
五、实验小结和思考
-
问题1:未正确处理递归终止条件(
n=0
),导致程序陷入无限循环。
解决:在factorial
函数开始时增加beq a0, zero, exit
判断,若n=0
则直接跳转至返回阶段。 -
问题2:首次尝试时,未正确保存
ra
(返回地址),导致递归返回时跳转到错误位置。
解决:在每次递归调用前,先调整栈指针(addi sp, sp, -4
),并存储ra
到栈中(sw ra, 0(sp)
),返回时再恢复。 -
问题3:未保护
a0
(当前n
值)和a2
(累积结果),导致递归过程中数据丢失。
解决:在递归调用前将a0
和a2
压栈,返回后恢复,确保数据一致性。