一起学RISC-V汇编第5讲之常用指令及伪指令列表

一起学RISC-V汇编第5讲之常用指令及伪指令列表


这一篇介绍一下RISC-V常用的汇编指令,整理成表,便于查阅。

1 RISC-V指令命名

以slt指令为例,如下示意图:大括号{ }内列举了每组指令的所有变体,这些变体通过带下滑线的字母(单独的下划线_表示空字段),从左到右连接带下滑线的字母即可组成完整的指令集,比如slt意思是set less than,相当于是一种缩写,完整语句方便我们快速清晰的理解指令的作用。

下图表示:slt、slti、sltu、sltiu 这4条RVI指令。

指令示意:

注意:后续指令示意中的加粗部分表示RV64指令集,将RV64与RV32放在一起可以看出RV64只需在RV32的基础上加入少数指令:32 位的指令字(word),双字(doubleword)和长字(long)版本。

后续指令列表中使用了一些符号,这里提前进行说明:

符号 说明
寄存器 源寄存器rs1, rs2 目的寄存器 rd
符号扩展 RV32I/RV64I 的立即数总是进行符号扩展,sign-extend,使用sext()表示
内存访问 使用M()表示访问某处内存

下面列举如下指令集:

  • RVI(包括RV32I与RV64I)
  • RVM(包括RV32M与RV64M)
  • RVFD(包括RV32FD与RV64FD)
  • RVA(包括RV32A与RV64A)

2 RVI指令集

2.1 内存操作指令

指令示意:

RISC-V中访存指令唯一支持的寻址模式是将12位立即数符号扩展后与寄存器相加,即寄存器相对寻址,后面第7讲RISC-V的寻址模式。

RV32I/RV64I指令:

指令 类型 RV32I/RV64I 作用
lb I lb rd,offset(rs1) 取字节
x[rd] = sext( M[x[rs1] + sext(offset)][7:0] )
从地址 x[rs1] + sext(offset) 读取 1 字节,符号扩展后写入 x[rd]。
lh I lh rd,offset(rs1) 取半字
x[rd] = sext( M[x[rs1] + sext(offset)][15:0] )
从地址 x[rs1] + sext(offset) 读取 2 字节,符号扩展后写入 x[rd]。
lw I lw rd,offset(rs1) 取字
x[rd] = sext( M[x[rs1] + sext(offset)][31:0] )
从地址 x[rs1] + sext(offset) 读取 4 字节,写入 x[rd],在RV64I中要进行符号扩展。
lbu I lbu rd,offset(rs1) 取无符号字节
x[rd] = M[x[rs1] + sext(offset)][7:0]
从地址 x[rs1] + sext(offset) 读取 1 字节,0扩展后写入 x[rd]。
lhu I lhu rd,offset(rs1) 取无符号半字
x[rd] = M[x[rs1] + sext(offset)][15:0]
从地址 x[rs1] + sext(offset) 读取 2 字节,0扩展后写入 x[rd]。
sb S sb rs2,offset(rs1) 存字节
M[x[rs1] + sext(offset)] = x[rs2][7:0]
将x[rs2]的最低字节写入内存 x[rs1] + sext(offset) 处。
sh S sh rs2,offset(rs1) 存半字
M[x[rs1] + sext(offset)] = x[rs2][15:0]
将x[rs2]的最低2字节写入内存 x[rs1] + sext(offset) 处。
sw S sw rs2,offset(rs1) 存字
M[x[rs1] + sext(offset)] = x[rs2][31:0]
将x[rs2]的最低4字节写入内存 x[rs1] + sext(offset) 处。

RV64I指令:

指令 类型 RV64I 作用
ld I ld rd,offset(rs1) 取双字
x[rd] = M[x[rs1] + sext(offset)][63:0]
从地址 x[rs1] + sext(offset) 读取 8 字节,写入 x[rd]。
lwu I lwu rd,offset(rs1) 取无符号字
x[rd] = M[x[rs1] + sext(offset)][31:0]
从地址 x[rs1] + sext(offset) 读取 4 字节,0扩展后写入 x[rd]。
sd S sd rd,offset(rs1) 存双字
M[x[rs1] + sext(offset)] = x[rs2][63:0]
将x[rs2]中的8字节写入内存 x[rs1] + sext(offset) 处。

2.2 算术指令

指令示意:

RV32I/RV64I指令:

指令 类型 RV32I/RV64I 作用
add R add rd,rs1,rs2 加法
x[rd] = x[rs1] + x[rs2]
将 x[rs2] 与 x[rs1] 相加,结果写入 x[rd]。忽略算术溢出。
addi I addi rd,rs1,imm 加立即数
x[rd] = x[rs1] + sext(imm)
对 imm 符号扩展后与 x[rs1] 相加,结果写入 x[rd]。忽略算术溢出。
sub R sub rd,rs1,rs2 减法
x[rd] = x[rs1] - x[rs2]
将 x[rs1] 减去 x[rs2],结果写入 x[rd]。忽略算术溢出。

注意:RISC-V中没有SUBI指令,RVI的立即数总是进行符号扩展,因此它们也能表示负数,SUBI可以由ADDI来实现(减一个数等于加一个负数),故RVI中无须包含立即数版本的subi指令。

RV64I指令:

指令 类型 仅RV64I 作用
addw R addw rd,rs1,rs2 加字
x[rd] = sext( (x[rs1] + x[rs2])[31:0] )
将 x[rs2] 与 x[rs1] 相加,结果截为 32 位,符号扩展后写入 x[rd],忽略算术溢出。
addiw I addiw rd,rs1,imm 加立即数字
x[rd] = sext( (x[rs1] + sext(imm))[31:0] )
对 imm 符号扩展后与 x[rs1] 相加,结果截为 32 位,符号扩展后写入 x[rd],忽略算术溢出。
subw R subw rd,rs1,rs2 减字
x[rd] = sext( (x[rs1] - x[rs2])[31:0] )
将 x[rs1] 减去 x[rs2],结果截为 32 位,符号扩展后写入 x[rd]。忽略算术溢出。

伪指令:

指令 伪指令 实际指令 作用
mv mv rd,rs addi rd,rs,0 move指令,支持RV32I 和 RV64I
x[rd] = x[rs1]
将 x[rs1] 复制到 x[rd] 中。
nop nop addi x0,x0,0 空操作,支持 RV32I 和 RV64I
仅让 pc指向下一条指令。
neg neg rd, rs sub rd,x0,rs 取负,支持 RV32I 和 RV64I
x[rd] = -x[rs2]
将 x[rs2] 的相反数写入 x[rd]。
negw negw rd, rs subw rd,rs1,rs2 取负字,仅支持 RV64I
x[rd] = sext( (-x[rs2])[31:0] )
将 x[rs2] 的相反数截为 32 位,符号扩展后写入 x[rd]。
sext.w sext.w rd, rs addiw rd, rs, 0 符号扩展字,仅支持 RV64I
x[rd] = sext( x[rs1][31:0] )
将 x[rs1] 低 32 位的符号扩展结果写入 x[rd]

lui与auipc指令:

注意:有两条指令lui与auipc指令,不好归类,绿卡将其归到算术指令,这里也放到这一类吧。

指令示意:

指令 类型 RV32I/RV64I 作用
lui U lui rd, imm 装入高位立即数
x[rd] = sext( imm )<< 12
将 20 位 imm 符号扩展后左移 12 位,低 12 位置零,结果写入 x[rd]。
auipc U auipc rd, imm pc 加高位立即数
x[rd] = pc + (sext(imm)<< 12)
对 20 位 imm 符号扩展后左移 12 位,与 pc相加,结果写入 x[rd]。

