跳到主要内容

扩展指令集

RISC-V 的设计具有模块化和可扩展性。在基本指令集(RV32I 或 RV64I)的基础上,RISC-V 定义了一系列扩展指令集,满足不同领域和应用场景的需求。这些扩展指令集通过附加功能来增强性能、提高效率或支持特定功能。

以下是 RISC-V 的主要扩展指令集及其功能简介。

1. M 扩展(整数乘除扩展)

1.1 功能

M 扩展增加了整数的乘法和除法操作,适用于需要大量算术运算的应用。

1.2 乘法指令

指令功能说明示例
mul无符号整数乘法mul x3, x1, x2
mulh高位乘积(有符号乘法)mulh x3, x1, x2
mulhu高位乘积(无符号乘法)mulhu x3, x1, x2
mulhsu高位乘积(有符号*无符号乘法)mulshu x3, x1, x2
mulw低位乘积mulw x3, x1, x2

1.2.1 乘法指令格式

1

1.2.2 字段说明

位宽字段描述
7funct7用于指令功能标识
5rs2第二操作数(乘数/因子)
5rs1第一操作数(被乘数/因子)
3funct3功能选择(区分具体操作)
5rd目标寄存器(存放结果)
7opcode操作码,表示这是乘除法操作指令

1.2.3 示例

MUL a0, a1, a2 # a0 = a1 * a2 (低 XLEN 位结果)
MULH a0, a1, a2 # a0 = 高 XLEN 位的有符号乘法结果
MULHSU a0, a1, a2 # a0 = 高 XLEN 位的混合符号乘法结果
MULW a0, a1, a2 # a0 = 32 位乘法结果,符号扩展至 64 位

1.3 除法指令

指令功能说明示例
div有符号整数除法div x3, x1, x2
divu无符号整数除法divu x3, x1, x2
rem有符号整数取余rem x3, x1, x2
remu无符号整数取余remu x3, x1, x2
divw/remwRV64指令,仅对低 32 位操作,结果符号扩展至 64 位divw/remw x3, x1, x2

1.3.1 除法指令格式

2

1.3.2 字段说明

位宽字段描述
7funct7用于指令功能标识
5rs2第二操作数(除数)
5rs1第一操作数(被除数)
3funct3功能选择(区分具体操作)
5rd目标寄存器(存放结果)
7opcode操作码,表示这是乘除法操作指令

1.3.3 示例

DIV a0, a1, a2 # a0 = a1 / a2(商)
REM a0, a1, a2 # a0 = a1 % a2(余数)
DIVU a0, a1, a2 # a0 = 无符号(a1 / a2) 的商
REMU a0, a1, a2 # a0 = 无符号(a1 % a2) 的余数
DIVW a0, a1, a2 # a0 = 低 32 位 a1 / a2 的商,符号扩展至 64 位
REMW a0, a1, a2 # a0 = 低 32 位 a1 % a2 的余数,符号扩展至 64 位

2. A 扩展(原子操作扩展)

2.1 功能

标准的原子指令扩展(简称“A”)包含可以原子性地对内存进行读-改-写操作的指令,用于支持在共享内存空间中多个RISC-V硬件线程(hart)之间的同步。这些原子指令分为两种形式:保留加载/条件存储(Load-Reserved/Store-Conditional,LR/SC)指令和原子性取值并操作内存(Atomic Fetch-and-Op Memory)指令。这两种指令形式均支持包括无序、获取(Acquire)、释放(Release)和顺序一致(Sequentially Consistent)语义在内的多种内存一致性顺序。通过这些指令,RISC-V能够支持RCsc(Release Consistency with Sequential Consistency)内存一致性模型。

2.2 LR/SC指令

指令功能说明示例
lr.w加载并保留(Load Reserved)lr.w x3, (x1)
sc.w条件存储(Store Conditional)sc.w x3, x2, (x1)

2.2.1 指令格式

1

2.2.2 字段说明

位段范围字段名位宽描述
31funct55功能编码
27aq1获取顺序约束位
26rl1释放顺序约束位
25-24rs25源寄存器2
20-19rs15源寄存器1(地址)
15-14funct33功能编码
12-11rd5目标寄存器
7-6opcode7操作码

2.2.3 示例

这段代码实现了一个简单的 CAS 操作,通过 LR/SC 指令确保原子操作的正确性和内存一致性。

