跳到主要内容

RISC-V Zve32x:嵌入式整数向量扩展

Zve32x 是 RISC-V Vector 1.0 中面向嵌入式处理器的基础整数向量扩展。它把向量寄存器、配置指令、整数运算、定点运算、掩码、归约、排列和访存指令加入 RV32 或 RV64 标量处理器,但不要求浮点向量运算,也不要求 64 位元素运算。

Zve32x 依赖 Zicsr。实现必须支持至少 32 位的向量寄存器长度,并支持 8、16、32 位有效元素宽度。它适合音频处理、传感器数据、整数 DSP、轻量图像处理、密码算法的基础数据操作,以及不需要 FP32/FP64 向量单元的控制型处理器。

Zve32x 的定义范围

项目Zve32x 要求说明
可配套的标量 ISARV32 或 RV64XLEN 与向量寄存器宽度相互独立。
依赖扩展Zicsr向量控制状态通过 CSR 访问。
最小 VLEN32 位实现可以提供 64、128、256 位或更大的 VLEN
标准元素宽度上限32 位Zve32x 规定的最大 EEW 为 32;Zve32x-only 实现的 ELEN=32
支持的有效元素宽度 EEW8、16、32 位64 位元素操作不属于 Zve32x。
整数向量运算支持包括单宽、加宽、变窄、乘除、移位、比较和归约。
定点向量运算支持包括饱和、定点舍入、平均和裁剪。
向量访存支持包括单位步长、固定步长、索引、分段和整寄存器访存。
掩码与排列支持包括掩码逻辑、计数、前缀、slide、gather 和 compress。
浮点向量运算不支持需要 Zve32f 或更高扩展。
trap精确所有 Zve* 标准扩展均要求精确 trap。

与其他 Zve* 扩展的关系

扩展最小 VLEN必须支持的 EEWFP32FP64依赖关系
Zve32x328、16、32Zicsr
Zve32f328、16、32Zve32xF
Zve64x648、16、32、64Zve32x
Zve64f648、16、32、64Zve32fZve64xF
Zve64d648、16、32、64Zve64fD

Zve32fZve64x 均以 Zve32x 为基础。单字母 V 面向应用处理器,它依赖 Zve64dZvl128b,因此最小 VLEN=128,并完整支持 64 位整数和 FP64 向量运算。

misa.V 只表示单字母 V 扩展。实现 Zve32x 不等于置位 misa.V;操作系统、引导软件或平台接口应通过 ISA 扩展字符串等平台定义的方式报告 Zve32x

向量寄存器和调用约定

Zve32x 定义 32 个向量寄存器 v0v31,每个寄存器均为 VLEN 位。寄存器可以单独使用,也可按 LMUL=2/4/8 组成连续寄存器组。v0 在带掩码指令中保存执行掩码,但在不需要掩码时也可以保存普通向量数据。

标准向量调用约定把全部向量寄存器视为调用者可修改状态,不用于传递普通函数的向量参数或返回值。带 riscv_vector_cc 属性的变体调用约定使用 v0 传递第一个向量掩码参数并返回掩码结果,使用 v8v23 传递向量数据、向量 tuple 和其余掩码参数,同时返回向量数据或 tuple 结果。被调用函数必须保存 v1v7v24v31的全部内容。

下表列出全部 32 个寄存器、变体调用约定用途和寄存器组起始限制。m2/m4/m8 列表示该寄存器能否作为对应整数 LMUL 寄存器组的首寄存器。