伪指令:

指令 伪指令 实际指令 作用
li li rd,imm 多种指令序列 装入立即数,支持RV32I 和 RV64I
x[rd] = imm
使用尽可能少的指令将常量装入 x[rd]。
在 RV32I 中,它展开为 lui 和 addi组合;
在RV64I 中的展开结果较长:lui, addi, slli, addi, slli, addi, slli, addi
la la rd, symbol 多种指令序列 装入地址,支持RV32I 和 RV64I
x[rd] = &symbol
symbol 的地址装入 x[rd]。
当汇编位置无关代码时,它展开为对全局偏移量表(Global Offset Table)的读入操作:在 RV32I 中展开为 auipc rd, offsetHi 和 addi rd, rd, offsetLo
否则与lla等价
lla lla rd, symbol auipc rd, symbol[31:12]
addi rd, rd, symbol[11:0]
装入本地地址,支持RV32I 和 RV64I
x[rd] = &symbol
symbol 的地址装入 x[rd]。展开为 auipc rd, offsetHi 和 addi rd, rd, offsetLo

2.3 移位指令

指令示意:

RV32I/RV64I指令:

指令 类型 RV32I/RV64I 作用
sll R sll rd,rs1,rs2 逻辑左移
x[rd] = x[rs1] << x[rs2]
将 x[rs1] 左移 x[rs2] 位,空位补零,结果写入 x[rd]
x[rs2] 的低 5 位(在 RV64I 中是低 6 位)为移位位数,高位忽略。
slli I slli rd,rs1,shamt 逻辑左移立即数
x[rd] = x[rs1] << shamt
将 x[rs1] 左移 shamt 位,空位补零,结果写入 x[rd]
在 RV32I 中仅当 shamt[5]=0时该指令合法。
srl R srl rd,rs1,rs2 逻辑右移
x[rd] = x[rs1] >> x[rs2]
将 x[rs1] 右移 x[rs2] 位,空位补零,结果写入 x[rd]
x[rs2] 的低 5 位(在 RV64I 中是低 6 位)为移位位数,高位忽略。
srli I srli rd,rs1,shamt 逻辑右移立即数
x[rd] = x[rs1] >> shamt
将 x[rs1] 右移 shamt 位,空位补零,结果写入 x[rd]
在 RV32I 中,仅当 shamt[5]=0时该指令合法。
sra R sra rd,rs1,rs2 算术右移
x[rd] = x[rs1] >> x[rs2]
将 x[rs1] 右移 x[rs2] 位,空位用 x[rs1] 的最高位填充,结果写入 x[rd]
x[rs2] 的低 5 位(在 RV64I 中是低 6 位)为移位位数,高位忽略。
srai I srai rd,rs1,shamt 算术右移立即数
x[rd] = x[rs1] >> shamt
将 x[rs1] 右移 shamt 位,空位用 x[rs1] 的最高位填充,结果写入 x[rd]
在 RV32I 中,仅当 shamt[5]=0时该指令合法。

RV64I指令:

指令 类型 RV64I 作用
sllw R sllw rd,rs1,rs2 逻辑左移字
x[rd] = sext((x[rs1] << x[rs2][4:0])[31:0])
将 x[rs1] 左移 x[rs2] 位,空位补零,结果写入 x[rd]
x[rs2] 的低 5 位为移位位数,高位忽略。
slliw I slliw rd,rs1,shamt 逻辑左移立即数字
x[rd] = sext((x[rs1] << shamt)[31:0])
将 x[rs1] 左移 shamt 位,空位补零,结果截为 32 位,符号扩展后写入 x[rd]
仅当 shamt[5]=0时该指令合法。
srlw R srlw rd,rs1,rs2 逻辑右移字
x[rd] = sext(x[rs1][31:0] >>x[rs2][4:0])
将 x[rs1] 右移 x[rs2] 位,空位补零,符号扩展后写入 x[rd]
x[rs2] 的低 5 位为移位位数,高位忽略。
srliw I srliw rd,rs1,shamt 逻辑右移立即数
x[rd] = x[rs1] >> shamt
将 x[rs1] 右移 shamt 位,空位补零,结果写入 x[rd]
在 RV32I 中,仅当 shamt[5]=0时该指令合法。
sraw R sraw rd,rs1,rs2 算术右移字
x[rd] = sext(x[rs1][31:0] >> x[rs2][4:0])
将 x[rs1] 的低 32 位右移 x[rs2] 位,空位用 x[rs1][31] 填充,将 32 位结果符号扩展后写入 x[rd]
x[rs2] 的低 5 位为移位位数,高位忽略。
sraiw I sraiw rd,rs1,shamt 算术右移立即字
x[rd] = sext(x[rs1][31:0] >> shamt)
将 x[rs1] 的低 32 位右移 shamt 位,空位用 x[rs1][31] 填充,将 32 位结果符号扩展后写入 x[rd]
仅当 shamt[5]=0时该指令合法。

2.4 逻辑指令

指令示意:

RV32I/RV64I指令:

指令 类型 RV32I/RV64I 作用
xor R xor rd,rs1,rs2 异或
x[rd] = x[rs1] ^ x[rs2]
将 x[rs1] 和 x[rs2] 按位异或,结果写入 x[rd]
xori I xori rd,rs1,imm 异或立即数
x[rd] = x[rs1] ^ sext(imm)
将 x[rs1] 和符号扩展后的 imm 按位异或,结果写入 x[rd]。
or R or rd,rs1,rs2
x[rd] = x[rs1] | x[rs2]
将 x[rs1] 和 x[rs2] 按位或的结果写入 x[rd]
ori I ori rd,rs1,imm 或立即数
x[rd] = x[rs1] | sext(imm)
将 x[rs1] 和符号扩展后的 imm 按位或的结果写入 x[rd]。
and R and rd,rs1,rs2
x[rd] = x[rs1] & x[rs2]
将 x[rs1] 和 x[rs2] 的按位与结果写入 x[rd]
andi I andi rd,rs1,imm 与立即数
x[rd] = x[rs1] & sext(imm)
对 imm 符号扩展后和 x[rs1] 进行按位与,结果写入 x[rd]。

伪指令:

指令 伪指令 实际指令 作用
not not rd, rs1 xori rd, rs1, -1 取反,在 RV32I 和 RV64I 中
x[rd]=~x[rs1]
将 x[rs1] 按位取反后写入 x[rd]。
neg neg rd, rs2 sub rd, x0, rs2 取负,在 RV32I 和 RV64I 中
x[rd]=-x[rs2]
将 x[rs2] 的相反数写入 x[rd]
negw negw rd, rs2 subw rd, x0, rs2 取负,在 RV64I 中
x[rd] = sext((-x[rs2])[31:0])
将 x[rs2] 的相反数截为 32 位,符号扩展后写入 x[rd]

2.5 比较-置位指令

比较-置位指令指令本身并不直接涉及控制流的改变,但它经常配合分支指令使用。

指令示意:

RV32I/RV64I指令:

指令 类型 RV32I/RV64I 作用
slt R slt rd,rs1,rs2 小于则置位
x[rd] = x[rs1] < x[rs2]
比较 x[rs1] 和 x[rs2](视为补码),若 x[rs1] 更小,则向 x[rd] 写入 1,否则写入 0
slti I slti rd,rs1,imm 小于立即数则置位
x[rd] = x[rs1] < sext(imm)
比较 x[rs1] 和符号扩展后的 imm(视为补码),若 x[rs1] 更小,则向 x[rd] 写入 1,否则写入 0
sltu R sltu rd,rs1,rs2 无符号小于则置位
x[rd] = x[rs1] < x[rs2]
比较 x[rs1] 和 x[rs2](视为无符号数),若 x[rs1] 更小,则向 x[rd] 写入 1,否则写入 0
sltiu I sltiu rd,rs1,imm 小于无符号立即数则置位
x[rd] = x[rs1] < sext(imm)
比较 x[rs1] 和符号扩展后的 imm(视为无符号数),若 x[rs1] 更小,则向 x[rd] 写入 1,否则写入 0

