首页 > 编程语言 >一起学RISC-V汇编第5讲之常用指令及伪指令列表

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

时间:2024-09-08 14:52:28浏览次数:13  
标签:汇编 写入 伪指令 RISC underline rd rs1 rs2 mathrm

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

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

1 RISC-V指令命名

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

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

指令示意:
$$
\mathrm{\underline{s}et;\underline{l}ess;\underline{t}han}
\left{
\begin{aligned}
& _ \
& \mathrm{\underline{i}mmediate}
\end{aligned}
\right}
\left{
\begin{aligned}
& _ \
& \mathrm{\underline{u}nsigned}
\end{aligned}
\right}
$$

注意:后续指令示意中的加粗部分表示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 内存操作指令

指令示意:
$$
\left{
\begin{aligned}
& \mathrm{\underline{l}oad} \
& \mathrm{\underline{s}tore}
\end{aligned}
\right}
\left{
\begin{aligned}
& \mathrm{\underline{b}yte} \
& \mathrm{\underline{h}alfword} \
& \mathrm{\underline{w}ord} \
& \mathrm{\mathbf{\underline{d}oubleword}} \
\end{aligned}
\right}
$$

$$
\mathrm{\underline{l}oad}
\left{
\begin{aligned}
& \mathrm{\underline{b}yte} \
& \mathrm{\underline{h}alfword} \
& \mathrm{\mathbf{\underline{w}ord}} \
\end{aligned}
\right}
\mathrm{\underline{u}nsigned}
$$

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.1 算术指令

指令示意:
$$
\mathrm{\underline{add}}
\left{
\begin{aligned}
& _ \
& \mathrm{\underline{i}mmediate}
\end{aligned}
\right}
\left{
\begin{aligned}
& _ \
& \mathrm{\mathbf{\underline{w}ord}}
\end{aligned}
\right}
$$

$$
\mathrm{\underline{sub}tract}
\left{
\begin{aligned}
& _ \
& \mathrm{\mathbf{\underline{w}ord}}
\end{aligned}
\right}
$$

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指令,不好归类,绿卡将其归到算术指令,这里也放到这一类吧。

指令示意:
$$
\mathrm{\underline{l}oad;\underline{u}pper;\underline{i}mmediate}
$$

$$
\mathrm{\underline{a}dd;\underline{u}pper;\underline{i}mmediate;to;\underline{p}c}
$$

指令 类型 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.2 移位指令

指令示意:
$$
\left{
\begin{aligned}
& \mathrm{\underline{s}hift; \underline{l}eft;\underline{l}ogical} \
& \mathrm{\underline{s}hift;\underline{r}ight;\underline{a}rithmetic}\
& \mathrm{\underline{s}hift;\underline{r}ight;\underline{l}ogical}
\end{aligned}
\right}
\left{
\begin{aligned}
& _ \
& \mathrm{\underline{i}mmediate}\
\end{aligned}
\right}
\left{
\begin{aligned}
& _ \
& \mathrm{\mathbf{\underline{w}ord}}
\end{aligned}
\right}
$$
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.3 逻辑指令

指令示意:
$$
\left{
\begin{aligned}
& \mathrm{\underline{and}} \
& \mathrm{\underline{or}} \
& \mathrm{e\underline{x}clusive;\underline{or}} \
\end{aligned}
\right}
\left{
\begin{aligned}
& _ \
& \mathrm{\underline{i}mmediate}
\end{aligned}
\right}
$$

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.4 比较-置位指令

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

指令示意:
$$
\mathrm{\underline{s}et;\underline{l}ess;\underline{t}han}
\left{
\begin{aligned}
& _ \
& \mathrm{\underline{i}mmediate}
\end{aligned}
\right}
\left{
\begin{aligned}
& _ \
& \mathrm{\underline{u}nsigned}
\end{aligned}
\right}
$$

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.5 分支指令

指令示意:
$$
\mathrm{\underline{b}ranch}
\left{
\begin{aligned}
& \mathrm{\underline{eq}ual} \
& \mathrm{\underline{n}ot;\underline{e}qual}
\end{aligned}
\right}
$$

$$
\mathrm{\underline{b}ranch}
\left{
\begin{aligned}
& \mathrm{\underline{g}reater;than;or;\underline{e}qual} \
& \mathrm{\underline{l}ess;\underline{t}han}
\end{aligned}
\right}
\left{
\begin{aligned}
& _ \
& \mathrm{\underline{u}nsigned}
\end{aligned}
\right}
$$

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.6 跳转指令