寄存器常见用途标准调用约定riscv_vector_ccm2 起始m4 起始m8 起始
v0掩码或普通数据不保留首个掩码参数/返回值,不保留
v1普通数据不保留被调用者保存
v2普通数据不保留被调用者保存
v3普通数据不保留被调用者保存
v4普通数据不保留被调用者保存
v5普通数据不保留被调用者保存
v6普通数据不保留被调用者保存
v7普通数据不保留被调用者保存
v8参数或返回值不保留数据参数/返回值,不保留
v9参数或返回值不保留数据参数/返回值,不保留
v10参数或返回值不保留数据参数/返回值,不保留
v11参数或返回值不保留数据参数/返回值,不保留
v12参数或返回值不保留数据参数/返回值,不保留
v13参数或返回值不保留数据参数/返回值,不保留
v14参数或返回值不保留数据参数/返回值,不保留
v15参数或返回值不保留数据参数/返回值,不保留
v16参数或返回值不保留数据参数/返回值,不保留
v17参数或返回值不保留数据参数/返回值,不保留
v18参数或返回值不保留数据参数/返回值,不保留
v19参数或返回值不保留数据参数/返回值,不保留
v20参数或返回值不保留数据参数/返回值,不保留
v21参数或返回值不保留数据参数/返回值,不保留
v22参数或返回值不保留数据参数/返回值,不保留
v23参数或返回值不保留数据参数/返回值,不保留
v24普通数据不保留被调用者保存
v25普通数据不保留被调用者保存
v26普通数据不保留被调用者保存
v27普通数据不保留被调用者保存
v28普通数据不保留被调用者保存
v29普通数据不保留被调用者保存
v30普通数据不保留被调用者保存
v31普通数据不保留被调用者保存

整数 LMUL=2 的寄存器组必须从偶数寄存器开始;LMUL=4 必须从 4 的倍数开始;LMUL=8 必须从 8 的倍数开始。例如 v8m4 下表示 v8v11,指令中不能把 v9 写成该组的首寄存器。

VLEN、SEW、EEW、LMUL 与 EMUL

Zve32x 的数据组织由以下参数决定。

名称定义Zve32x 中的含义
XLEN整数寄存器宽度32 或 64 位。影响地址和标量操作数,不决定向量寄存器宽度。
VLEN单个向量寄存器位数至少 32 位、2 的幂,且不大于规范允许的上限。
ELEN任一向量操作支持的最大元素位数Zve32x 至少为 32。
SEWvtype 选择的标准元素宽度Zve32x 的有效值为 8、16、32。
EEW某个操作数的有效元素宽度通常等于 SEW;加宽、变窄和显式宽度访存中可以不同。
LMULvtype 选择的向量寄存器组倍率支持 m1/m2/m4/m8,并支持规定范围内的分数倍率。
EMUL某个操作数实际占用的寄存器组倍率EMUL = LMUL × EEW / SEW
VLMAX当前配置可容纳的最大元素数VLMAX = LMUL × VLEN / SEW
vl当前指令实际处理的元素数满足 0 ≤ vl ≤ VLMAX

例如,VLEN=128SEW=16LMUL=2 时,VLMAX=16。同一条加宽指令若源操作数 EEW=16、目的操作数 EEW=32,目的寄存器组的 EMUL=4,因此目的值需要四个连续向量寄存器。

所有实现必须支持整数 LMUL=1/2/4/8。分数 LMUL 用于减少窄元素占用的寄存器空间。规范要求实现支持 LMUL ≥ SEW_MIN/ELEN 的分数配置。Zve32x 的 SEW_MIN=8ELEN=32,因此 mf2mf4 必须可用;mf8 可以不实现,不支持时配置结果进入 vill 状态。

Zve32x 的七个向量 CSR

地址CSR权限位宽/字段详细作用
0x008vstartURWXLEN保存下一次开始执行的元素序号。正常完成向量指令后清零;精确 trap 可保存未完成位置。
0x009vxsatURW[0]定点饱和累积标志。任一活动元素发生饱和时置 1,后续普通运算不会自动清零。
0x00AvxrmURW[1:0]定点舍入模式。影响平均、缩放移位、饱和乘法和裁剪等指令。
0x00FvcsrURW[2:1]=vxrm[0]=vxsatvxrmvxsat 的组合视图。写任一视图会反映到另一个视图。
0xC20vlUROXLEN当前向量长度。软件通过 vsetvlivsetivlivsetvl 间接更新。
0xC21vtypeUROXLEN当前 SEW、LMUL、tail/mask 策略和非法配置标志。由向量配置指令写入。
0xC22vlenbUROXLENVLEN/8,在同一 hart 上为常数,用于分配上下文保存空间。