cas:
lr.w t0, (a0) # 加载原始值到 t0。
bne t0, a1, fail # 如果 t0 不等于 a1,则跳转到失败处理。
sc.w t0, a2, (a0) # 尝试更新为 a2 的值。
bnez t0, cas # 如果 store-conditional 失败,重试。
li a0, 0 # 设置返回值为成功。
jr ra # 返回。

fail:
li a0, 1 # 设置返回值为失败。
jr ra # 返回。

2.3 AMO指令

指令功能说明示例
AMOSWAP.W/D交换操作,指定源、地址、宽度和目标amoswap.w t0, t1, (a0)
AMOADD.W/D加法操作,指定源、地址、宽度和目标amoadd.w t0, t1, (a0)
AMOAND.W/D按位与操作,指定源、地址、宽度和目标amoand.w t0, t1, (a0)
AMOOR.W/D按位或操作,指定源、地址、宽度和目标amoer.w t0, t1, (a0)
AMOXOR.W/D按位异或操作,指定源、地址、宽度和目标amoxor.w t0, t1, (a0)
AMOMAX[U].W/D最大值操作,指定源、地址、宽度和目标amomax.w t0, t1, (a0)
AMOMIN[U].W/D最小值操作,指定源、地址、宽度和目标amomin.w t0, t1, (a0)

2.3.1 指令格式

1

2.3.2 字段说明

位宽字段描述
5funct5用于指令功能标识
1aq获取操作位 (Acquire)
1rl释放操作位 (Release)
5rs2第二个操作数 (操作数2)
5rs1第一个操作数 (操作数1)
3funct3功能选择 (区分具体操作)
5rd目标寄存器 (存放结果)
7opcode操作码,表示这是AMO操作指令

2.3.3 示例

以下是受测试和测试设置自旋锁保护的临界区的示例代码。

li t0, 1 # 初始化交换值
again:
lw t1, (a0) # 检查锁是否被持有
bnez t1, again # 如果锁被持有则重试
amoswap.w.aq t1, t0, (a0) # 尝试获取锁
bnez t1, again # 如果锁被持有则重试
# ...
# 临界区代码
# ...
amoswap.w.rl x0, x0, (a0) # 通过存储0释放锁

3. F 扩展(单精度浮点扩展)

3.1 功能

F 扩展为 RISC-V 添加了支持 IEEE 754 单精度浮点格式的指令。F 扩展指令集可以进行单精度浮点加法、减法、乘法、除法、比较以及其他常见的浮点运算,提供了处理浮点数的能力。这些指令使得 RISC-V 可以进行更高效的浮点计算,特别是在嵌入式系统、数字信号处理和图形计算等领域。

3.2 浮点运算指令

指令功能说明示例
FADD.S单精度浮点加法fadd.s f0, f1, f2
FSUB.S单精度浮点减法fsub.s f0, f1, f2
FMUL.S单精度浮点乘法fmul.s f0, f1, f2
FDIV.S单精度浮点除法fdiv.s f0, f1, f2
FMADD.S单精度浮点乘加(fused multiply-add)fmadd.s f0, f1, f2, f3
FMSUB.S单精度浮点乘减(fused multiply-subtract)fmsub.s f0, f1, f2, f3
FSGNJ.S单精度浮点设置符号fsgnj.s f0, f1, f2
FSQRT.S单精度浮点平方根fsqrt.s f0, f1
FCVT.W.S单精度浮点转整数(向下取整)fcvt.w.s x1, f0

3.2.1 指令格式

F 扩展指令的格式通常为 R-type 或 I-type 格式。具体格式如下:

R-type格式(例如:FADD.S, FMUL.S)

opcoderdfunct3rs1rs2funct7
7 bits5 bits3 bits5 bits5 bits7 bits
  • opcode:操作码,指定指令类型。
  • rd:目标寄存器,存储运算结果。
  • funct3:功能选择位,指定具体的操作类型(如加法、减法等)。
  • rs1:源寄存器 1,参与运算的第一个操作数。
  • rs2:源寄存器 2,参与运算的第二个操作数。
  • funct7:功能编码,指定具体指令的操作类型(如浮点加法、浮点乘法等)。

I-type格式(例如:FCVT.W.S)

opcoderdfunct3rs1imm
7 bits5 bits3 bits5 bits12 bits
  • opcode:操作码,指定指令类型。
  • rd:目标寄存器,存储运算结果。
  • funct3:功能选择位,指定具体操作。
  • rs1:源寄存器 1,参与运算的操作数。
  • imm:立即数,指定常数值(如转换为整数时的位移量)。