指令示意:
$$
\mathrm{\underline{j}ump;\underline{a}nd;\underline{l}ink}
\left{
\begin{aligned}
& \mathrm{_} \
& \mathrm{\underline{r}egister}
\end{aligned}
\right}
$$

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.7 同步指令

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

2.8 环境指令

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

2.9 控制状态寄存器指令

指令示意:
$$
\mathrm{\underline{c}ontrol;\underline{s}tatus;\underline{r}egister}
\left{
\begin{aligned}
& \mathrm{\underline{r}ead;& ;\underline{c}lear;bit} \
& \mathrm{\underline{r}ead;& ;\underline{s}et;bit}\
& \mathrm{\underline{r}ead;& ;\underline{w}rite}
\end{aligned}
\right}
\left{
\begin{aligned}
& _ \
& \mathrm{\underline{i}mmediate}\
\end{aligned}
\right}
$$
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指令集

指令示意:
$$
\mathrm{\underline{mul}tiply}
\left{
\begin{aligned}
& \mathrm{_} \
& \mathrm{\mathbf{\underline{w}ord}}
\end{aligned}
\right}
$$

$$
\mathrm{\underline{mul}tiply;\underline{h}igh}
\left{
\begin{aligned}
& _ \
& \mathrm{\underline{u}nsigned} \
& \mathrm{\underline{s}igned;\underline{u}nsigned}
\end{aligned}
\right}
$$

$$
\left{
\begin{aligned}
& \mathrm{\underline{div}ide} \
& \mathrm{\underline{rem}ainder}
\end{aligned}
\right}
\left{
\begin{aligned}
& \mathrm{_} \
& \mathrm{\underline{u}nsigned}
\end{aligned}
\right}
\left{
\begin{aligned}
& \mathrm{_} \
& \mathrm{\mathbf{\underline{w}ord}}
\end{aligned}
\right}
$$

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 访存指令

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

指令示意:
$$
\mathrm{\underline{f}loat}
\left{
\begin{aligned}
& \mathrm{\underline{l}oad} \
& \mathrm{\underline{s}tore}
\end{aligned}
\right}
\left{
\begin{aligned}
& \mathrm{\underline{w}ord} \
& \mathrm{\underline{d}oubleword} \
\end{aligned}
\right}
$$

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 算术指令

指令示意:
$$
\mathrm{\underline{f}loat}
\left{
\begin{aligned}
& \mathrm{\underline{add}} \
& \mathrm{\underline{sub}tract} \
& \mathrm{\underline{mul}tiply} \
& \mathrm{\underline{div}ide} \
& \mathrm{\underline{sq}uare\ \underline{r}oo\underline{t}} \
& \mathrm{\underline{min}imum} \
& \mathrm{\underline{max}imum}
\end{aligned}
\right}
\left{
\begin{aligned}
& \mathrm{\underline{.s}ingle} \
& \mathrm{\underline{.d}ouble} \
\end{aligned}
\right}
$$

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 乘加指令

指令示意:
$$
\mathrm{\underline{f}loat}
\left{
\begin{aligned}
& \mathrm{_} \
& \mathrm{\underline{n}egative}
\end{aligned}
\right}
\mathrm{\underline{m}ultiply}
\left{
\begin{aligned}
& \mathrm{\underline{add}} \
& \mathrm{\underline{sub}tract}
\end{aligned}
\right}
\left{
\begin{aligned}
& \mathrm{\underline{.s}ingle} \
& \mathrm{\underline{.d}ouble} \
\end{aligned}
\right}
$$

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操作。

指令示意:
$$
\mathrm{\underline{f}loat}\
\mathrm{\underline{m}o\underline{v}e}\
\mathrm{to}\
\mathrm{\underline{.s}ingle} \
\mathrm{from}\
\mathrm{\underline{.x}\ register} \
$$

$$
\mathrm{\underline{f}loat}\
\mathrm{\underline{m}o\underline{v}e}\
\mathrm{to}\
\mathrm{\underline{.x}\ register} \
\mathrm{from}\

\mathrm{\underline{.s}ingle} \
$$

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 转换指令