vstart 主要用于 trap 后恢复。应用程序通常不主动写入非零值,因为部分实现对非零 vstart 的执行速度较低,某些指令也要求 vstart=0。标准调用约定要求函数入口和函数返回时 vstart=0

vxrm 定点舍入模式

编码助记名称加入被丢弃位后的处理
00rnuround-to-nearest-up最近值;正好居中时向上。
01rneround-to-nearest-even最近值;正好居中时使保留结果最低位为偶数。
10rdnround-down直接截断被移出的低位。
11rodround-to-odd若被丢弃部分非零,则将保留结果最低位置 1。

vtype 字段和 Zve32x 有效编码

字段位位置含义
vill[XLEN-1]非法或不支持的 vtype 配置。置 1 时其余位和 vl 为 0。
保留[XLEN-2:8]当前写 0;软件读取时不依赖其值。
vma[7]掩码关闭元素策略:0 为 undisturbed,1 为 agnostic。
vta[6]tail 元素策略:0 为 undisturbed,1 为 agnostic。
vsew[5:3]标准元素宽度编码。
vlmul[2:0]LMUL 的有符号编码。

vsew 编码

vsewSEWZve32x 状态
0008必须支持。
00116必须支持。
01032必须支持。
01164Zve32x 不支持,配置产生 vill
100111128 及以上Zve32x 不支持,配置产生 vill

vlmul 编码

vlmulLMULZve32x 要求
000m1 = 1必须支持。
001m2 = 2必须支持。
010m4 = 4必须支持。
011m8 = 8必须支持。
100保留产生 vill
101mf8 = 1/8Zve32x 不强制实现。
110mf4 = 1/4必须支持。
111mf2 = 1/2必须支持。

向量配置指令

指令AVL 来源vtype 来源适用情况
vsetvli rd, rs1, vtypeix[rs1] 或特殊 x0 形式指令立即数字段运行期长度与常见 SEW/LMUL 配置。
vsetivli rd, uimm, vtypei5 位零扩展立即数指令立即数字段元素数较小且编译期已知。
vsetvl rd, rs1, rs2x[rs1] 或特殊 x0 形式x[rs2] 中的完整 vtype上下文恢复或动态恢复已有配置。

vsetvli 的常见形式如下:

# a0 = 尚未处理的元素数;t0 = 本次实际处理的元素数
vsetvli t0, a0, e32, m1, ta, ma

e32 选择 SEW=32m1 选择一个寄存器组成一个逻辑向量;ta 表示 tail-agnostic,ma 表示 mask-agnostic。指令把实际 vl 写入 t0,同时更新 vlvtype CSR。

AVL 与 vl 的确定规则

设应用请求长度为 AVL,则配置指令按以下规则选择 vl

AVL 条件vl 约束
AVL = 0vl = 0
0 < AVL ≤ VLMAXvl = AVL
VLMAX < AVL < 2 × VLMAXceil(AVL/2) ≤ vl ≤ VLMAX
AVL ≥ 2 × VLMAXvl = VLMAX

同一实现对相同 AVL 和 VLMAX 必须给出确定结果。程序不能假设第二种区间以外的 vl 总等于 VLMAX,而应使用配置指令返回值更新地址和剩余计数。

vsetvlirs1≠x0 时,AVL 来自整数寄存器;rs1=x0rd≠x0 时,AVL 视为全 1,从而请求 VLMAXrs1=x0rd=x0 时,以原 vl 作为 AVL,该形式用于保持 vl 的配置变化,并要求新的配置不改变实际 vl

元素执行状态与掩码

对一条向量指令,元素序号可分为四类:

元素类别序号或条件指令行为
prestartindex < vstart本次不执行,用于 trap 恢复。
activevstart ≤ index < vl 且掩码允许执行指令定义的运算并写结果。
inactivevstart ≤ index < vl 且掩码关闭vma 保留旧值或写入未指定值。
tailvl ≤ index < VLMAXvta 保留旧值或写入未指定值。