伪指令:

指令 伪指令 实际指令 作用
seqz seqz rd, rs sltiu rd, rs, 1 等于零时置位,在 RV32I 和 RV64I 中
x[rd] = (x[rs1] == 0)
若 x[rs1] 等于 0,则向 x[rd] 写入 1,否则写入 0
snez snez rd, rs sltu rd, x0, rs 不等于零则置位,在 RV32I 和 RV64I 中
x[rd] = (x[rs2] != 0)
若 x[rs1] 不等于 0,则向 x[rd] 写入 1,否则写入 0
sltz sltz rd, rs slt rd, rs, x0 小于0则置位,在 RV32I 和 RV64I 中
x[rd] = x[rs1] < 0
若 x[rs1] 小于0,则向 x[rd] 写入 1,否则写入 0
sgtz sgtz rd, rs slt rd, x0, rs 大于0则置位,在 RV32I 和 RV64I 中
x[rd] = x[rs1] > 0
若 x[rs1] 大于0,则向 x[rd] 写入 1,否则写入 0

2.6 分支指令

指令示意:

RV32I/RV64I指令:

指令 类型 RV32I/RV64I 作用
beq B beq rs1,rs2,offset 相等时分支
if (rs1 == rs2) pc += sext(offset)
若 x[rs1] 和 x[rs2] 相等,将 pc 设为当前 pc 加上符号扩展后的 offset。
bne B bne rs1,rs2,offset 不等时分支
if (rs1 != rs2) pc += sext(offset)
若 x[rs1] 和 x[rs2] 不相等,将 pc 设为当前 pc 加上符号扩展后的 offset。
blt B blt rs1,rs2,offset 小于时分支
if (rs1 < rs2) pc += sext(offset)
若 x[rs1] 小于 x[rs2](补码比较),将 pc 设为当前 pc 加上符号扩展后的 offset。
bge B bge rs1,rs2,offset 大于等于时分支
if (rs1 >= rs2) pc += sext(offset)
若 x[rs1] 大于等于 x[rs2](补码比较),将 pc 设为当前 pc 加上符号扩展后的 offset。
bltu B bltu rs1,rs2,offset 无符号小于时分支
if (rs1 < rs2) pc += sext(offset)
若 x[rs1] 小于 x[rs2](无符号比较),将 pc 设为当前 pc 加上符号扩展后的 offset。
bgeu B bgeu rs1,rs2,offset 无符号大于等于时分支
if (rs1 >= rs2) pc += sext(offset)
若 x[rs1] 大于等于 x[rs2](无符号比较),将 pc 设为当前 pc 加上符号扩展后的 offset。

伪指令:

指令 伪指令 实际指令 作用
beqz beqz rs1, offset beq rs1,x0,offset 等于0时分支,在 RV32I 和 RV64I 中
if (rs1 == 0) pc += sext(offset)
若 x[rs1] 等于0,将 pc 设为当前 pc 加上符号扩展后的 offset。
bnez bnez rs1, offset bne rs1,x0,offset 不等于0时分支,在 RV32I 和 RV64I 中
if (rs1 != 0) pc += sext(offset)
若 x[rs1] 等于0,将 pc 设为当前 pc 加上符号扩展后的 offset。
bgez bgez rs1, offset bge rs1, x0, offset 大于等于0时分支,在 RV32I 和 RV64I 中
if (rs1 >=0) pc += sext(offset)
若 x[rs1] 大于等于0,将 pc 设为当前 pc 加上符号扩展后的 offset。
bgt bgt rs1, rs2, offset blt rs2, rs1, offset 大于时分支,在 RV32I 和 RV64I 中
if (rs1 > rs2) pc += sext(offset)
若 x[rs1] 大于x[rs2],(补码比较),将 pc 设为当前 pc 加上符号扩展后的 offset。
bgtu bgtu rs1, rs2, offset bltu rs2, rs1, offset 无符号大于时分支,在 RV32I 和 RV64I 中
if (rs1 > rs2) pc += sext(offset)
若 x[rs1] 大于x[rs2](无符号比较),将 pc 设为当前 pc 加上符号扩展后的 offset。
bgtz bgtz rs2, offset blt x0, rs2, offset 大于0时分支,在 RV32I 和 RV64I 中
if (rs2 > 0) pc += sext(offset)
若x[rs2] 大于0,(补码比较),将 pc 设为当前 pc 加上符号扩展后的 offset。
ble ble rs1, rs2, offset bge rs2, rs1, offset 小于等于时分支,在 RV32I 和 RV64I 中
if (rs1 <= rs2) pc += sext(offset)
若 x[rs1] 小于等于 x[rs2](补码比较),将 pc 设为当前 pc 加上符号扩展后的 offset。
bleu bleu rs1, rs2, offset bgeu rs2, rs1, offset 无符号小于等于时分支,在 RV32I 和 RV64I 中
if (rs1 <= rs2) pc += sext(offset)
若 x[rs1] 小于等于 x[rs2](无符号比较),将 pc 设为当前 pc 加上符号扩展后的 offset。
blez blez rs2, offset bge x0, rs2, offset 小于等于0时分支,在 RV32I 和 RV64I 中
if (rs2 <= 0) pc += sext(offset)
若 x[rs2] 小于0(补码比较),将 pc 设为当前 pc 加上符号扩展后的 offset。
bltz bltz rs1, offset blt rs1,x0,offset 小于0时分支,在 RV32I 和 RV64I 中
if (rs1 < 0) pc += sext(offset)
若 x[rs1] 小于0(补码比较),将 pc 设为当前 pc 加上符号扩展后的 offset。

2.7 跳转指令

指令示意:

RV32I/RV64I指令:

指令 类型 RV32I/RV64I 作用
jal J jal rd, offset 跳转并链接
x[rd] = pc+4; pc += sext(offset)
将下一条指令的地址(pc+4)写入 x[rd],然后将 pc 设为当前 pc 加上符号扩展后的
jalr I jalr rd,offset(rs1) 寄存器跳转并链接
t=pc+4; pc=(x[rs1]+sext(offset))&~1; x[rd]=t
将 pc 设为 x[rs1] + sext(offset),将跳转地址的最低位清零,并将原 pc+4 写入 x[rd]。若省略 rd,则默认为 x1

伪指令:

指令 伪指令 实际指令 作用
j j offset jal x0, offset 跳转,在 RV32I 和 RV64I 中
pc += sext(offset)
将 pc 设为当前 pc 加上符号扩展后的 offset。
jr jr rs1 jalr x0, 0(rs1) 寄存器跳转,在 RV32I 和 RV64I 中
pc = x[rs1]
将 pc 设为 x[rs1]。展开为 jalr x0, 0(rs1)
ret ret jalr x0, 0(x1) 从子过程返回,在 RV32I 和 RV64I 中
pc = x[1]
从子过程返回

2.8 同步指令

指令 类型 RV32I/RV64I 作用
fence I fence pred, succ 内存和 I/O 屏障
Fence(pred, succ)
fence.i I fence.i 指令流屏障
Fence(Store, Fetch)
使内存指令区域的写入对后续取指操作可见

2.9 环境指令