这些指令格式通过不同的opcode和funct3字段,能够指定不同的浮点运算和浮点数转换操作。

3.2.2 示例

  • FADD.S(单精度浮点加法)

该指令将两个单精度浮点数相加,并将结果存储在目标寄存器中。

fadd.s f0, f1, f2 # f0 = f1 + f2
  • FSUB.S(单精度浮点减法)

该指令执行浮点减法操作,将 f1 中的单精度浮点数减去 f2 中的浮点数,并将结果存储到 f3 中。

fsub.s f3, f1, f2 # f3 = f1 - f2
  • FMUL.S(单精度浮点乘法)

该指令执行浮点乘法操作,将 f1 和 f2 中的单精度浮点数相乘,并将结果存储到 f3 中。

fmul.s f3, f1, f2 # f3 = f1 * f2
  • FDIV.S(单精度浮点除法)

该指令执行浮点除法操作,将 f1 中的单精度浮点数除以 f2 中的浮点数,并将结果存储到 f3 中。

fdiv.s f3, f1, f2 # f3 = f1 / f2
  • FDIV.S(单精度浮点比较)

这些指令执行单精度浮点比较操作,分别比较 f1 和 f2 的相等性、小于关系以及小于等于关系,结果存储在 t0 中。

feq.s t0, f1, f2 # 如果 f1 == f2,t0 = 1,否则 t0 = 0
flt.s t0, f1, f2 # 如果 f1 < f2,t0 = 1,否则 t0 = 0
fle.s t0, f1, f2 # 如果 f1 <= f2,t0 = 1,否则 t0 = 0
  • FDIV.S(单精度浮点转换)

这些指令执行浮点与整数之间的转换,将 t0 中的整数转换为单精度浮点数,并将 f1 中的单精度浮点数转换为整数。

fcvt.s.w f1, t0 # 将整数 t0 转换为单精度浮点数,结果存储到 f1
fcvt.w.s t0, f1 # 将单精度浮点数 f1 转换为整数,结果存储到 t0
  • FDIV.S(单精度浮点加载和存储)

这些指令执行浮点数的加载和存储操作,分别将内存中的单精度浮点数加载到寄存器 f1 中,或者将寄存器 f1 中的单精度浮点数存储到内存中。

flw f1, 0(a0) # 从内存地址 a0 处加载单精度浮点数到 f1
fsw f1, 0(a0) # 将 f1 中的单精度浮点数存储到内存地址 a0 处
  • FDIV.S(单精度浮点绝对值操作)

该指令执行浮点数的绝对值操作,将 f1 中的单精度浮点数的绝对值存储到 f3 中。

fabs.s f3, f1 # f3 = |f1|
  • FDIV.S(单精度浮点其他操作)

这些指令执行常见的浮点操作,如平方根、符号调整、最小值和最大值操作。

fsqrt.s f3, f1 # f3 = √f1
fsgnj.s f3, f1, f2 # f3 = f1 的符号与 f2 相同的浮点数
fmin.s f3, f1, f2 # f3 = f1 和 f2 中的较小值
fmax.s f3, f1, f2 # f3 = f1 和 f2 中的较大值

4. D 扩展(双精度浮点扩展)

4.1. 功能

标准的双精度浮点指令集扩展,称为 “D”,该扩展增加了符合 IEEE 754-2008 算术标准的双精度浮点计算指令。D 扩展依赖于基础的单精度指令子集 F。

4.2 指令

指令功能说明示例
fld浮点数加载fld f1, 0(x1)
fsd浮点数存储fsd f1, 0(x1)
fadd.d双精度浮点加法fadd.d f1, f2, f3
fsub.d双精度浮点减法fsub.d f1, f2, f3
fmul.d双精度浮点乘法fmul.d f1, f2, f3
fdiv.d双精度浮点除法fdiv.d f1, f2, f3

4.2.1 指令格式

1

4.2.2 字段说明

字段说明
funct5指令功能码,用于指定指令的具体操作类型。对于不同的指令,funct5字段的值会有所不同,以区分不同的运算或操作。
fmt数据格式字段,指示操作数的浮点数格式。该字段用于指定源和目标寄存器中存储的浮点数的精度(如单精度、双精度等)。
rs2第二个源寄存器,参与运算的浮点寄存器。该字段指向需要与rs1操作的第二个浮点数值寄存器。
rs1第一个源寄存器,参与运算的浮点寄存器。该字段指向进行计算或存储操作的第一个浮点数值寄存器。
rm舍入模式字段,指定在进行浮点数运算时采用的舍入模式。它决定了在结果无法精确表示时应如何处理。
rd目标寄存器,存储操作结果的寄存器。该字段指定计算结果将被写入哪个浮点寄存器。
opcode操作码字段,标识指令的类型和类别。它用于指示该指令是执行何种类型的操作(如加载、存储、算术运算等)。