向量指令编码中的 vm=1 表示不使用掩码;vm=0 表示由 v0 的对应掩码位控制。汇编语法用 v0.t 明确带掩码执行:

vmsne.vi v0, v8, 0          # v0[i] = (v8[i] != 0)
vadd.vv v10, v8, v9, v0.t # 仅处理 v0[i] = 1 的活动元素

v0 作为掩码源时,目的寄存器组与 v0 的重叠受到指令规则限制。掩码结果按每个元素一位存放,与当前 SEW 无关。vcpop.m 可统计掩码中置位元素数,vfirst.m 可返回第一个置位元素序号。

Zve32x 指令类别

Zve32x 支持 V 规范中的整数、定点、访存、掩码、整数归约和整数排列指令,但仅允许 8、16、32 位有效元素宽度。

类别代表指令说明
配置vsetvlivsetivlivsetvl设置 vl、SEW、LMUL 和非活动元素策略。
单位步长访存vle8/16/32.vvse8/16/32.v连续地址读写;宽度由助记符直接指定。
固定步长访存vlse*.vvsse*.v步长来自整数寄存器,允许正、负和零。
无序索引访存vluxei*.vvsuxei*.v向量元素提供字节偏移,不保证元素访问顺序。
有序索引访存vloxei*.vvsoxei*.v按元素序号维持规定的访问顺序。
分段访存vlseg*e*.vvsseg*e*.v读取或写入结构体式多字段数据。
fault-only-firstvle*ff.v只要求第一个活动元素的异常精确进入 trap,后续元素故障可缩短 vl
整寄存器访存vl1re*.vvl2re*.vvl4re*.vvl8re*.v 及对应存储不依赖当前 vtype 保存和恢复完整寄存器内容。
整数加减vaddvsubvrsubvadcvsbc支持向量-向量、向量-标量和部分立即数形式。
逻辑vandvorvxor按元素执行位逻辑。
移位vsllvsrlvsra移位量按元素宽度截取。
比较vmseqvmsnevmsltvmslevmsgt结果写入掩码寄存器。
最小/最大vminuvminvmaxuvmax分有符号和无符号形式。
乘除与余数vmulvmulh*vdiv*vrem*Zve32x 支持 8/16/32 位整数乘除。
加宽运算vwadd*vwsub*vwmul*vwaddu.w*结果 EEW 为源 EEW 的两倍;Zve32x 可执行 8→16、16→32。
变窄运算vnsrlvnsravnclip*结果 EEW 为源 EEW 的一半;Zve32x 可执行 32→16、16→8。
整数扩展vzext.vf2/vf4vsext.vf2/vf4将窄元素零扩展或符号扩展。具体倍率受 EEW≤32 限制。
饱和加减vsadduvsaddvssubuvssub饱和时置 vxsat
定点平均和缩放vaadduvaaddvasubuvasubvssrlvssra使用 vxrm 控制舍入。
定点乘法与裁剪vsmulvnclipuvnclip饱和结果置 vxsat
整数归约vredsumvredmax*vredmin*vredand/or/xor将活动元素归并到目的寄存器元素 0。
加宽归约vwredsumuvwredsum8→16 或 16→32 的加宽求和。
掩码逻辑vmand*vmor*vmxor*vmnot.m对掩码位执行逻辑。
掩码生成与计数vmsbf.mvmsif.mvmsof.mviota.mvid.vvcpop.mvfirst.m生成前缀掩码、元素序号或统计结果。
排列vmvvmergevslideup/downvslide1up/downvrgathervcompress在寄存器内移动、选择和压缩元素。

Zve32x 不支持浮点向量算术、浮点归约或以浮点值为操作数的排列指令。SEW=32 的加宽结果需要 64 位 EEW,因此不属于 Zve32x;同理,任何显式 64 位元素访存和索引操作都不可使用。

基于 vl 的 32 位向量加法