指令 类型 RV32I/RV64I 作用
ecall I ecall 环境调用
RaiseException(EnvironmentCall)
通过抛出环境调用异常调用执行环境
ebreak I ebreak 环境断点
RaiseException(Breakpoint)
通过抛出断点异常调用调试器

2.10 控制状态寄存器指令

指令示意:

RV32I/RV64I指令:

指令 类型 RV32I/RV64I 作用
csrrw I csrrw rd, csr, rs1 控制状态寄存器读后写
t = CSRs[csr]; CSRs[csr] = x[rs1]; x[rd] = t
记控制状态寄存器 csr 的值为 t。将 x[rs1] 写入 csr,再将 t 写入 x[rd]。
csrrs I csrrs rd, csr, rs1 控制状态寄存器读后置位
t = CSRs[csr]; CSRs[csr] = t | x[rs1]; x[rd] = t
记控制状态寄存器 csr 的值为 t。将 t 和 x[rs1] 的按位或结果写入 csr,再将 t 写入x[rd]。
csrrc I csrrc rd, csr, rs1 控制状态寄存器读后清位
t = CSRs[csr]; CSRs[csr] = t &x[rs1]; x[rd] = t
记控制状态寄存器 csr 的值为 t。将 x[rs1] 的反码和 t 按位与,结果写入 csr,再将 t 写入 x[rd]。
csrrwi I csrrwi rd, csr, zimm[4:0] 控制状态寄存器读后写立即数
x[rd] = CSRs[csr]; CSRs[csr] = zimm
将控制状态寄存器 csr 的值复制到 x[rd] 中,再将 5 位立即数 zimm 的零扩展结果写入csr
csrrsi I csrrsi rd, csr, zimm[4:0] 控制状态寄存器读后置位立即数
t = CSRs[csr]; CSRs[csr] = t | zimm; x[rd] = t
记控制状态寄存器 csr 的值为 t。将 5 位立即数 zimm 零扩展后,和 t 按位或,结果写入 csr,再将 t 写入 x[rd](csr 中的第 5 及更高的位不变)
csrrci I csrrci rd, csr, zimm[4:0] 控制状态寄存器读后清位立即数
t = CSRs[csr]; CSRs[csr] = t &zimm; x[rd] = t
记控制状态寄存器 csr 的值为 t。将 5 位立即数 zimm 零扩展后的反码和 t 按位与结果写入 csr,再将 t 写入 x[rd](csr 中的第 5 及更高的位不变)

伪指令:

指令 伪指令 实际指令 作用
csrc csrc csr, rs1 csrrc x0, csr, rs1 控制状态寄存器清位,在RV32I和RV64I中
CSRs[csr] &= x[rs1]
对于 x[rs1] 中每一个为 1 的位,将控制状态寄存器 csr 的对应位清零
csrci csrci csr, zimm[4:0] csrrci x0, csr, zimm 控制状态寄存器清位立即数,在RV32I和RV64I中
CSRs[csr] &= zimm
对于 5 位立即数零扩展后中每一个为 1 的位,将控制状态寄存器 csr 的对应位清零
csrr csrr rd, csr csrrs rd, csr, x0 控制状态寄存器读,在RV32I和RV64I中
x[rd] = CSRs[csr]
将控制状态寄存器 csr 写入 x[rd]
csrs csrs csr, rs1 csrrs x0, csr, rs1 控制状态寄存器置位,在RV32I和RV64I中
CSRs[csr] |= x[rs1]
对于 x[rs1] 中每一个为 1 的位,将控制状态寄存器 csr 的对应位置 1
csrsi csrsi csr, zimm[4:0] csrrsi x0, csr, zimm 控制状态寄存器置位立即数,在RV32I和RV64I中
CSRs[csr] |= zimm
对于 5 位立即数 zimm 的零扩展结果中每一个为 1 的位,将控制状态寄存器 csr 的对应位置 1
csrw csrw csr, rs1 csrrw x0, csr, rs1 控制状态寄存器写,在RV32I和RV64I中
CSRs[csr] = x[rs1]
将 x[rs1] 的值写入控制状态寄存器 csr
csrwi csrwi csr, zimm[4:0] csrrwi x0, csr,zimm 控制状态寄存器写立即数,在RV32I和RV64I中
CSRs[csr] = zimm
将 5 位立即数 zimm 的零扩展结果写入控制状态寄存器 csr

3 RVM指令集

指令示意:

RV32M/RV64M指令:

指令 类型 RV32M/RV64M 作用
mul R mul rd, rs1, rs2
x[rd] = x[rs1] × x[rs2]
将 x[rs2] 与 x[rs1] 相乘,乘积写入 x[rd]。忽略算术溢出。
mulh R mulh rd, rs1, rs2 高位乘
x[rd] = (x[rs1] × x[rs2]) >> XLEN
将 x[rs2] 与 x[rs1] 视为补码并相乘,乘积的高位写入 x[rd]。
mulhsu R mulhsu rd, rs1, rs2 高位有符号-无符号乘
x[rd] = (x[rs1] × x[rs2]) >> XLEN
将 x[rs1](视为补码)与 x[rs1](视为无符号数)相乘,乘积的高位写入 x[rd]
mulhu R mulhu rd, rs1, rs2 高位有无符号乘
x[rd] = (x[rs1] × x[rs2]) >> XLEN
将 x[rs1]与 x[rs1](视为无符号数)相乘,乘积的高位写入x[rd]
div R div rd, rs1, rs2
x[rd] = x[rs1] ÷ x[rs2]
x[rs1] 除以 x[rs2](补码除法),结果向零舍入,将商写入 x[rd]
divu R divu rd, rs1, rs2 无符号除
x[rd] = x[rs1] ÷ x[rs2]
x[rs1] 除以 x[rs2](无符号除法),结果向零舍入,将商写入 x[rd]
rem R rem rd, rs1, rs2 求余数
x[rd] = x[rs1] % x[rs2]
将 x[rs1] 和 x[rs2] 视为补码并相除,向 0 舍入,将余数写入 x[rd]。
remu R remu rd, rs1, rs2 求无符号余数
x[rd] = x[rs1] % x[rs2]
将 x[rs1] 和 x[rs2] 视为无符号数并相除,向 0 舍入,将余数写入 x[rd]。

RV64M指令:

指令 类型 RV64M 作用
mulw R mulw rd, rs1, rs2 乘字
x[rd] = sext((x[rs1] × x[rs2])[31:0])
将 x[rs2] 与 x[rs1] 相乘,乘积截为 32 位,符号扩展后写入 x[rd]。忽略算术溢出。
divw R divw rd, rs1, rs2 除字
x[rd] = sext(x[rs1][31:0] ÷ x[rs2][31:0])
x[rs1] 的低 32 位除以 x[rs2] 的低 32 位(补码除法),结果向零舍入,将 32 位商的符号扩展结果写入 x[rd]。
divuw R divuw rd, rs1, rs2 无符号除字
x[rd] = sext(x[rs1][31:0] ÷ x[rs2][31:0]))
x[rs1] 的低 32 位除以 x[rs2] 的低 32 位(无符号除法),结果向零舍入,将 32 位商的符号扩展结果写入 x[rd]。
remw R remw rd, rs1, rs2 求余数字
x[rd] = sext(x[rs1][31:0] % x[rs2][31:0])
将 x[rs1] 和 x[rs2] 的低 32 位视为补码并相除,向 0 舍入,将 32 位余数符号扩展后写入 x[rd]
remuw R remuw rd, rs1, rs2 求余数字
x[rd] = sext(x[rs1][31:0] % x[rs2][31:0])
将 x[rs1] 和 x[rs2] 的低 32 位视为无符号数并相除,向 0 舍入,将 32 位余数符号扩展后写入 x[rd]