4.2.3 示例

  • 加载双精度浮点数
fld f1, 0(x1) # 从内存地址 x1 加载双精度浮点数到寄存器 f1
  • 存储双精度浮点数
fsd f1, 0(x1) # 将寄存器 f1 中的双精度浮点数存储到内存地址 x1
  • 双精度浮点加法
fadd.d f1, f2, f3 # 计算 f2 + f3,将结果存储到 f1
  • 双精度浮点减法
fsub.d f1, f2, f3 # 计算 f2 - f3,将结果存储到 f1
  • 双精度浮点乘法
fmul.d f1, f2, f3 # 计算 f2 * f3,将结果存储到 f1
  • 双精度浮点除法
fdiv.d f1, f2, f3 # 计算 f2 / f3,将结果存储到 f1

5. C 扩展(压缩指令集)

5.1 功能

本章描述了当前的RISC-V标准压缩指令集扩展提案,称为C,它通过为常见操作添加短16位指令编码来减少静态和动态代码大小。C扩展可以添加到任何基本ISA(RV32,RV64,RV128),我们使用通用术语RVC来涵盖这些。通常,程序中的50%-60%的RISC-V指令可以被RVC指令替代,从而减少25%-30%的代码大小。压缩指令的格式通常为16位,具体格式取决于指令类型。不同的指令类型将有不同的字段布局,用于编码操作码、寄存器编号和立即数等。

5.2 指令

指令功能说明示例
c.addi压缩版立即数加法c.addi x1, 10
c.lw压缩版加载字c.lw x1, 0(x2)
c.sw压缩版存储字c.sw x1, 0(x2)
c.j压缩版跳转c.j Label
c.beqz压缩版等于零分支跳转c.beqz x1, Label
c.bnez压缩版不等于零分支跳转c.bnez x1, Label
c.jal压缩版跳转并链接c.jal x1, Label
c.add压缩版加法c.add x1, x2, x3
c.sub压缩版减法c.sub x1, x2, x3
c.and压缩版与操作c.and x1, x2, x3
c.or压缩版或操作c.or x1, x2, x3
c.xor压缩版异或操作c.xor x1, x2, x3
c.slli压缩版左移立即数c.slli x1, x2, 2
c.srli压缩版右移立即数c.srli x1, x2, 2
c.srai压缩版算术右移立即数c.srai x1, x2, 2

5.2.1 指令格式

1

5.2.2 字段说明

字段名称说明
funct4CR 格式指令的功能字段,4 位
funct3CI、CSS、CIW、CL、CS、CA、CB、CJ 格式指令的功能字段,3 位
funct6CA 格式指令的功能字段,6 位
funct2CA 格式指令的附加功能字段,2 位
rd/rs1目标寄存器(rd)或源寄存器(rs1)
rs2额外的源寄存器(rs2)
imm立即数字段
offset分支指令的偏移量
jump target跳转指令的目标地址
op操作码字段

5.2.3 示例

以下是一些压缩指令的示例及其功能说明:

  • c.addi x1, 10

    c.addi x1, 10 # 将立即数 10 加入寄存器 x1
  • c.lw x1, 0(x2)

    c.lw x1, 0(x2) # 从地址 x2 加 0 加载字到寄存器 x1
  • c.sw x1, 0(x2)

    c.sw x1, 0(x2) # 将寄存器 x1 的值存储到地址 x2 加 0 的位置
  • c.j Label

    c.j Label # 跳转到标签 Label
  • c.beqz x1, Label

    c.beqz x1, Label # 如果寄存器 x1 为 0,则跳转到 Label
  • c.bnez x1, Label

    c.bnez x1, Label # 如果寄存器 x1 不为 0,则跳转到 Label
  • c.jal x1, Label

    c.jal x1, Label # 跳转到 Label,并将返回地址保存到 x1
  • c.add x1, x2, x3

    c.add x1, x2, x3 # 将寄存器 x2 和 x3 的值相加,结果存储到 x1
  • c.sub x1, x2, x3

    c.sub x1, x2, x3 # 从 x2 中减去 x3 的值,结果存储到 x1
  • c.and x1, x2, x3

    c.and x1, x2, x3 # 将寄存器 x2 和 x3 进行按位与,结果存储到 x1
  • c.or x1, x2, x3

    c.or x1, x2, x3 # 将寄存器 x2 和 x3 进行按位或,结果存储到 x1
  • c.xor x1, x2, x3

    c.xor x1, x2, x3 # 将寄存器 x2 和 x3 进行按位异或,结果存储到 x1
  • c.slli x1, x2, 2

    c.slli x1, x2, 2 # 将寄存器 x2 左移 2 位,结果存储到 x1
  • c.srli x1, x2, 2

    c.srli x1, x2, 2 # 将寄存器 x2 右移 2 位,结果存储到 x1
  • c.srai x1, x2, 2

    c.srai x1, x2, 2 # 将寄存器 x2 算术右移 2 位,结果存储到 x1