下例计算 dst[i] = lhs[i] + rhs[i]。代码不依赖固定 VLEN;每次迭代使用返回的 vl 更新三个地址和剩余元素数。

# a0 = count, a1 = lhs, a2 = rhs, a3 = dst
.Lloop:
vsetvli t0, a0, e32, m1, ta, ma
vle32.v v8, (a1)
vle32.v v9, (a2)
vadd.vv v10, v8, v9
vse32.v v10, (a3)

slli a4, t0, 2 # 当前字节数 = vl × sizeof(int32_t)
add a1, a1, a4
add a2, a2, a4
add a3, a3, a4
sub a0, a0, t0
bnez a0, .Lloop

VLEN=32LMUL=1,一次只能处理一个 32 位元素;若 VLEN=128,一次最多处理四个;若 VLEN=256,一次最多处理八个。二进制指令序列保持不变,差异只体现在每次配置得到的 vl

8 位无符号饱和加法

下例使用 vsaddu.vv 计算无符号 8 位饱和加法,并在整个数组处理后读取 vxsatvxsat 是累积标志,因此循环前先清零,循环内任一元素饱和都会使最终读值为 1。

csrwi vxsat, 0

.Lsat_loop:
vsetvli t0, a0, e8, m1, ta, ma
vle8.v v8, (a1)
vle8.v v9, (a2)
vsaddu.vv v10, v8, v9
vse8.v v10, (a3)

add a1, a1, t0
add a2, a2, t0
add a3, a3, t0
sub a0, a0, t0
bnez a0, .Lsat_loop

csrr a0, vxsat # a0=1 表示至少一个元素发生饱和

精确 trap、vstart 与上下文保存

Zve32x 要求精确 trap。向量指令在元素 k 处中断时,实现可以把 vstart 设置为 k,trap 返回后从该元素继续。指令成功完成后,vstart 必须清零。部分指令要求 vstart=0,软件不能把 vstart 当作普通循环索引使用。

mstatus.VSsstatus.VS 记录向量上下文状态:

编码状态含义
00Off执行向量指令或访问向量 CSR 产生非法指令异常。
01Initial向量状态已启用,软件可按初始状态处理。
10Clean向量状态自上次保存后未被修改。
11Dirty向量寄存器或 CSR 可能已修改,上下文切换需要保存。

操作系统保存向量上下文时需要处理 v0v31vtypevlvstartvxrmvxsatvlenb 给出单个寄存器的字节数,可用于计算每个线程所需的保存区。整寄存器 load/store 指令允许在不知道原 SEW 和 LMUL 的情况下复制寄存器位模式。

RTL 结构与实现要求

最小 VLEN=32 的 Zve32x 实现仍必须提供 32 个架构向量寄存器和完整的 vl/vtype/vstart 行为。实现可以采用 32 位数据通路逐元素执行,也可以采用多 lane 并行结构;两者对软件呈现相同的架构状态。

  • 向量寄存器文件的实际读写端口数由每周期发射元素数、掩码读取、加宽目的组和访存结构决定。
  • 解码阶段需要根据 SEW、LMUL、EEW 计算每个操作数的 EMUL,并检查寄存器组起始编号、组宽和重叠规则。
  • vl 只限制活动元素数,不改变寄存器文件的物理宽度;tail 和 inactive 元素的写入行为由 vta/vma 决定。
  • 访存单元需要按元素生成地址,并为单位步长、固定步长和索引模式提供不同的地址来源。精确异常还要求记录首个未完成元素。
  • 定点指令同时更新向量目的寄存器和 vxsat,两类状态必须在异常、清流水和重放时保持一致。
  • 不支持的 SEW、LMUL 或 EEW 组合必须通过 vill 或非法指令异常体现,不能静默按较窄数据执行。
  • VLEN 大于最小值时,软件仍只能依赖 vlenbvl 和 VLMAX 公式,不能根据实现名称假定固定宽度。

参考:RISC-V Vector 1.0 与 Zve* 定义RISC-V Vector 汇编示例RISC-V psABI 向量寄存器约定