4 RVFD指令集

4.1 访存指令

用于浮点数的取数存数操作。

指令示意:

RV32F/RV64F指令:

指令 类型 RV32F/RV64F 作用
flw I flw rd, offset(rs1) 取浮点字
f[rd] = M[x[rs1] + sext(offset)][31:0]
从内存地址 x[rs1] + sext(offset) 中读取单精度浮点数,并写入 f[rd]
fsw S fsw rs2, offset(rs1) 存浮点字
M[x[rs1] + sext(offset)] = f[rs2][31:0]
将 f[rs2] 中的单精度浮点数写入内存地址 x[rs1] + sext(offset) 中

RV32D/RV64D指令:

指令 类型 RV32F/RV64F 作用
fld I fld rd, offset(rs1) 取浮点双字
f[rd] = M[x[rs1] + sext(offset)][63:0]
从内存地址 x[rs1] + sext(offset) 中读取双精度浮点数,并写入 f[rd]
fsd S fsd rs2, offset(rs1) 存浮点双字
M[x[rs1] + sext(offset)] = f[rs2][63:0]
将 f[rs2] 中的双精度浮点数写入内存地址 x[rs1] + sext(offset) 中

4.2 RVFD 算术指令

指令示意:

RV32F/RV64F指令:

指令 类型 RV32F/RV64F 作用
fadd.s R fadd.s rd, rs1, rs2 单精度浮点加
f[rd] = f[rs1] + f[rs2]
将 f[rs1] 与 f[rs2] 中的单精度浮点数相加,将舍入后的单精度结果写入 f[rd]
fsub.s R fsub.s rd, rs1, rs2 单精度浮点减
f[rd] = f[rs1] - f[rs2]
将 f[rs1] 与 f[rs2] 中的单精度浮点数相减,将舍入后的单精度结果写入 f[rd]
fmul.s R fmul.s rd, rs1, rs2 单精度浮点乘
f[rd] = f[rs1] × f[rs2]
将 f[rs1] 与 f[rs2] 中的单精度浮点数相乘,将舍入后的单精度结果写入 f[rd]。
fdiv.s R fdiv.s rd, rs1, rs2 单精度浮点除
f[rd] = f[rs1] ÷ f[rs2]
将 f[rs1] 与 f[rs2] 中的单精度浮点数相除,并将舍入后的商写入 f[rd]。
fsqrt.s R fsqrt.s rd, rs1 单精度浮点求平方根
f[rd] = f[rs1]
计算 f[rs1] 中的单精度浮点数的平方根,将舍入后的单精度结果写入 f[rd]
fmin.s R fmin.s rd, rs1, rs2 单精度浮点最小值
f[rd] = min(f[rs1], f[rs2])
将 f[rs1] 和 f[rs2] 中的单精度浮点数较小者写入 f[rd]
fmax.s R fmax.s rd, rs1, rs2 单精度浮点最大值
f[rd] = max(f[rs1], f[rs2])
将 f[rs1] 和 f[rs2] 中的单精度浮点数较大者写入 f[rd]。

RV32D/RV64D指令:

指令 类型 RV32D/RV64D 作用
fadd.d R fadd.d rd, rs1, rs2 双精度浮点加
f[rd] = f[rs1] + f[rs2]
将 f[rs1] 与 f[rs2] 中的双精度浮点数相加,将舍入后的双精度结果写入 f[rd]。
fsub.d R fsub.d rd, rs1, rs2 双精度浮点减
f[rd] = f[rs1] - f[rs2]
将 f[rs1] 与 f[rs2] 中的双精度浮点数相减,将舍入后的双精度结果写入 f[rd]
fmul.d R fmul.d rd, rs1, rs2 双精度浮点乘
f[rd] = f[rs1] × f[rs2]
将 f[rs1] 与 f[rs2] 中的双精度浮点数相乘,将舍入后的双精度结果写入 f[rd]。
fdiv.d R fdiv.d rd, rs1, rs2 双精度浮点除法
f[rd] = f[rs1] ÷ f[rs2]
将 f[rs1] 与 f[rs2] 中的双精度浮点数相除,并将舍入后的商写入 f[rd]。
fsqrt.d R fsqrt.d rd, rs1 双精度浮点求平方根
f[rd] = f[rs1]
计算 f[rs1] 中的双精度浮点数的平方根,将舍入后的双精度结果写入 f[rd]。
fmin.d R fmin.d rd, rs1, rs2 双精度浮点最小值
f[rd] = min(f[rs1], f[rs2])
将 f[rs1] 和 f[rs2] 中的双精度浮点数较小者写入 f[rd]
fmax.d R fmax.d rd, rs1, rs2 双精度浮点最大值
f[rd] = max(f[rs1], f[rs2])
将 f[rs1] 和 f[rs2] 中的双精度浮点数较大者写入 f[rd]

4.3 RVFD 乘加指令

指令示意:

RV32F/RV64F指令:

指令 类型 RV32F/RV64F 作用
fmadd.s R4 fmadd.s rd, rs1, rs2, rs3 单精度浮点乘加
f[rd] = f[rs1]×f[rs2]+f[rs3]
将 f[rs1] 与 f[rs2] 中的单精度浮点数相乘,并将未舍入的积与 f[rs3] 中的单精度浮点数相加,将舍入后的单精度结果写入 f[rd]
fmsub.s R4 fmsub.s rd, rs1, rs2, rs3 单精度浮点乘减
f[rd] = f[rs1]×f[rs2]-f[rs3]
将 f[rs1] 与 f[rs2] 中的单精度浮点数相乘,并将未舍入的积与 f[rs3] 中的单精度浮点数相减,将舍入后的单精度结果写入 f[rd]
fnmadd.s R4 fnmadd.s rd, rs1, rs2, rs3 单精度浮点乘加取负
f[rd] = -f[rs1]×f[rs2]-f[rs3]
将 f[rs1] 与 f[rs2] 中的单精度浮点数相乘,结果取负,并将未舍入的积与 f[rs3] 中的单精度浮点数相减,将舍入后的单精度结果写入 f[rd]。
fnmsub.s R4 fnmsub.s rd, rs1, rs2, rs3 单精度浮点乘减取负
f[rd] = -f[rs1]×f[rs2]+f[rs3]
将 f[rs1] 与 f[rs2] 中的单精度浮点数相乘,结果取负,并将未舍入的积与 f[rs3] 中的单精度浮点数相加,将舍入后的单精度结果写入 f[rd]

RV32D/RV64D指令:

指令 类型 RV32D/RV64D 作用
fmadd.d R4 fmadd.d rd, rs1, rs2, rs3 双精度浮点乘加
f[rd] = f[rs1]×f[rs2]+f[rs3]
将 f[rs1] 与 f[rs2] 中的双精度浮点数相乘,并将未舍入的积与 f[rs3] 中的双精度浮点数相加,将舍入后的双精度结果写入 f[rd]
fmsub.d R4 fmsub.d rd, rs1, rs2, rs3 双精度浮点乘减
f[rd] = f[rs1]×f[rs2]-f[rs3]
将 f[rs1] 与 f[rs2] 中的双精度浮点数相乘,并将未舍入的积与 f[rs3] 中的双精度浮点数相减,将舍入后的双精度结果写入 f[rd]。
fnmadd.d R4 fnmsub.d rd, rs1, rs2, rs3 双精度浮点乘减取负
f[rd] = -f[rs1]×f[rs2]-f[rs3]
将 f[rs1] 与 f[rs2] 中的双精度浮点数相乘,结果取负,并将未舍入的积与 f[rs3] 中的双精度浮点数相减,将舍入后的双精度结果写入 f[rd]。
fnmsub.d R4 fnmsub.d rd, rs1, rs2, rs3 双精度浮点乘减取负
f[rd] = -f[rs1]×f[rs2]+f[rs3]
将 f[rs1] 与 f[rs2] 中的双精度浮点数相乘,结果取负,并将未舍入的积与 f[rs3] 中的双精度浮点数相加,将舍入后的双精度结果写入 f[rd]