6. Zicsr 和 Zifencei 扩展(控制状态寄存器与指令屏障)

6.1 功能

Zicsr:提供对控制状态寄存器(CSR)的读写操作,允许程序访问和修改与特权状态和控制相关的寄存器。 Zifencei:用于处理指令流中的顺序一致性,确保写入指令内存的操作在后续指令获取之前可见。

6.2 指令

指令功能说明示例
csrrw读写 CSR 寄存器csrrw x1, csr, x2
csrrs读并设置 CSR 位csrrs x1, csr, x2
csrrc读并清除 CSR 位csrrc x1, csr, x2
csrrwi使用立即数写入 CSRcsrrwi x1, csr, 5
csrsi使用立即数设置 CSR 位csrsi x1, csr, 5
csrci使用立即数清除 CSR 位csrci x1, csr, 5
fence.i指令流同步屏障fence.i

6.2.1 指令格式

1

6.2.2 字段说明

字段名称说明
csr指定要操作的控制状态寄存器的地址
rs1源寄存器,用于提供值或立即数
funct3指令的功能类型(如读、写、设置、清除等)
rd存储读取到的 CSR 值的目标寄存器
opcode指令操作码,用于区分不同的操作类型

6.2.3 示例

  • csrrw 示例
csrrw x1, 0x300, x2 # 将 CSR 地址为 0x300 的值读入 x1,同时将 x2 的值写入 CSR
  • csrrs 示例
csrrs x1, 0x300, x2 # 将 CSR 地址为 0x300 的值读入 x1,并将 x2 中的位设置到 CSR
  • fence.i 示例
fence.i # 确保之前的存储操作对指令获取可见

7. 示例

7.1 进入示例

下载测试代码

下载解压并进入示例目录

7.2 编译

make

7.3 运行

make run

运行后LOG如下

qemu-system-riscv64 -nographic -machine virt -m 128M -bios m_mode.bin -device loader,file=s_mode.bin,addr=0x80200000 -kernel s_mode.elf
_____ ____ _____
/ ____| _ \_ _|
| (___ | |_) || |
\ \___ \| _ < | |
____) | |_) || |_
|_|_____/|____/_____|

Result of risc-v assembly 'mul x1, x2, x3' is: 15
Result of risc-v assembly 'mulh x1, x2, x3' is: -1
Result of risc-v assembly 'mulhsu x1, x2, x3' is: 1
Result of risc-v assembly 'mulw x1, x2, x3' is: 116650
Result of risc-v assembly 'div x1, x2, x3' is: 655
Result of risc-v assembly 'divu x1, x2, x3' is: 655
Result of risc-v assembly 'rem x1, x2, x3' is: 35
Result of risc-v assembly 'remu x1, x2, x3' is: 35
Result of LR operation: 0
Result of SC operation: 1 (new value: 0)
Result of AMOSWAP operation: 0 (new value: 100)
Result of AMOADD operation: 100 (new value: 110)
Result of risc-v assembly 'fadd.s x1, x2, x3' is: 4.70
Result of risc-v assembly 'fsub.s x1, x2, x3' is: 2.30
Result of risc-v assembly 'fmul.s x1, x2, x3' is: 4.20
Result of risc-v assembly 'fdiv.s x1, x2, x3' is: 2.92
Result of risc-v assembly 'fadd.d x1, x2, x3' is: 4.70
Result of risc-v assembly 'fsub.d x1, x2, x3' is: 2.30
Result of risc-v assembly 'fmul.d x1, x2, x3' is: 4.20
Result of risc-v assembly 'fdiv.d x1, x2, x3' is: 2.92

详见请参考文档:实验环境搭建。