有了前两节对于RISC-V汇编、寄存器、汇编语法等的认识,本节开始介绍RISC-V指令集和伪指令。
前面说了RISC-V的模块化特点,是以RV32I为作为ISA的核心模块,其他都是要基于此为基础,可以这样认为:RISC-V ISA = 基本整数指令集+多个可选扩展指令集
;另外RISC-V的ISA spec上是从指令类型和指令格式开始介绍指令的;但从一个嵌入式软件开发人员的角度来说,不是特别适合学习和记忆,所以我这里简单罗列下,不多讲解,感兴趣可以参考spec。
1 指令类型
1.1 组成格式
所有RISC-V指令都是固定长度的32位,这有助于简化指令解码过程。每个指令都由以下几个关键部分组成:
- opcode:这是7位的操作码,用来标识指令的基本类型。
- funct3:这是一个3位的功能码,与opcode一起使用以进一步细化指令的类别。
- funct7:某些指令使用额外的7位功能码来更精确地定义指令的行为。
- rs1/rs2/rd:这些是5位的寄存器地址,分别代表源寄存器1、源寄存器2和目的寄存器。
- imm:立即数字段,其大小和位置根据指令类型的不同而变化。
1.2 类型
RISC-V定义了几种基本的指令格式,每一种都针对特定类型的运算或操作。这些格式包括:R型、I型、S型、B型、U型、J型。
-
R型(Register)
用于寄存器间的算术/逻辑运算(如ADD x1, x2, x3)
字段:opcode确定操作类型,funct3和funct7进一步指定具体操作(如区分ADD与SUB) -
I型(Immediate)
用于立即数操作(如ADDI x1, x2, 42)或加载指令(如LW x1, 100(x2))
立即数:12位符号扩展,直接嵌入指令中 -
S型(Store)
存储数据到内存(如SW x3, 200(x4))
立即数:12位拆分为imm[11:5]和imm[4:0],组合后作为偏移地址。 -
B型(Branch)
条件分支(如BEQ x1, x2, label)
立即数:13位(符号扩展后左移1位),拆分为imm[12|10:5|4:1|11],支持更大跳转范围 -
U型(Upper Immediate)
加载高20位立即数(如LUI x1, 0x12345)或构造地址(如AUIPC)
立即数:20位直接嵌入高位,低12位由后续指令补充 -
J型(Jump)
长距离无条件跳转(如JAL x1, label)
立即数:20位符号扩展后左移1位,支持±1MB跳转范围
但在实际应用中,我们也很难记住这么汇编指令机器码,一般情况下也不会有错,具体可以参考spec。
2 指令命名
下图是RV32I基础指令集的⼀⻚图形表示,将有下划线的字⺟从左到右连接起来,即可组成完整的RV32I指令集。集合标志{}内列举了指令的所有变体,变体⽤加下划线的字⺟或下划线字符_表示,特别的,下划线字符_表示对于此指令变体不需⽤字符表示
以slt指令为例,如下示意图:大括号{ }内列举了每组指令的所有变体,这些变体通过带下滑线的字母(单独的下划线_表示空字段),从左到右连接带下滑线的字母即可组成完整的指令集,比如slt意思是set less than,相当于是一种缩写,完整语句方便我们快速清晰的理解指令的作用。
上图可以表示:slt、slti、sltu、sltiu 这4条RVI指令。
下面将列举以下RISC-V指令集:
- RVI(包括RV32I与RV64I)
- RVM(包括RV32M与RV64M)
- RVFD(包括RV32FD与RV64FD)
- RVA(包括RV32A与RV64A)
3 RVI指令集
RVI是 RISC-V 指令集架构的基础部分,它定义了32位整数运算的核心指令集。RVI 包括 RV32I(32位整数指令集)和 RV64I(64位整数指令集),它们为处理器提供了执行基本计算任务的能力;包括:内存操作指令、逻辑指令、分支和跳转指令、算术指令等等,下面就一一列举。
3.1 内存操作指令
在RISC-V中,内存操作主要通过加载(Load)和存储(Store)两类指令来实现。这些指令允许程序从内存读取数据到寄存器(Load),或将寄存器中的数据写入内存(Store)
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
LB | lb rd, offset(rs1) | 加载字节(符号扩展) | rd = SignExt(Mem[rs1 + offset][7:0]) | RV32I / RV64I |
LBU | lbu rd, offset(rs1) | 加载字节(无符号扩展) | rd = ZeroExt(Mem[rs1 + offset][7:0]) | RV32I / RV64I |
LH | lh rd, offset(rs1) | 加载半字(符号扩展) | rd = SignExt(Mem[rs1 + offset][15:0]) | RV32I / RV64I |
LHU | lhu rd, offset(rs1) | 加载半字(无符号扩展) | rd = ZeroExt(Mem[rs1 + offset][15:0]) | RV32I / RV64I |
LW | lw rd, offset(rs1) | 加载字(RV32I:32位;RV64I:符号扩展至64位) | RV32I: rd = Mem[rs1 + offset][31:0] RV64I: rd = SignExt(Mem[rs1 + offset][31:0]) | RV32I / RV64I |
LWU | lwu rd, offset(rs1) | 加载字(无符号扩展至64位) | rd = ZeroExt(Mem[rs1 + offset][31:0]) | RV64I |
LD | ld rd, offset(rs1) | 加载双字(64位) | rd = Mem[rs1 + offset][63:0] | RV64I |
SB | sb rs2, offset(rs1) | 存储字节 | Mem[rs1 + offset] = rs2[7:0] | RV32I / RV64I |
SH | sh rs2, offset(rs1) | 存储半字 | Mem[rs1 + offset] = rs2[15:0] | RV32I / RV64I |
SW | sw rs2, offset(rs1) | 存储字 | Mem[rs1 + offset] = rs2[31:0] | RV32I / RV64I |
SD | sd rs2, offset(rs1) | 存储双字 | Mem[rs1 + offset] = rs2[63:0] | RV64I |
3.2 算术指令
算术指令狭义定义:仅包含加法、减法及其直接相关的操作,用于寄存器或寄存器与立即数之间的数值运算。
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
基础加减指令 | ||||
ADD | add rd, rs1, rs2 | 加法(忽略溢出) | rd = rs1 + rs2 | RV32I / RV64I |
SUB | sub rd, rs1, rs2 | 减法(忽略溢出) | rd = rs1 - rs2 | RV32I / RV64I |
ADDI | addi rd, rs1, imm | 立即数加法(符号扩展立即数) | rd = rs1 + SignExt(imm) | RV32I / RV64I |
RV64I 扩展加减指令 | ||||
ADDIW | addiw rd, rs1, imm | 立即数加法(32位,符号扩展至64位) | rd = SignExt((rs1 + SignExt(imm))[31:0]) | RV64I |
ADDW | addw rd, rs1, rs2 | 加法(32位,符号扩展至64位) | rd = SignExt((rs1 + rs2)[31:0]) | RV64I |
SUBW | subw rd, rs1, rs2 | 减法(32位,符号扩展至64位) | rd = SignExt((rs1 - rs2)[31:0]) | RV64I |
高位立即数构建指令 | ||||
LUI | lui rd, imm | 加载高位立即数(imm[31:12]) | rd = imm << 12 | RV32I / RV64I |
AUIPC | auipc rd, imm | 将高位立即数与 PC 相加 | rd = PC + (imm << 12) | RV32I / RV64I |
伪指令表格:
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
寄存器操作 | ||||
MV | mv rd, rs | 寄存器间移动值 | addi rd, rs, 0 | RV32I / RV64I |
NEG | neg rd, rs | 取负值(rd = -rs) | sub rd, x0, rs | RV32I / RV64I |
NEGW | negw rd, rs | 取负值(32位操作,符号扩展) | subw rd, x0, rs | RV64I |
立即数操作 | ||||
LI | li rd, imm | 加载任意立即数到寄存器 | 若 imm 在 12 位有符号范围内:addi rd, x0, imm 否则: lui rd, imm[31:12] + addi rd, rd, imm[11:0] | RV32I / RV64I |
地址加载 | ||||
LA | la rd, symbol | 加载绝对地址(链接时解析) | auipc rd, offset_hi + addi rd, rd, offset_lo 或 lui rd, offset_hi + addi rd, rd, offset_lo | RV32I / RV64I |
LLA | lla rd, symbol | 加载本地地址(PC相对,位置无关) | auipc rd, offset_hi + addi rd, rd, offset_lo | RV32I / RV64I |
符号扩展 | ||||
SEXT.W | sext.w rd, rs | 将低32位符号扩展至64位(RV64I) | addiw rd, rs, 0 | RV64I |
空操作 | ||||
NOP | nop | 空操作(无实际效果) | addi x0, x0, 0 | RV32I / RV64I |
3.3 移位指令
移位指令用于对寄存器中的数据进行位级左移或右移,分为以下两类:
-
- 寄存器移位:移位位数由另一个寄存器的低 5 位(RV32I)或低 6 位(RV64I)指定。
-
- 立即数移位:移位位数由指令中的立即数字段直接指定。
- 立即数移位:移位位数由指令中的立即数字段直接指定。
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
逻辑左移 | ||||
SLL | sll rd, rs1, rs2 | 逻辑左移(低位补零) | rd = rs1 << (rs2[4:0]) (RV32I,取低5位)rd = rs1 << (rs2[5:0]) (RV64I,取低6位) | RV32I / RV64I |
SLLI | slli rd, rs1, shamt | 立即数逻辑左移 | rd = rs1 << shamt (shamt范围:RV32I为 0–31,RV64I为 0–63) | RV32I / RV64I |
SLLW | sllw rd, rs1, rs2 | 32位逻辑左移(RV64I,低32位操作) | rd = SignExt((rs1[31:0] << rs2[4:0])) | RV64I |
SLLIW | slliw rd, rs1, shamt | 32位立即数逻辑左移(RV64I) | rd = SignExt((rs1[31:0] << shamt)[31:0]) (shamt范围:0–31) | RV64I |
逻辑右移 | ||||
SRL | srl rd, rs1, rs2 | 逻辑右移(高位补零) | rd = rs1 >> (rs2[4:0]) (RV32I)rd = rs1 >> (rs2[5:0]) (RV64I) | RV32I / RV64I |
SRLI | srli rd, rs1, shamt | 立即数逻辑右移 | rd = rs1 >> shamt | RV32I / RV64I |
SRLW | srlw rd, rs1, rs2 | 32位逻辑右移(RV64I,低32位操作) | rd = SignExt((rs1[31:0] >> rs2[4:0])) | RV64I |
SRLIW | srliw rd, rs1, shamt | 32位立即数逻辑右移(RV64I) | rd = SignExt((rs1[31:0] >> shamt)[31:0]) (shamt范围:0–31) | RV64I |
算术右移 | ||||
SRA | sra rd, rs1, rs2 | 算术右移(高位补符号位) | rd = rs1 >>> (rs2[4:0]) (RV32I)rd = rs1 >>> (rs2[5:0]) (RV64I) | RV32I / RV64I |
SRAI | srai rd, rs1, shamt | 立即数算术右移 | rd = rs1 >>> shamt | RV32I / RV64I |
SRAW | sraw rd, rs1, rs2 | 32位算术右移(RV64I,低32位操作) | rd = SignExt((rs1[31:0] >>> rs2[4:0])) | RV64I |
SRAIW | sraiw rd, rs1, shamt | 32位立即数算术右移(RV64I) | rd = SignExt((rs1[31:0] >>> shamt)[31:0]) (shamt范围:0–31) | RV64I |
3.4 逻辑指令
逻辑指令用于对寄存器中的数据进行按位操作,分为以下两类:
- 1.寄存器-寄存器操作:两个寄存器之间的按位运算。
- 2.寄存器-立即数操作:寄存器与符号扩展后的立即数进行按位运算。
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
按位与操作 | ||||
AND | and rd, rs1, rs2 | 按位与 | rd = rs1 & rs2 | RV32I / RV64Ity-reference |
ANDI | andi rd, rs1, imm | 立即数按位与(符号扩展立即数) | rd = rs1 & SignExt(imm) | RV32I / RV64Ity-reference |
按位或操作 | ||||
OR | or rd, rs1, rs2 | 按位或 | `rd = rs1 | rs2` |
ORI | ori rd, rs1, imm | 立即数按位或(符号扩展立即数) | `rd = rs1 | SignExt(imm)` |
按位异或操作 | ||||
XOR | xor rd, rs1, rs2 | 按位异或 | rd = rs1 ^ rs2 | RV32I / RV64Ity-reference |
XORI | xori rd, rs1, imm | 立即数按位异或(符号扩展立即数) | rd = rs1 ^ SignExt(imm) | RV32I / RV64Ity-reference |
伪指令:
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
NOT | not rd, rs | 按位取反(rd = ~rs) | xori rd, rs, -1 | RV32I / RV64I |
3.5 比较-置位指令
指令根据两个操作数的比较结果设置目标寄存器的值为 1 或 0,用于条件判断和逻辑控制,支持有符号和无符号比较。
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
有符号比较 | ||||
SLT | slt rd, rs1, rs2 | 有符号比较:若 rs1 < rs2,则 rd = 1,否则 rd = 0 | rd = (rs1 < rs2) ? 1 : 0 (有符号比较) | RV32I / RV64Ity-reference |
SLTI | slti rd, rs1, imm | 有符号立即数比较:若 rs1 < SignExt(imm),则 rd = 1 | rd = (rs1 < SignExt(imm)) ? 1 : 0 | RV32I / RV64Ity-reference |
无符号比较 | ||||
SLTU | sltu rd, rs1, rs2 | 无符号比较:若 rs1 < rs2,则 rd = 1 | rd = (rs1 < rs2) ? 1 : 0 (无符号比较) | RV32I / RV64Ity-reference |
SLTIU | sltiu rd, rs1, imm | 无符号立即数比较(立即数符号扩展后按无符号比较):若 rs1 < SignExt(imm),则 rd = 1 | rd = (rs1 < SignExt(imm)) ? 1 : 0 (无符号比较) | RV32I / RV64Ity-reference |
伪指令:
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
零值判断 | ||||
SEQZ | seqz rd, rs | 若 rs == 0,则 rd = 1,否则 0 | sltiu rd, rs, 1 | RV32I / RV64I |
SNEZ | snez rd, rs | 若 rs ≠ 0,则 rd = 1,否则 0 | sltu rd, x0, rs | RV32I / RV64I |
符号判断 | ||||
SLTZ | sltz rd, rs | 若 rs < 0(有符号),则 rd = 1 | slt rd, rs, x0 | RV32I / RV64I |
SGTZ | sgtz rd, rs | 若 rs > 0(有符号),则 rd = 1 | slt rd, x0, rs | RV32I / RV64I |
非零符号判断 | ||||
SLEZ | slez rd, rs | 若 rs ≤ 0(有符号),则 rd = 1 | slt rd, x0, rs → xori rd, rd, 1 | RV32I / RV64I |
SGEZ | sgez rd, rs | 若 rs ≥ 0(有符号),则 rd = 1 | slt rd, rs, x0 → xori rd, rd, 1 | RV32I / RV64I |
3.6 分支指令
分支指令用于控制程序流程,根据条件或地址跳转执行目标代码,均为 B-Type 或 J-Type 格式。
条件分支指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
BEQ | beq rs1, rs2, offset | 若 rs1 == rs2,跳转到 PC + offset | if (rs1 == rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BNE | bne rs1, rs2, offset | 若 rs1 ≠ rs2,跳转到 PC + offset | if (rs1 != rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BLT | blt rs1, rs2, offset | 若 rs1 < rs2(有符号),跳转 | if (rs1 < rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BGE | bge rs1, rs2, offset | 若 rs1 ≥ rs2(有符号),跳转 | if (rs1 >= rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BLTU | bltu rs1, rs2, offset | 若 rs1 < rs2(无符号),跳转 | if (rs1 < rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BGEU | bgeu rs1, rs2, offset | 若 rs1 ≥ rs2(无符号),跳转 | if (rs1 >= rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
条件分支伪指令
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
BEQZ | beqz rs, offset | 若 rs == 0,跳转到 offset | beq rs, x0, offset | RV32I / RV64I |
BNEZ | bnez rs, offset | 若 rs ≠ 0,跳转到 offset | bne rs, x0, offset | RV32I / RV64I |
BGT | bgt rs1, rs2, offset | 若 rs1 > rs2(有符号),跳转 | blt rs2, rs1, offset | RV32I / RV64I |
BGTU | bgtu rs1, rs2, offset | 若 rs1 > rs2(无符号),跳转 | bltu rs2, rs1, offset | RV32I / RV64I |
BLE | ble rs1, rs2, offset | 若 rs1 ≤ rs2(有符号),跳转 | bge rs2, rs1, offset | RV32I / RV64I |
BLEU | bleu rs1, rs2, offset | 若 rs1 ≤ rs2(无符号),跳转 | bgeu rs2, rs1, offset | RV32I / RV64I |
3.7 跳转指令
跳转指令用于改变程序的执行流程,使程序能够跳转到代码中的其他位置执行
无条件跳转指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
JAL | jal rd, offset | 跳转到 PC + offset,并将返回地址存入 rd | rd = PC + 4; PC += SignExt(offset << 1) | RV32I / RV64I |
JALR | jalr rd, offset(rs1) | 跳转到 rs1 + offset,存入返回地址 | rd = PC + 4; PC = (rs1 + SignExt(offset)) & ~1 | RV32I / RV64I |
无条件跳转伪指令
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
J | j offset | 无条件跳转到 offset | jal x0, offset | RV32I / RV64I |
JR | jr rs | 跳转到 rs 指向的地址 | jalr x0, 0(rs) | RV32I / RV64I |
RET | ret | 从函数返回(跳转到 ra 地址) | jalr x0, 0(ra) | RV32I / RV64I |
3.8 同步指令
同步指令用于处理内存访问顺序控制,确保数据一致性和并发安全。
内存屏障指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
FENCE | fence pred, succ | 内存屏障(控制访存顺序) | 确保 pred 操作在 succ 操作前完成 (pred/succ 可以为 r(读)、w(写)、i(指令流)) | RV32I / RV64I |
FENCE.I | fence.i | 指令流同步屏障 | 确保后续指令看到此前所有指令的修改(用于自修改代码) | RV32I / RV64I) |
3.9 环境指令
环境指令用于系统调用、调试、中断处理等特权级操作,通常需在特定权限模式下执行。
系统调用与异常处理指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
ECALL | ecall | 触发环境调用(系统调用/异常) | 根据当前模式跳转到异常处理程序 | RV32I / RV64I |
EBREAK | ebreak | 触发断点异常(用于调试) | 进入调试模式或触发异常处理 | RV32I / RV64I |
中断返回指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
MRET | mret | 从机器模式异常返回 | PC = MEPC; Privilege = MPP | RV32I / RV64I |
SRET | sret | 从监管者模式异常返回 | PC = SEPC; Privilege = SPP | RV32I / RV64I |
URET | uret | 从用户模式异常返回 | PC = UEPC | RV32I / RV64I |
等待与暂停指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
WFI | wfi | 等待中断(暂停执行直至中断发生) | 暂停 CPU 直至中断或事件唤醒 | RV32I / RV64I ) |
3.10 控制状态寄存器指令
指令用于读写处理器的控制状态寄存器(如中断配置、计数器、特权模式设置等),支持原子操作和位操作,适用于系统编程和特权级管理。
CSR 读写指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
CSRRW | csrrw rd, csr, rs1 | 将 rs1 写入 CSR,原值存入 rd | t = CSR[csr]; CSR[csr] = rs1; rd = t | RV32I / RV64I |
CSRRS | csrrs rd, csr, rs1 | 将 rs1 对应位设为 1,原值存入 rd | `t = CSR[csr]; CSR[csr] | = rs1; rd = t` |
CSRRC | csrrc rd, csr, rs1 | 将 rs1 对应位清 0,原值存入 rd | t = CSR[csr]; CSR[csr] &= ~rs1; rd = t | RV32I / RV64I |
CSRRWI | csrrwi rd, csr, imm | 将 5 位立即数写入 CSR | t = CSR[csr]; CSR[csr] = imm; rd = t | RV32I / RV64I |
CSRRSI | csrrsi rd, csr, imm | 将立即数对应位置 1 | `t = CSR[csr]; CSR[csr] | = imm; rd = t` |
CSRRCI | csrrci rd, csr, imm | 将立即数对应位清 0 | t = CSR[csr]; CSR[csr] &= ~imm; rd = t | RV32I / RV64I |
CSR 伪指令
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
CSRR | csrr rd, csr | 读取 CSR 的值到寄存器 | csrrs rd, csr, x0 (读 CSR,不修改) | RV32I / RV64I |
CSRW | csrw csr, rs | 将寄存器的值写入 CSR | csrrw x0, csr, rs (丢弃原值,仅写入) | RV32I / RV64I |
CSRS | csrs csr, rs | 设置 CSR 中由 rs 指定的位 | csrrs x0, csr, rs (按位或,不保存结果) | RV32I / RV64I |
CSRC | csrc csr, rs | 清除 CSR 中由 rs 指定的位 | csrrc x0, csr, rs (按位与取反,不保存结果) | RV32I / RV64I |
CSRWI | csrwi csr, imm | 将 5 位立即数写入 CSR | csrrwi x0, csr, imm | RV32I / RV64I |
CSRSI | csrsi csr, imm | 设置 CSR 中由立即数指定的位 | csrrsi x0, csr, imm | RV32I / RV64I |
CSRCI | csrci csr, imm | 清除 CSR 中由立即数指定的位 | csrrci x0, csr, imm | RV32I / RV64I |
4 RVM指令集
RVM 扩展指令分为 乘法指令 和 除法/取余指令,支持有符号和无符号操作,并区分 RV32 和 RV64 的差异。
乘法指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
MUL | mul rd, rs1, rs2 | 乘法(低32/64位结果) | rd = (rs1 * rs2)[31:0] (RV32)rd = rs1 * rs2 (RV64) | RV32M / RV64M |
MULH | mulh rd, rs1, rs2 | 有符号乘法(高32/64位结果) | rd = (rs1 * rs2)[63:32] (RV32)rd = (rs1 * rs2)[127:64] (RV64) | RV32M / RV64M |
MULHU | mulhu rd, rs1, rs2 | 无符号乘法(高32/64位结果) | 同上,操作数为无符号数 | RV32M / RV64M |
MULHSU | mulhsu rd, rs1, rs2 | 有符号-无符号乘法(高32/64位结果) | rs1 有符号,rs2 无符号 | RV32M / RV64M |
MULW | mulw rd, rs1, rs2 | 32位乘法(结果符号扩展至64位) | rd = SignExt((rs1[31:0] * rs2[31:0])) | RV64M |
除法/取余指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
DIV | div rd, rs1, rs2 | 有符号除法(商) | rd = rs1 / rs2 (向零舍入) | RV32M / RV64M |
DIVU | divu rd, rs1, rs2 | 无符号除法(商) | rd = rs1 / rs2 | RV32M / RV64M |
REM | rem rd, rs1, rs2 | 有符号取余(余数) | rd = rs1 % rs2 (符号与 rs1 相同) | RV32M / RV64M |
REMU | remu rd, rs1, rs2 | 无符号取余(余数) | rd = rs1 % rs2 | RV32M / RV64M |
DIVW | divw rd, rs1, rs2 | 32位有符号除法(符号扩展至64位) | rd = SignExt((rs1[31:0] / rs2[31:0])) | RV64M |
DIVUW | divuw rd, rs1, rs2 | 32位无符号除法(零扩展至64位) | rd = ZeroExt((rs1[31:0] / rs2[31:0])) | RV64M |
REMW | remw rd, rs1, rs2 | 32位有符号取余(符号扩展至64位) | rd = SignExt((rs1[31:0] % rs2[31:0])) | RV64M |
REMUW | remuw rd, rs1, rs2 | 32位无符号取余(零扩展至64位) | rd = ZeroExt((rs1[31:0] % rs2[31:0])) | RV64M |
5 RVFD指令集
5.1 访存指令
指令用于在内存和浮点寄存器(f0-f31)之间传输单精度(F 扩展)或双精度(D 扩展)浮点数据:
浮点加载和存储指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
FLW | flw fd, offset(rs1) | 从内存加载单精度浮点数到浮点寄存器 | fd = F32(Mem[rs1 + offset]) | RV32F / RV64F |
FSW | fsw fs, offset(rs1) | 将单精度浮点数从浮点寄存器存入内存 | Mem[rs1 + offset] = F32(fs) | RV32F / RV64F |
FLD | fld fd, offset(rs1) | 从内存加载双精度浮点数到浮点寄存器 | fd = F64(Mem[rs1 + offset]) | RV64D |
FSD | fsd fs, offset(rs1) | 将双精度浮点数从浮点寄存器存入内存 | Mem[rs1 + offset] = F64(fs) | RV64D |
5.2 算术指令
算术指令用于执行各种数学运算,如加法、减法、乘法、除法等。当涉及到浮点数时,这些操作变得更为复杂,因为它们需要处理指数和尾数部分
基本算术指令
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
加法 | FADD.S | fadd.s fd, fs1, fs2 | 单精度浮点加法 | fd = fs1 + fs2 | RV32F / RV64F |
FADD.D | fadd.d fd, fs1, fs2 | 双精度浮点加法 | fd = fs1 + fs2 | RV64D | |
减法 | FSUB.S | fsub.s fd, fs1, fs2 | 单精度浮点减法 | fd = fs1 - fs2 | RV32F / RV64F |
FSUB.D | fsub.d fd, fs1, fs2 | 双精度浮点减法 | fd = fs1 - fs2 | RV64D | |
乘法 | FMUL.S | fmul.s fd, fs1, fs2 | 单精度浮点乘法 | fd = fs1 * fs2 | RV32F / RV64F |
FMUL.D | fmul.d fd, fs1, fs2 | 双精度浮点乘法 | fd = fs1 * fs2 | RV64D | |
除法 | FDIV.S | fdiv.s fd, fs1, fs2 | 单精度浮点除法 | fd = fs1 / fs2 | RV32F / RV64F |
FDIV.D | fdiv.d fd, fs1, fs2 | 双精度浮点除法 | fd = fs1 / fs2 | RV64D | |
平方根 | FSQRT.S | fsqrt.s fd, fs1 | 单精度浮点平方根 | fd = sqrt(fs1) | RV32F / RV64F |
FSQRT.D | fsqrt.d fd, fs1 | 双精度浮点平方根 | fd = sqrt(fs1) | RV64D | |
最小值 | FMIN.S | fmin.s fd, fs1, fs2 | 单精度浮点最小值 | fd = min(fs1, fs2) | RV32F / RV64F |
FMIN.D | fmin.d fd, fs1, fs2 | 双精度浮点最小值 | fd = min(fs1, fs2) | RV64D | |
最大值 | FMAX.S | fmax.s fd, fs1, fs2 | 单精度浮点最大值 | fd = max(fs1, fs2) | RV32F / RV64F |
FMAX.D | fmax.d fd, fs1, fs2 | 双精度浮点最大值 | fd = max(fs1, fs2) | RV64D |
5.3 RVFD 乘加指令
指令用于执行 乘加融合运算(Fused Multiply-Add, FMA),即在一个操作中完成乘法和加法,通常具有更高的精度和性能
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
单精度乘加 | FMADD.S | fmadd.s fd, fs1, fs2, fs3 | 单精度浮点乘加 | fd = (fs1 * fs2) + fs3 | RV32F / RV64F |
单精度乘减 | FMSUB.S | fmsub.s fd, fs1, fs2, fs3 | 单精度浮点乘减 | fd = (fs1 * fs2) - fs3 | RV32F / RV64F |
单精度负乘加 | FNMADD.S | fnmadd.s fd, fs1, fs2, fs3 | 单精度浮点负乘加 | fd = -((fs1 * fs2) + fs3) | RV32F / RV64F |
单精度负乘减 | FNMSUB.S | fnmsub.s fd, fs1, fs2, fs3 | 单精度浮点负乘减 | fd = -((fs1 * fs2) - fs3) | RV32F / RV64F |
双精度乘加 | FMADD.D | fmadd.d fd, fs1, fs2, fs3 | 双精度浮点乘加 | fd = (fs1 * fs2) + fs3 | RV64D |
双精度乘减 | FMSUB.D | fmsub.d fd, fs1, fs2, fs3 | 双精度浮点乘减 | fd = (fs1 * fs2) - fs3 | RV64D |
双精度负乘加 | FNMADD.D | fnmadd.d fd, fs1, fs2, fs3 | 双精度浮点负乘加 | fd = -((fs1 * fs2) + fs3) | RV64D |
双精度负乘减 | FNMSUB.D | fnmsub.d fd, fs1, fs2, fs3 | 双精度浮点负乘减 | fd = -((fs1 * fs2) - fs3) | RV64D |
5.4 RVFD传送指令
指令用于在 浮点寄存器 和 整数寄存器 之间传输数据,或在不同浮点寄存器之间复制数据
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
浮点到整数 | FMV.X.S | fmv.x.s rd, fs1 | 将单精度浮点数转为整数表示 | rd = fs1 (按位复制) | RV32F / RV64F |
浮点到整数 | FMV.X.D | fmv.x.d rd, fs1 | 将双精度浮点数转为整数表示 | rd = fs1 (按位复制) | RV64D |
整数到浮点 | FMV.S.X | fmv.s.x fd, rs1 | 将整数表示转为单精度浮点数 | fd = rs1 (按位复制) | RV32F / RV64F |
整数到浮点 | FMV.D.X | fmv.d.x fd, rs1 | 将整数表示转为双精度浮点数 | fd = rs1 (按位复制) | RV64D |
5.5 RVFD 转换指令
分两类归纳:浮点寄存器间传送 和 浮点与整数寄存器间传送,涵盖符号操作、位模式复制及特殊值处理
浮点与整数之间的转换
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
浮点 → 整数 | FCVT.W.S | fcvt.w.s rd, fs1 | 单精度浮点转为 32 位有符号整数 | rd = (int32_t)fs1 | RV32F / RV64F |
FCVT.WU.S | fcvt.wu.s rd, fs1 | 单精度浮点转为 32 位无符号整数 | rd = (uint32_t)fs1 | RV32F / RV64F | |
FCVT.L.S | fcvt.l.s rd, fs1 | 单精度浮点转为 64 位有符号整数 | rd = (int64_t)fs1 | RV64F | |
FCVT.LU.S | fcvt.lu.s rd, fs1 | 单精度浮点转为 64 位无符号整数 | rd = (uint64_t)fs1 | RV64F | |
FCVT.W.D | fcvt.w.d rd, fs1 | 双精度浮点转为 32 位有符号整数 | rd = (int32_t)fs1 | RV64D | |
FCVT.WU.D | fcvt.wu.d rd, fs1 | 双精度浮点转为 32 位无符号整数 | rd = (uint32_t)fs1 | RV64D | |
FCVT.L.D | fcvt.l.d rd, fs1 | 双精度浮点转为 64 位有符号整数 | rd = (int64_t)fs1 | RV64D | |
FCVT.LU.D | fcvt.lu.d rd, fs1 | 双精度浮点转为 64 位无符号整数 | rd = (uint64_t)fs1 | RV64D | |
整数 → 浮点 | FCVT.S.W | fcvt.s.w fd, rs1 | 32 位有符号整数转为单精度浮点 | fd = (float)rs1 | RV32F / RV64F |
FCVT.S.WU | fcvt.s.wu fd, rs1 | 32 位无符号整数转为单精度浮点 | fd = (float)rs1 | RV32F / RV64F | |
FCVT.S.L | fcvt.s.l fd, rs1 | 64 位有符号整数转为单精度浮点 | fd = (float)rs1 | RV64F | |
FCVT.S.LU | fcvt.s.lu fd, rs1 | 64 位无符号整数转为单精度浮点 | fd = (float)rs1 | RV64F | |
FCVT.D.W | fcvt.d.w fd, rs1 | 32 位有符号整数转为双精度浮点 | fd = (double)rs1 | RV64D | |
FCVT.D.WU | fcvt.d.wu fd, rs1 | 32 位无符号整数转为双精度浮点 | fd = (double)rs1 | RV64D | |
FCVT.D.L | fcvt.d.l fd, rs1 | 64 位有符号整数转为双精度浮点 | fd = (double)rs1 | RV64D | |
FCVT.D.LU | fcvt.d.lu fd, rs1 | 64 位无符号整数转为双精度浮点 | fd = (double)rs1 | RV64D |
浮点精度之间的转换
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
单精度 ↔ 双精度 | FCVT.S.D | fcvt.s.d fd, fs1 | 双精度浮点转为单精度浮点 | fd = (float)fs1 | RV64D |
单精度 ↔ 双精度 | FCVT.D.S | fcvt.d.s fd, fs1 | 单精度浮点转为双精度浮点 | fd = (double)fs1 | RV64D |
5.6 RVFD 符号注入指令
指令用于将 整数立即数 或 整数寄存器值 注入到浮点寄存器中,通常用于快速构造浮点常数或特殊值(如 NaN、无穷大)
单精度浮点注入指令
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
符号复制 | FSGNJ.S | fsgnj.s fd, fs1, fs2 | 复制数值,符号位取自 fs2 | fd = {fs2[31], fs1[30:0]} | RV32F / RV64F |
符号取反 | FSGNJN.S | fsgnjn.s fd, fs1, fs2 | 复制数值,符号位取反自 fs2 | fd = {~fs2[31], fs1[30:0]} | RV32F / RV64F |
符号取绝对值 | FSGNJX.S | fsgnjx.s fd, fs1, fs2 | 复制数值,符号位异或(取绝对值) | fd = {fs1[31] ^ fs2[31], fs1[30:0]} | RV32F / RV64F |
双精度浮点注入指令
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
符号复制 | FSGNJ.D | fsgnj.d fd, fs1, fs2 | 复制数值,符号位取自 fs2 | fd = {fs2[63], fs1[62:0]} | RV64D |
符号取反 | FSGNJN.D | fsgnjn.d fd, fs1, fs2 | 复制数值,符号位取反自 fs2 | fd = {~fs2[63], fs1[62:0]} | RV64D |
符号取绝对值 | FSGNJX.D | fsgnjx.d fd, fs1, fs2 | 复制数值,符号位异或(取绝对值) | fd = {fs1[63] ^ fs2[63], fs1[62:0]} | RV64D |
伪指令
指令类型 | 伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|---|
单精度浮点注入 | FABS.S | fabs.s fd, fs | 单精度浮点取绝对值 | fsgnjx.s fd, fs, fs | RV32F / RV64F |
FMV.S | fmv.s fd, fs | 单精度浮点复制 | fsgnj.s fd, fs, fs | RV32F / RV64F | |
FNEG.S | fneg.s fd, fs | 单精度浮点取反 | fsgnjn.s fd, fs, fs | RV32F / RV64F |
指令类型 | 伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|---|
双精度浮点注入 | FABS.D | fabs.d fd, fs | 双精度浮点取绝对值 | fsgnjx.d fd, fs, fs | RV64D |
FMV.D | fmv.d fd, fs | 双精度浮点复制 | fsgnj.d fd, fs, fs | RV64D | |
FNEG.D | fneg.d fd, fs | 双精度浮点取反 | fsgnjn.d fd, fs, fs | RV64D |
5.7 RVFD 比较指令
指令用于比较两个浮点数的值,并将比较结果写入整数寄存器,支持 相等、小于 和 小于等于 三种比较操作
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
相等比较 | FEQ.S | feq.s rd, fs1, fs2 | 单精度浮点相等比较 | rd = (fs1 == fs2) ? 1 : 0 | RV32F / RV64F |
FEQ.D | feq.d rd, fs1, fs2 | 双精度浮点相等比较 | rd = (fs1 == fs2) ? 1 : 0 | RV64D | |
小于比较 | FLT.S | flt.s rd, fs1, fs2 | 单精度浮点小于比较 | rd = (fs1 < fs2) ? 1 : 0 | RV32F / RV64F |
FLT.D | flt.d rd, fs1, fs2 | 双精度浮点小于比较 | rd = (fs1 < fs2) ? 1 : 0 | RV64D | |
小于等于比较 | FLE.S | fle.s rd, fs1, fs2 | 单精度浮点小于等于比较 | rd = (fs1 <= fs2) ? 1 : 0 | RV32F / RV64F |
FLE.D | fle.d rd, fs1, fs2 | 双精度浮点小于等于比较 | rd = (fs1 <= fs2) ? 1 : 0 | RV64D |
5.8 RVFD 分类指令
指令用于检查浮点数的类别(如正无穷、负零、NaN 等),并将结果写入整数寄存器,适用于浮点数的异常处理和特殊值检测
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
浮点分类 | 单精度分类 | fclass.s rd, fs1 | 单精度浮点分类 | rd = classify(fs1) | RV32F / RV64F |
浮点分类 | 双精度分类 | fclass.d rd, fs1 | 双精度浮点分类 | rd = classify(fs1) | RV64D |
5.9 RVFD 配置指令
指令用于配置和管理浮点单元的状态,包括 舍入模式、异常标志 和 浮点控制状态寄存器(fcsr) 的操作
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
浮点控制状态寄存器(fcsr)操作 | |||||
读取 fcsr | FRCSR | frcsr rd | 读取 fcsr 的值到整数寄存器 | rd = fcsr | RV32F / RV64F |
写入 fcsr | FSCSR | fscsr rd, rs | 将整数寄存器的值写入 fcsr | fcsr = rs | RV32F / RV64F |
交换 fcsr | FSRCS | fscsr rd, rs | 交换 fcsr 和整数寄存器的值 | t = fcsr; fcsr = rs; rd = t | RV32F / RV64F |
舍入模式配置 | |||||
读取舍入模式 | FRRM | frrm rd | 读取舍入模式到整数寄存器 | rd = fcsr[7:5] | RV32F / RV64F |
写入舍入模式 | FSRM | fsrm rd, rs | 将整数寄存器的值写入舍入模式 | fcsr[7:5] = rs[2:0] | RV32F / RV64F |
交换舍入模式 | FSRRM | fsrrm rd, rs | 交换舍入模式和整数寄存器的值 | t = fcsr[7:5]; fcsr[7:5] = rs[2:0]; rd = t | RV32F / RV64F |
异常标志操作 | |||||
读取异常标志 | FFLAGS | fflags rd | 读取异常标志到整数寄存器 | rd = fcsr[4:0] | RV32F / RV64F |
写入异常标志 | FSFLAGS | fsflags rd, rs | 将整数寄存器的值写入异常标志 | fcsr[4:0] = rs[4:0] | RV32F / RV64F |
交换异常标志 | FSRFLAGS | fsrflags rd, rs | 交换异常标志和整数寄存器的值 | t = fcsr[4:0]; fcsr[4:0] = rs[4:0]; rd = t | RV32F / RV64F |
6 RVA指令集
RVA(Atomic Operations)扩展为 RISC-V 提供了硬件支持的原子操作指令,用于在多线程或多核环境中实现 原子内存访问 和 同步操作,确保数据一致性和并发安全。
加载保留与条件存储指令
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
加载保留 | LR.W | lr.w rd, (rs1) | 加载保留(原子加载字,标记内存地址) | rd = Mem[rs1]; Reserve rs1 | RV32A / RV64A |
LR.D | lr.d rd, (rs1) | 加载保留(原子加载双字) | rd = Mem[rs1]; Reserve rs1 | RV64A | |
条件存储 | SC.W | sc.w rd, rs2, (rs1) | 条件存储(若地址未被修改,存储字) | if (Reserve rs1 still valid) { Mem[rs1] = rs2; rd = 0 } else { rd = 1 } | RV32A / RV64A |
SC.D | sc.d rd, rs2, (rs1) | 条件存储(若地址未被修改,存储双字) | if (Reserve rs1 still valid) { Mem[rs1] = rs2; rd = 0 } else { rd = 1 } | RV64A |
原子内存操作指令
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
原子加 | AMOADD.W | amoadd.w rd, rs2, (rs1) | 原子加并返回原值 | rd = Mem[rs1]; Mem[rs1] += rs2 | RV32A / RV64A |
AMOADD.D | amoadd.d rd, rs2, (rs1) | 原子加并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] += rs2 | RV64A | |
原子交换 | AMOSWAP.W | amoswap.w rd, rs2, (rs1) | 原子交换并返回原值 | rd = Mem[rs1]; Mem[rs1] = rs2 | RV32A / RV64A |
AMOSWAP.D | amoswap.d rd, rs2, (rs1) | 原子交换并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] = rs2 | RV64A | |
原子按位与 | AMOAND.W | amoand.w rd, rs2, (rs1) | 原子按位与并返回原值 | rd = Mem[rs1]; Mem[rs1] &= rs2 | RV32A / RV64A |
AMOAND.D | amoand.d rd, rs2, (rs1) | 原子按位与并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] &= rs2 | RV64A | |
原子按位或 | AMOOR.W | amoor.w rd, rs2, (rs1) | 原子按位或并返回原值 | `rd = Mem[rs1]; Mem[rs1] | = rs2` |
AMOOR.D | amoor.d rd, rs2, (rs1) | 原子按位或并返回原值(双字) | `rd = Mem[rs1]; Mem[rs1] | = rs2` | |
原子按位异或 | AMOXOR.W | amoxor.w rd, rs2, (rs1) | 原子按位异或并返回原值 | rd = Mem[rs1]; Mem[rs1] ^= rs2 | RV32A / RV64A |
AMOXOR.D | amoxor.d rd, rs2, (rs1) | 原子按位异或并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] ^= rs2 | RV64A | |
原子最大值 | AMOMAX.W | amomax.w rd, rs2, (rs1) | 原子有符号最大值并返回原值 | rd = Mem[rs1]; Mem[rs1] = max(rd, rs2) | RV32A / RV64A |
AMOMAX.D | amomax.d rd, rs2, (rs1) | 原子有符号最大值并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] = max(rd, rs2) | RV64A | |
原子无符号最大值 | AMOMAXU.W | amomaxu.w rd, rs2, (rs1) | 原子无符号最大值并返回原值 | rd = Mem[rs1]; Mem[rs1] = maxu(rd, rs2) | RV32A / RV64A |
AMOMAXU.D | amomaxu.d rd, rs2, (rs1) | 原子无符号最大值并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] = maxu(rd, rs2) | RV64A | |
原子最小值 | AMOMIN.W | amomin.w rd, rs2, (rs1) | 原子有符号最小值并返回原值 | rd = Mem[rs1]; Mem[rs1] = min(rd, rs2) | RV32A / RV64A |
AMOMIN.D | amomin.d rd, rs2, (rs1) | 原子有符号最小值并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] = min(rd, rs2) | RV64A | |
原子无符号最小值 | AMOMINU.W | amominu.w rd, rs2, (rs1) | 原子无符号最小值并返回原值 | rd = Mem[rs1]; Mem[rs1] = minu(rd, rs2) | RV32A / RV64A |
AMOMINU.D | amominu.d rd, rs2, (rs1) | 原子无符号最小值并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] = minu(rd, rs2) | RV64A |
上面列举了RISC-V指令集,但实际上上面列举的指令集我很多也没用过,是按照spec总结了下,如有错误或者遗漏,还请各位大佬评论区指出。
参考
riscv-spec-20240411.pdf
一起学RISC-V汇编第5讲之常用指令及伪指令列表
RISC-V 常用汇编指令