指令示意:
$$
\mathrm{\underline{f}loat}\
\mathrm{\underline{c}on\underline{v}er\underline{t}\ to}
\left{
\begin{aligned}
& \mathrm{\underline{.s}ingle} \
& \mathrm{\underline{.d}ouble} \
\end{aligned}
\right}
\mathrm{from}\
\mathrm{\underline{.w}ord} \
\left{
\begin{aligned}
& \mathrm{_} \
& \mathrm{\underline{u}nsigned}
\end{aligned}
\right}
$$

$$
\mathrm{\underline{f}loat}\
\mathrm{\underline{c}on\underline{v}er\underline{t} \ to\ \underline{.w}ord}
\left{
\begin{aligned}
& \mathrm{_} \
& \mathrm{\underline{u}nsigned}
\end{aligned}
\right}
\mathrm{from}
\left{
\begin{aligned}
& \mathrm{\underline{.s}ingle} \
& \mathrm{\underline{.d}ouble} \
\end{aligned}
\right}
$$

$$
\mathrm{\underline{f}loat}\
\mathrm{\underline{c}on\underline{v}er\underline{t} \ to\ \underline{.s}ingle}
\mathrm{from} \
\mathrm{\underline{.d}ouble}
$$

$$
\mathrm{\underline{f}loat}\
\mathrm{\underline{c}on\underline{v}er\underline{t} \ to\ \underline{.d}ouble}
\mathrm{from} \
\mathrm{\underline{.s}ingle}
$$

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 符号注入指令

指令示意:
$$
\mathrm{\underline{f}loat}\
\mathrm{\underline{s}i\underline{gn} \ in\underline{j}ection}
\left{
\begin{aligned}
& \mathrm{_} \
& \mathrm{\underline{n}egative} \
& \mathrm{e\underline{x}clusive \ or} \
\end{aligned}
\right}
\left{
\begin{aligned}
& \mathrm{\underline{.s}ingle} \
& \mathrm{\underline{.d}ouble} \
\end{aligned}
\right}
$$

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 比较指令

指令示意:
$$
\mathrm{compare} \
\mathrm{\underline{f}loat}\
\left{
\begin{aligned}
& \mathrm{\underline{eq}uals} \
& \mathrm{\underline{l}ess \ \underline{t}han} \
& \mathrm{\underline{l}ess \ \underline{t}han \ or \ \underline{eq}uals} \
\end{aligned}
\right}
\left{
\begin{aligned}
& \mathrm{\underline{.s}ingle} \
& \mathrm{\underline{.d}ouble} \
\end{aligned}
\right}
$$

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 分类指令

指令示意:
$$
\mathrm{\underline{f}loat}\
\mathrm{\underline{class}ify}\
\left{
\begin{aligned}
& \mathrm{\underline{.s}ingle} \
& \mathrm{\underline{.d}ouble} \
\end{aligned}
\right}
$$

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指令可以不上锁保证操作的原子性。

指令示意:
$$
\mathrm{\underline{a}tomic \ \underline{m}emory \ \underline{o}peration}\
\left{
\begin{aligned}
& \mathrm{\underline{add}} \
& \mathrm{\underline{and}} \
& \mathrm{\underline{or}} \
& \mathrm{\underline{swap}} \
& \mathrm{\underline{xor}} \
& \mathrm{\underline{maxi}mum} \
& \mathrm{\underline{maxi}mum \ \underline{u}nsigned} \
& \mathrm{\underline{mini}mum} \
& \mathrm{\underline{mini}mum \ \underline{u}nsigned} \
\end{aligned}
\right}
\left{
\begin{aligned}
& \mathrm{\underline{.w}ord} \
& \mathrm{\mathbf{\underline{.d}oubleword}} \
\end{aligned}
\right}
$$

$$
\left{
\begin{aligned}
& \mathrm{\underline{l}oad \ \underline{r}eserved} \
& \mathrm{\underline{s}tore \ \underline{c}onditional} \
\end{aligned}
\right}
\left{
\begin{aligned}
& \mathrm{\underline{.w}ord} \
& \mathrm{\mathbf{\underline{.d}oubleword}} \
\end{aligned}
\right}
$$

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)

标签:汇编,写入,伪指令,RISC,underline,rd,rs1,rs2,mathrm
From: https://www.cnblogs.com/sureZ-learning/p/18402849