4.4 RVFD传送指令

用于标量寄存器与浮点寄存器之间数据mv操作。

指令示意:

RV32F/RV64F指令:

指令 类型 RV32F/RV64F 作用
fmv.w.x R fmv.w.x rd, rs1 从整数传送字到浮点
f[rd] = x[rs1][31:0]
将 x[rs1] 中的单精度浮点数复制到 f[rd]。
fmv.x.w R fmv.x.w rd, rs1 从浮点传送字到整数
x[rd] = sext(f[rs1][31:0])
将 f[rs1] 中的单精度浮点数复制到 x[rd],在 RV64F 中额外对结果进行符号扩展

RV64D指令:

指令 类型 RV64D 作用
fmv.d.x R fmv.d.x rd, rs1 从整数传送双字到浮点
f[rd] = x[rs1][63:0]
将 x[rs1] 中的双精度浮点数复制到 f[rd]
fmv.x.d R fmv.x.d rd, rs1 从浮点传送双字到整数
x[rd] = f[rs1][63:0]
将 f[rs1] 中的双精度浮点数复制到 x[rd]。

4.5 RVFD 转换指令

指令示意:

RV32F/RV64F指令:

指令 类型 RV32F 作用
fcvt.s.w R fcvt.s.w rd, rs1 字转换为单精度浮点
f[rd] = f32(x[rs1])
将 x[rs1] 中的 32 位有符号整数(补码表示)转换为单精度浮点数,并写入 f[rd]
fcvt.w.s R fcvt.w.s rd, rs1 单精度浮点转换为字
x[rd] = sext(s32(f[rs1]))
将 f[rs1] 中的单精度浮点数转换为 32 位有符号整数(补码表示),符号扩展后写入x[rd]。
fcvt.s.wu R fcvt.s.wu rd, rs1 无符号字转换为单精度浮点
f[rd] = f32(x[rs1])
将 x[rs1] 中的 32 位无符号整数转换为单精度浮点数,并写入 f[rd]。
fcvt.wu.s R fcvt.wu.s rd, rs1 单精度浮点转换为无符号字
x[rd] = sext(u32(f[rs1]))
将 f[rs1] 中的单精度浮点数转换为 32 位无符号整数,符号扩展后写入 x[rd]

RV32D/RV64D指令:

指令 类型 RV64D 作用
fcvt.s.d R fcvt.s.d rd, rs1 双精度转换为单精度浮点
f[rd] = f32(f[rs1])
将 f[rs1] 中的双精度浮点数转换为单精度浮点数,并写入 f[rd]。
fcvt.d.s R fcvt.d.s rd, rs1 单精度浮点转换为双精度浮点
f[rd] = f64(f[rs1])
将 f[rs1] 中的单精度浮点数转换为双精度浮点数,并写入 f[rd]
fcvt.d.w R fcvt.d.w rd, rs1 字转换为双精度浮点
f[rd] = f64(x[rs1])
将 x[rs1] 中的 32 位有符号整数(补码表示)转换为双精度浮点数,并写入 f[rd]
fcvt.w.d R fcvt.w.d rd, rs1 双精度浮点转换为字
x[rd] = sext(s32(f[rs1]))
将 f[rs1] 中的双精度浮点数转换为 32 位有符号整数(补码表示),符号扩展后写入x[rd]。
fcvt.d.wu R fcvt.d.wu rd, rs1 无符号字转换为双精度浮点
f[rd] = f64(x[rs1])
将 x[rs1] 中的 32 位无符号整数转换为双精度浮点数,并写入 f[rd]
fcvt.wu.d R fcvt.wu.d rd, rs1 双精度浮点转换为无符号字
x[rd] = sext(u32(f[rs1]))
将 f[rs1] 中的双精度浮点数转换为 32 位无符号整数,符号扩展后写入 x[rd]

RV64F指令:

指令 类型 RV64F 作用
fcvt.l.s R fcvt.l.s rd, rs1 单精度浮点转换为长字
x[rd] = s64(f[rs1])
将 f[rs1] 中的单精度浮点数转换为 64 位有符号整数(补码表示),并写入 x[rd]
fcvt.s.l R fcvt.s.l rd, rs1 长字转换为单精度浮点转换
f[rd] = f32(x[rs1])
将 x[rs1] 中的 64 位有符号整数(补码表示)转换为单精度浮点数,并写入 f[rd]。
fcvt.s.lu R fcvt.s.lu rd, rs1 无符号长字转换为单精度浮点
f[rd] = f32(x[rs1])
将 x[rs1] 中的 64 位无符号整数转换为单精度浮点数,并写入 f[rd]。
fcvt.lu.s R fcvt.lu.s rd, rs1 单精度浮点转换为无符号长字
x[rd] = u64f32(f[rs1])
将 f[rs1] 中的单精度浮点数转换为 64 位无符号整数,并写入 x[rd]。

RV64D指令:

指令 类型 RV64D 作用
fcvt.d.l R fcvt.d.l rd, rs1 长字转换为双精度浮点
f[rd] = f64(x[rs1])
将 x[rs1] 中的 64 位有符号整数(补码表示)转换为双精度浮点数,并写入 f[rd]
fcvt.l.d R fcvt.l.d rd, rs1 双精度浮点转长字
x[rd] = s64(f[rs1])
将 f[rs1] 中的双精度浮点数转换为 64 位有符号整数(补码表示),并写入 x[rd]。
fcvt.d.lu R fcvt.d.lu rd, rs1 无符号长字转换为双精度浮点
f[rd] = f64(x[rs1])
将 x[rs1] 中的 64 位无符号整数转换为双精度浮点数,并写入 f[rd]。
fcvt.lu.d R fcvt.lu.d rd, rs1 双精度浮点转换为无符号长字
x[rd] = u64(f[rs1])
将 f[rs1] 中的双精度浮点数转换为 64 位无符号整数,并写入 x[rd]。

4.6 RVFD 符号注入指令

指令示意:

RV32F/RV64F指令:

指令 类型 RV32F/RV64F 作用
fsgnj.s R fsgnj.s rd, rs1, rs2 单精度浮点符号注入
f[rd] = {f[rs2][31], f[rs1][30:0]}
用 f[rs1] 的阶码和尾数,以及 f[rs2] 的符号位,组成一个新的单精度浮点数,并将其写入 f[rd]。
fsgnjn.s R fsgnjn.s rd, rs1, rs2 单精度浮点符号取反注入
f[rd] = {f[rs2][31], f[rs1][30:0]}
用 f[rs1] 的阶码和尾数,以及 f[rs2] 的符号位取反,组成一个新的单精度浮点数,并将其写入 f[rd]
fsgnjx.s R fsgnjx.s rd, rs1, rs2 单精度浮点符号异或注入
f[rd] = {f[rs1][31] ˆ f[rs2][31], f[rs1][30:0]}
用 f[rs1] 的阶码和尾数,以及 f[rs1] 和 f[rs2] 符号位的异或,组成一个新的单精度浮点数,并将其写入 f[rd]

RV32D/RV64D指令:

