🎯要点
- 🎯使用单板计算机 Visionfive 2 或模拟器测试RISC-V汇编
- 🎯RISC-V汇编加载和算术。🎯使用GNU MAKE汇编RISC-V指令,ESP32使用CMake编译执行指令。🎯RISC-V汇编功能和使用释义:控制指令,内存管理,功能块和堆栈。
- 🎯 使用RISC-V汇编代码控制GPIO。🎯RISC-V汇编指令嵌入C 代码,C代码调用汇编指令控制,Python代码调用RISC-V汇编指令。🎯RISC-V数学计算汇编指令,矩阵乘法示例。🎯使用模拟器测试RISC-V浮点运算。🎯RISC-V汇编代码优化,使用渗透工具将RISC-V汇编和C 代码之间关系。
- 🎯ESP32-C3使用RISC-V 汇编:安装RISC-V模拟器编译调试。🎯 C代码和RISC-V汇编示例1:32位整数累加。🎯C代码和RISC-V汇编示例2:控制LED闪烁🎯C代码和RISC-V汇编示例3:奇校验。🎯C代码和RISC-V汇编示例4:加载和存储。🎯C代码和RISC-V汇编示例5:摄氏度数据。🎯C代码和RISC-V汇编示例6:调用程序指令。🎯C代码和RISC-V汇编示例7:程序流控制。🎯C代码和RISC-V汇编示例8:算术运算。🎯C代码和RISC-V汇编示例9:乘法除法。🎯C代码和RISC-V汇编示例10:寻址、下标和字符串。🎯C代码和RISC-V汇编示例11:浮点处理。🎯C代码和RISC-V汇编示例12:使用GCC处理测试代码。🎯C代码和RISC-V汇编示例13:控制拓展。🎯C代码和RISC-V汇编示例14:内嵌汇编。
5.🎯安装FPGA开发工具HLS和IDE,创建和模拟IP。- 🎯安装和使用RISC-V工具链,模拟器/调试器,调试C代码示例。🎯RV32I(RISC-V)汇编示例,C代码和汇编代码。
- 🎯更新程序计数器的路径C++代码:顶层函数原型,读取内存数组函数,执行函数,IP运行条件函数,使用测试平台进行 IP 仿真,FPGA开发板测试IP,构建 RISC-V 指令编码,填充执行阶段构建寄存器路径。
- 🎯构建RISC-V处理器(C++代码):RV32I 顶层函数,更新指令编码,计算访问地址,使用测试平台模拟RV32I,FPGA开发板测试IP。
- 🎯自编汇编代码测试RISC-V处理器,使用RISC-V ISA模拟器测试,在 Rv32I 处理器上运行基准测试套件,使 Rv32I IP 适应 RISC-V F 扩展。
- 🎯构建流水线 RISC-V 处理器(C++代码):级间传输类型定义,IP 顶层函数,编码函数,执行函数,IP的仿真与综合,Vivado项目使用该IP,将流水线分为多个阶段。
- 🎯使用多周期流水线构建 RISC-V 处理器(C++代码),使用多个 Hart 流水线构建 RISC-V 处理器,互连 IP ,构建多核RISC-V处理器,使用 Multihart 内核的多核 RISC-V 处理器,开发板使用RISC-V处理器。
🍇RISC-V汇编
输入Doubler
您应该知道,RISC-V 函数的输入位于寄存器 a0、a1 至 a7 中。这些只是从 x10 开始的寄存器的别名。
assembly
doubler:
ADD a0, a0, a0
为了测试这一点,请在模拟器中运行代码之前在寄存器 a0 中放置一个初始值。如果有效,那么 a0 应该加倍。函数应该在 a0 中返回结果,所以这是正确的方法。
如果这是从其他地方调用的真实函数,我们将需要在最后一行从函数返回:
assembly
JALR zero, ra, 0
通常RISC-V汇编器会有一条伪指令RET来实现这一点。
该指令如何运作?在真实的程序中,我们以 42 作为参数调用的倍增函数必须写成这样:
assembly
ADDI a0, zero, 42
JAL ra, doubler
SUB t3, t4, t2
这意味着返回地址存储在 ra (x1) 寄存器中,因此当 doubler 返回时,它开始执行 SUB t3、t4、t2 指令。这意味着什么?只是我放在那里的任意指令。
乘八
这次我要你将 input 的输入乘以 8。基本 RISC-V ISA 没有乘法指令,我们使用的解释器没有任何支持除法和乘法的 RISC-V M 扩展。
加法
从概念上讲,乘法只是重复加法,所以这可能是最明显的解决方案:
assembly
eight_times:
ADD a0, a0, a0
ADD a0, a0, a0
ADD a0, a0, a0
HLT # Stop execution
使用逻辑移位
在二进制数系统中,将所有数字向左移动一位与乘以二相同。移动两个位置就像乘以四。
assembly
010b = 2
010b << 1 = 100b = 4
001b << 2 = 100b
在 RISC-V 汇编中,我们使用 SLLI 和 SLL 执行左移。 I 后缀表示我们使用立即值而不是寄存器来指定要移位的位置数。
assembly
eight_times:
SLLI a0, a0, 3
JALR zero, ra, 0
HTL # Stop excution. Normally you put RET
寻找最大值
这是公共函数 c = max(a, b) 的实现,它将 a 或 b 中较大的值分配给 c。要解决这个问题需要使用跳转和分支指令。有关如何将值从一个寄存器移动到另一个寄存器的提示是,您可以使用 ADD 或 ADDI 指令。
普通的 RISC-V 汇编代码有一个称为 MV 的伪指令,我们在这里无法访问它,但以下这两行是等效的:
assembly
MV a4, a3
ADDI a4, a3, 0
查看下面的解决方法:
assembly
max:
BLT a0, a1, second # if a0 < a1 then a1 is larger
JAL zero, done
second:
ADD a0, zero, a1 # make a1 the return value
done:
HLT # normally a RET would be here
如果你没搞清楚这一点。您可以尝试实现 min 函数。
简单乘数
我们不用与固定数字相乘,而是将两个任意数字相乘。 在这种情况下,您可以仅使用添加和分支。 它不需要是高效的。 该函数将 a0 和 a1 中的两个参数相乘,并像往常一样在 a0 中返回结果。
assembly
multiply:
ADD t0, zero, zero
ADDI a1, a1, -1
accumulate:
ADD t0, t0, a0
ADDI a1, a1, -1
BGE a1, zero, accumulate
ADD a0, zero, t0
HLT
由于我们的解释器缺少大量 RISC-V 指令,因此它的长度稍长,可读性也较差。
assembly
multiply:
LI t0, 0 # set t0 to 0
accumulate:
ADD t0, t0, a0
ADDI a1, a1, -1 # decrement a1
BGT a1, zero, accumulate
MV a0, t0 # copy t0 value to a0
RET # return to calling function
快速乘法
当乘法在软件中实现时,我们上面使用的方法没有被使用,因为这太慢了。相反,使用了添加和移位的组合。比如执行 42 × 20,只需两次加法,而不是二十次加法。您可以使用左移 SLL 或 SLLI 以及右移 SRA 和 SRAI。
assembly
fast_multiply:
ADD t0, zero, zero # to keep track of result
next_digit:
ANDI t1, a1, 1 # is rightmost bit 1?
SRAI a1, a1, 1
BEQ t1, zero, skip # if right most bit 0, don't add
ADD t0, t0, a0
skip:
SLLI a0, a0, 1 # double first argument
BNE a1, zero, next_digit
ADD a0, zero, t0 # move accum result to a0
HLT