相关文章

  • 澎峰科技受邀参加全球AI芯片峰会,探讨大模型推理引擎PerfXLM面向RISC-V的移植和优化
    2024全球AI芯片峰会,9月6-7日北京开启!9月6-7日,2024全球AI芯片峰会(GACS2024)将在北京辽宁大厦盛大举办。全球AI芯片峰会至今已成功举办六届,现已成为国内规模最大、规格最高、影响力最强的产业峰会之一。本届峰会由芯东西与智猩猩共同主办,以「智算纪元共筑芯路」为主题。峰会采......
  • 编译原理项目——C++实现C语言编译器输出为gcc级汇编(代码/报告材料)
    完整的代码材料见文章末尾以下为核心内容和部分结果项目介绍function.cpp实现了共有的函数lexer.cpp词法分析器get_predict_table.cpp获取预测分析表LR.cpp语法分析generate.cpp语义分析中间代码生成to_asm.cpp目标代码生成部分核心代码LR分析#include"co......
  • RISC芯片/红外NEC应用教程/实操/含可运行代码~
    红外NEC协议一、NEC简介    红外(Infrared,IR)遥控是一种无线、非接触控制技术,常用于遥控器、无线键盘、鼠标等设备之间的通信。IR协议的工作原理是,发送方通过红外线发送一个特定的编码,接收方通过识别该编码来执行相应的操作。    IR协议是指红外线通信协议......
  • 《ARM Cortex-R 学习指南》-【第四章】-汇编语言简介
    第4章汇编语言简介汇编语言是一种低级编程语言。通常情况下,汇编语言指令(助记符)和处理器执行的实际二进制操作码之间存在一对一的对应关系。许多从事应用级开发的程序员很少需要编写汇编语言代码。然而,在某些情况下,掌握汇编代码的知识可能会非常有用,比如需要高度优化代码......
  • 信息学奥赛初赛天天练-82-NOIP2014普及组-完善程序-机器语言、汇编语言、高级语言、计
    1NOIP2014普及组基础题11以下哪个是面向对象的高级语言()A汇编语言BC++CFortranDBasic2TB代表的字节数是()A2的10次方B2的20次方C2的30次方D2的40次方3二进制数00100100和00010101的和是()A00101000B001010......
  • Go plan9 汇编:手写汇编
    原创文章,欢迎转载,转载请注明出处,谢谢。0.前言在Goplan9汇编:打通应用到底层的任督二脉一文中介绍了从应用程序到汇编指令的转换。本文将结合汇编和Go程序实现手写基本的汇编指令,以加深对Goplan9汇编的了解。1.手写汇编1.1全局变量首先写一个打印整型变量的函数......
  • GNU 汇编语法基础
     目录一、引言二、GNU汇编基本结构1.指令格式2.注释3.段三、寄存器和寻址方式1.寄存器命名2.寻址方式四、指令集 1.数据传送指令2.算术运算指令 3.逻辑运算指令4.控制流指令 五、宏和函数 1.宏定义 2. 函数定义六、总结 一、引言     ......
  • Go plan9 汇编: 打通应用到底层的任督二脉
    原创文章,欢迎转载,转载请注明出处,谢谢。0.前言作为一个严肃的Gopher,了解汇编是必须的。本汇编系列文章会围绕基本的Go程序介绍汇编的基础知识。1.Go程序到汇编首先看一个简单到令人发指的示例:packagemainfuncmain(){ a:=1 print(a)}运行程序,输出:#gorun......
  • RSIC-V常用汇编语言及常用数据结构-栈
    这是我在上完浙大刘鹏老师的视频课后做的笔记。我觉得在学完后,自己写出来会记忆会更深刻,因为要重新梳理一遍。同时遇到不会的还可以重新复习以前的知识。程序执行流程:高级语言->汇编语言->逻辑块->数字电路常用汇编语言:1.算数指令和访存指令在汇编语言里面,操作对象是寄存......
  • ESP8684 系列芯片搭载 RISCV 32 位单核处理器的极低功耗 SoC 支持(2.4 GHz WiFi) 和 B
    ESP8684系列芯片搭载RISCV32位单核处理器的极低功耗SoC支持(2.4GHzWiFi)和Bluetooth5(LE)ESP8684系列芯片搭载RISCV32位单核处理器的极低功耗SoC支持IEEE802.11b/g/n(2.4GHzWiFi)和Bluetooth5(LE)在4×4mm的QFN封装中叠封1MB、2MB或4MBf......