指令 类型 RV32D/RV64D 作用
fsgnj.d R fsgnj.d rd, rs1, rs2 双精度浮点符号注入
f[rd] = {f[rs2][63], f[rs1][62:0]}
用 f[rs1] 的阶码和尾数,以及 f[rs2] 的符号位,组成一个新的双精度浮点数,并将其写入 f[rd]
fsgnjn.d R fsgnjn.d rd, rs1, rs2 双精度浮点符号取反注入
f[rd] = {f[rs2][63], f[rs1][62:0]}
用 f[rs1] 的阶码和尾数,以及 f[rs2] 的符号位取反,组成一个新的双精度浮点数,并将其写入 f[rd]
fsgnjx.d R fsgnjx.d rd, rs1, rs2 双精度浮点符号异或注入
f[rd] = {f[rs1][63] ˆ f[rs2][63], f[rs1][62:0]}
用 f[rs1] 的阶码和尾数,以及 f[rs1] 和 f[rs2] 符号位的异或,组成一个新的双精度浮点数,并将其写入 f[rd]。

伪指令:

指令 伪指令 实际指令 作用
fabs.s fabs.s rd, rs1 fsgnjx.s rd, rs1, rs1 单精度浮点数绝对值,在RV32F/RV64F中
f[rd] = |f[rs1]|
将双精度浮点数 f[rs1] 的绝对值写入 f[rd]
fmv.s fmv.s rd, rs1 fsgnj.s rd, rs1, rs1 单精度浮点数据传送,在RV32F/RV64F中
f[rd] = f[rs1]
将双精度浮点数 f[rs1] 复制到 f[rd] 中
fneg.s fneg.s rd, rs1 fsgnjn.s rd, rs1, rs1 单精度浮点取负,在RV32F/RV64F中
f[rd] = -f[rs1]
将双精度浮点数 f[rs1] 取负后写入 f[rd]
fabs.d fabs.d rd, rs1 fsgnjx.d rd, rs1, rs1 双精度浮点数绝对值,在RV32D/RV64D中
f[rd] = |f[rs1]|
将双精度浮点数 f[rs1] 的绝对值写入 f[rd]
fmv.d fmv.d rd, rs1 fsgnj.d rd, rs1, rs1 双精度浮点数据传送,在RV32D/RV64D中
f[rd] = f[rs1]
将双精度浮点数 f[rs1] 复制到 f[rd] 中
fneg.d fneg.d rd, rs1 fsgnjn.d rd, rs1, rs1 双精度浮点取负,在RV32D/RV64D中
f[rd] = -f[rs1]
将双精度浮点数 f[rs1] 取负后写入 f[rd]

4.7 RVFD 比较指令

指令示意:

RV32F/RV64F指令:

指令 类型 RV32F/RV64F 作用
feq.s R feq.s rd, rs1, rs2 单精度浮点相等
x[rd] = (f[rs1] == f[rs2])
若 f[rs1] 和 f[rs2] 中的单精度浮点数相等,则向 x[rd] 写 1,否则写 0
flt.s R fle.s rd, rs1, rs2 单精度浮点小于
x[rd] = (f[rs1] < f[rs2])
若 f[rs1] 中的单精度浮点数小于 f[rs2],则向 x[rd] 中写 1,否则写 0
fle.s R fle.s rd, rs1, rs2 单精度浮点小于等于
x[rd] = (f[rs1] f[rs2])
若 f[rs1] 中的单精度浮点数小于等于 f[rs2],则向 x[rd] 中写 1,否则写 0。

RV32D/RV64D指令:

指令 类型 RV32F/RV64F 作用
feq.d R feq.d rd, rs1, rs2 双精度浮点相等
x[rd] = (f[rs1] == f[rs2])
若 f[rs1] 和 f[rs2] 中的双精度浮点数相等,则向 x[rd] 写 1,否则写 0
flt.d R flt.d rd, rs1, rs2 双精度浮点小于
x[rd] = (f[rs1] < f[rs2])
若 f[rs1] 中的双精度浮点数小于 f[rs2],则向 x[rd] 写 1,否则写 0
fle.d R fle.d rd, rs1, rs2 双精度浮点小于等于
x[rd] = (f[rs1] f[rs2])
若 f[rs1] 中的双精度浮点数小于等于 f[rs2],则向 x[rd] 中写 1,否则写 0。

4.8 RVFD 分类指令

指令示意:

RV32F/RV64F指令:

指令 类型 RV32F/RV64F 作用
fclass.s R fclass.s rd, rs1 单精度浮点分类
x[rd] = classifys(f[rs1])
将一个表示 f[rs1] 中单精度浮点数类别的掩码写入 x[rd]。

RV32D/RV64D指令:

指令 类型 RV32D/RV64D 作用
fclass.d R fclass.d rd, rs1 双精度浮点分类
x[rd] = classifys(f[rs1])
将一个表示 f[rs1] 中双精度浮点数类别的掩码写入 x[rd]。

4.9 RVFD 配置指令

RV32F/RV64F伪指令:

指令 伪指令 实际指令 作用
frcsr frcsr rd csrrs rd, fcsr, x0 读浮点控制状态寄存器,在 RV32F 和 RV64F 中
x[rd] = CSRs[fcsr]
将浮点控制状态寄存器写入 x[rd]
frflags frflags rd csrrs rd, fflags, x0 读浮点异常标志,在 RV32F 和 RV64F 中
x[rd] = CSRs[fflags]
将浮点异常标志写入 x[rd]
frrm frrm rd csrrs rd, frm, x0 读浮点舍入模式,在 RV32F 和 RV64F 中
x[rd] = CSRs[frm]
将浮点舍入模式写入 x[rd]
fscsr fscsr rd, rs1 csrrw rd, fcsr, rs1 交换浮点控制状态寄存器,在 RV32F 和 RV64F 中
t = CSRs[fcsr]; CSRs[fcsr] = x[rs1]; x[rd] = t
将 x[rs1] 写入浮点控制状态寄存器,并将浮点控制状态寄存器的原值写入 x[rd]
若省略 rd,则默认为 x0
fsrm fsrm rd, rs1 csrrw rd, frm, rs1 交换浮点舍入模式,在 RV32F 和 RV64F 中
csrrw rd, frm, rs1
将 x[rs1] 写入浮点舍入模式寄存器,并将浮点舍入模式寄存器的原值写入 x[rd]
若省略 rd,则默认为 x0
fsflags fsflags rd, rs1 csrrw rd, fflags, rs1 交换浮点异常标志,在 RV32F 和 RV64F 中
t = CSRs[fflags]; CSRs[fflags] = x[rs1]; x[rd] = t
将 x[rs1] 写入浮点异常标志寄存器,并将浮点异常标志寄存器的原值写入 x[rd]
若省略 rd,则默认为 x0

5 RVA指令集

RVA 用于同步的原子操作有两种:

  • 原子内存操作 (atomic memory operation, AMO)

    AMO 指令对内存中的操作数执行一次原子操作,并将原内存值写入目的寄存器。“原子” 表示内存读写之间既不会发生中断,也不会被其他处理器修改内存值。

  • 加载保留/条件存储 ( load reserved / store conditional)

    加载保留和条件存储保证了它们两条指令之间的操作的原子性。

    • 加载保留读取一个内存字,存入目标寄存器中,并留下这个字的保留记录。
    • 而如果条件存储的目标地址上存在保留记录,它就把字存入这个地址。
    • 如果存入成功,它向目标寄存器中写入 0;否则写入一个非0 的错误代码。

    加载保留就是当Load数据时,保留加载这个地址数据的记录。条件存储表示Store并不是总能成功,需要满足一定的条件:1.有LR访问过该地址的记录;2.LR和SC之间没有其它的写操作或中断;这样做的好处就是不用长时间将总线上锁,所以LR/SC指令可以不上锁保证操作的原子性。

