RISC-V汇编学习(三)—— RV指令集

有了前两节对于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_lolui 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 移位指令

移位指令用于对寄存器中的数据进行位级左移或右移,分为以下两类:

    1. 寄存器移位:移位位数由另一个寄存器的低 5 位(RV32I)或低 6 位(RV64I)指定。
    1. 立即数移位:移位位数由指令中的立即数字段直接指定。
指令 格式 功能描述 操作(伪代码) 指令集
逻辑左移
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 常用汇编指令

相关推荐
leluckys20 小时前
swift -(5) 汇编分析结构体、类的内存布局
汇编
自不量力的A同学1 天前
香橙派首款高性能开源 RISC-V 开发板 OrangePi RV 即将开售
risc-v
乐鑫科技 Espressif1 天前
乐鑫打造全球首款 PSA Certified Level 2 RISC-V 芯片
esp32·risc-v·芯片·乐鑫科技
cheungxiongwei.com1 天前
ESP32-P4 支持哪些 RISC-V 汇编指令?
汇编·risc-v
国科安芯1 天前
RISC-V双核锁步高性能抗辐照MCU芯片技术解析与应用
单片机·嵌入式硬件·risc-v
charlie1145141913 天前
从0开始的操作系统手搓教程21:进程子系统的一个核心功能——简单的进程切换
汇编·学习·操作系统·线程·进程·手搓教程
凉、介3 天前
ARM 架构下 cache 一致性问题整理
linux·汇编·arm开发·学习·缓存·架构
老胖闲聊3 天前
Python Flask框架学习汇编
汇编·python·学习·flask
试试看1683 天前
汇编前置知识学习 第11-13天
汇编·学习·进制