指令示意:

RV32A/RV64A指令:

指令 类型 RV32A/RV64A 作用
amoadd.w R amoadd.w rd, rs2, (rs1) 原子加字
x[rd] = AMO32(M[x[rs1]] + x[rs2])
将内存地址为 x[rs1] 的字记为 t,将 t + x[rs2] 写入该地址,并将 t 的符号扩展结果写入 x[rd]
amoand.w R amoand.w rd, rs2, (rs1) 原子与字
x[rd] = AMO32(M[x[rs1]] & x[rs2])
将内存地址为 x[rs1] 的字记为 t,将 t 和 x[rs2] 的按位与结果写入该地址,并将 t 的符号扩展结果写入 x[rd]。
amoor.w R amoor.w rd, rs2, (rs1) 原子或字
x[rd] = AMO32(M[x[rs1]] |x[rs2])
将内存地址为 x[rs1] 的字记为 t,将 t 和 x[rs2] 的按位或结果写入该地址,并将 t 的符号扩展结果写入 x[rd]
amoswap.w R amoswap.w rd, rs2, (rs1) 原子交换字
x[rd] = AMO32(M[x[rs1]] SWAP x[rs2])
将内存地址为 x[rs1] 的字记为 t,将 x[rs2] 写入该地址,并将 t的符号扩展结果写入 x[rd]
amoxor.w R amoxor.w rd, rs2, (rs1) 原子异或字
x[rd] = AMO32(M[x[rs1]] ^ x[rs2])
将内存地址为 x[rs1] 的字记为 t,将 t 和 x[rs2] 的按位异或结果写入该地址,并将 t 的符号扩展结果写入 x[rd]
amomax.w R amomax.w rd, rs2, (rs1) 原子最大字
x[rd] = AMO32(M[x[rs1]] MAX x[rs2])
将内存地址为 x[rs1] 的字记为 t,将 t 和 x[rs2] 中较大者(补码比较)写入该地址,并将 t 的符号扩展结果写入 x[rd]。
amomaxu.w R amomaxu.w rd, rs2, (rs1) 原子无符号最大字
x[rd] = AMO32(M[x[rs1]] MAXU x[rs2])
将内存地址为 x[rs1] 的字记为 t,将 t 和 x[rs2] 中较大者(无符号比较)写入该地址,并将 t 的符号扩展结果写入 x[rd]。
amomin.w R amomin.w rd, rs2, (rs1) 原子最小字
x[rd] = AMO32(M[x[rs1]] MIN x[rs2])
将内存地址为 x[rs1] 的字记为 t,将 t 和 x[rs2] 中较小者(补码比较)写入该地址,并将 t 的符号扩展结果写入 x[rd]
amominu.w R amominu.w rd, rs2, (rs1) 原子无符号最小字
x[rd] = AMO32(M[x[rs1]] MINU x[rs2])
将内存地址为 x[rs1] 的字记为 t,将 t 和 x[rs2] 中较小者(无符号比较)写入该地址,并将 t 的符号扩展结果写入 x[rd]。
lr.w R lr.w rd, (rs1) 预订取字
x[rd] = LoadReserved32(M[x[rs1]])
从地址 x[rs1] 读取 4 字节,符号扩展后写入 x[rd],并预订该内存字
sc.w R sc.w rd, rs2, (rs1) 条件存字
x[rd] = StoreConditional32(M[x[rs1]], x[rs2])
若内存地址 x[rs1] 被预订,则将 x[rs2] 中的 4 字节写入该地址。若写入成功,则向x[rd] 写入 0,否则向其写入一个非 0 的错误码

RV64A指令:

指令 类型 RV64A 作用
amoadd.d R amoadd.d rd, rs2, (rs1) 原子加双字
x[rd] = AMO64(M[x[rs1]] + x[rs2])
将内存地址为 x[rs1] 的双字记为 t,将 t + x[rs2] 写入该地址,并将 t 写入 x[rd]。
amoand.d R amoand.d rd, rs2, (rs1) 原子与双字
x[rd] = AMO64(M[x[rs1]] & x[rs2])
将内存地址为 x[rs1] 的双字记为 t,将 t 和 x[rs2] 的按位与结果写入该地址,并将 t 写入 x[rd]
amoor.d R amoor.d rd, rs2, (rs1) 原子或双字
x[rd] = AMO32(M[x[rs1]] | x[rs2])
将内存地址为 x[rs1] 的双字记为 t,将 t 和 x[rs2] 的按位或结果写入该地址,并将 t 写入 x[rd]。
amoswap.d R amoswap.d rd, rs2, (rs1) 原子交换双字
x[rd] = AMO64(M[x[rs1]] SWAP x[rs2])
将内存地址为 x[rs1] 的双字记为 t,将 x[rs2] 写入该地址,并将t 写入 x[rd]。
amoxor.d R amoxor.d rd, rs2, (rs1) 原子异或双字
x[rd] = AMO32(M[x[rs1]] ^ x[rs2])
将内存地址为 x[rs1] 的双字记为 t,将 t 和 x[rs2] 的按位异或结果写入该地址,并将 t 写入 x[rd]。
amomax.d R amomax.d rd, rs2, (rs1) 原子最大双字
x[rd] = AMO64(M[x[rs1]] MAX x[rs2])
将内存地址为 x[rs1] 的双字记为 t,将 t 和 x[rs2] 中较大者(补码比较)写入该地址,并将 t 写入 x[rd]。
amomaxu.d R amomaxu.d rd, rs2, (rs1) 原子无符号最大双字
x[rd] = AMO64(M[x[rs1]] MAXU x[rs2])
将内存地址为 x[rs1] 的双字记为 t,将 t 和 x[rs2] 中较大者(无符号比较)写入该地址,并将 t 写入 x[rd]
amomin.d R amomin.d rd, rs2, (rs1) 原子最小双字
x[rd] = AMO64(M[x[rs1]] MIN x[rs2])
将内存地址为 x[rs1] 的双字记为 t,将 t 和 x[rs2] 中较小者(补码比较)写入该地址,并将 t 写入 x[rd]。
amominu.d R amominu.d rd, rs2, (rs1) 原子无符号最小双字
x[rd] = AMO64(M[x[rs1]] MINU x[rs2])
将内存地址为 x[rs1] 的双字记为 t,将 t 和 x[rs2] 中较小者(无符号比较)写入该地址,并将 t 写入 x[rd]。
lr.d R lr.d rd, (rs1) 预订取双字
x[rd] = LoadReserved64(M[x[rs1]])
从地址 x[rs1] 读取 8 字节,写入 x[rd],并预订该内存双字
sc.d R sc.d rd, rs2, (rs1) 条件存双字
x[rd] = StoreConditional64(M[x[rs1]], x[rs2])
若内存地址 x[rs1] 被预订,则将 x[rs2] 中的 8 字节写入该地址。若写入成功,则向x[rd] 写入 0,否则向其写入一个非 0 的错误码

参考:

  1. 《riscv-spec-20191213.pdf》
  2. riscv-asm-manual/riscv-asm.md at master · riscv-non-isa/riscv-asm-manual · GitHub
  3. 从零手写操作系统之RVOS任务同步和锁实现-07-腾讯云开发者社区-腾讯云 (tencent.com)
posted @ 2024-09-08 14:53  sureZ_ok  阅读(688)  评论(0编辑  收藏  举报