1. 引言
以下是《riscv-v-spec-1.0.pdf》文档的关键内容:
这是一份关于向量扩展的详细技术文档,内容覆盖了向量指令集的多个关键方面,如向量寄存器状态映射、向量指令格式、向量加载和存储操作、向量内存对齐约束、向量内存一致性模型、向量算术指令格式、向量整数和浮点算术指令、向量归约操作、向量掩码指令、向量置换指令、异常处理以及标准向量扩展等。
首先,文档定义了向量元素和向量寄存器状态之间的映射关系,并阐述了向量指令的格式。在此基础上,提出了配置设置指令,如vsetvl、ivsetiv和vlsetvl,用于设定向量长度(VL)和向量对齐长度(AVL)。
接着,文档详细说明了向量加载和存储操作,以及向量内存对齐和一致性模型。这些模型确保了向量操作的高效性和准确性。
然后,文档介绍了向量算术指令格式,包括向量整数、固定点和浮点算术指令。这些指令支持广泛的数学运算,为高性能计算提供了强大的支持。
此外,文档还涉及向量归约操作、掩码指令和置换指令,这些指令增强了向量操作的灵活性和功能性。
最后,文档讨论了异常处理机制,并列举了标准向量扩展指令列表。这些扩展指令为向量处理器提供了丰富的功能集,使其能够适应不同的应用场景和性能需求。
综上所述,这份文档为向量指令集的设计和实现提供了全面的指导和参考,有助于开发者更好地理解和利用向量处理器的能力。
【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(一)-向量扩展编程模型-CSDN博客
【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(二)-向量元素到向量寄存器状态的映射-CSDN博客
5 向量指令格式
该向量扩展的指令位于两个现有的主要操作码(LOAD-FP 和 STORE-FP)以及一个新的主要操作码(OP-V)之下。
向量加载和存储是在标量浮点加载和存储主要操作码(LOAD-FP/STORE-FP)内编码的。向量加载和存储编码重新利用了标准标量浮点加载/存储12位立即字段的一部分,以提供进一步的向量指令编码,其中第25位保留标准向量掩码位(参见掩码编码)。
LOAD-FP 主要操作码下的向量加载指令格式
STORE-FP 主要操作码下的向量存储指令格式
OP-V 主要操作码下的向量算术指令格式
OP-V 主要操作码下的向量配置指令格式
向量指令可以具有标量或向量源操作数,并产生标量或向量结果,并且大多数向量指令可以在掩码下无条件地或有条件地执行。
向量加载和存储操作在向量寄存器元素和内存之间移动位模式。向量算术指令对向量寄存器元素中保存的值进行操作。
5.1 标量操作
标量操作数可以是立即数,或者取自x寄存器、f寄存器或向量寄存器的元素0。标量结果被写入x或f寄存器,或者写入向量寄存器的元素0。任何向量寄存器都可以用来保存标量,无论当前的LMUL设置如何。
注意
Zinx(“X中的F”)是一个提议中的新ISA扩展,其中浮点指令从整数寄存器ile中获取参数。向量扩展也与Zinx兼容,其中Zinx向量扩展具有向量-标量浮点指令,这些指令从x寄存器中获取其标量参数。
我们曾考虑但没有采用将f寄存器叠加在v寄存器上的方法。所采用的方法减少了向量寄存器的压力,避免了与标准调用约定的交互,简化了高性能标量浮点设计,并提供了与Zinx ISA选项的兼容性。将f与v叠加在某些实现中会降低状态位的数量,但会复杂化高性能设计,并会阻止与提议的Zinx ISA选项的兼容性。
5.2 向量操作
每个向量操作数都有一个有效元素宽度(EEW)和一个有效LMUL(EMUL),用于确定向量寄存器组内所有元素的大小和位置。默认情况下,对于大多数指令的大多数操作数,EEW=SEW且EMUL=LMUL。
一些向量指令的源和目标向量操作数具有相同数量的元素,但宽度不同,因此EEW和EMUL分别与SEW和LMUL不同,但EEW/EMUL = SEW/LMUL。例如,大多数扩展算术指令的源组具有EEW=SEW和EMUL=LMUL,但其目标组具有EEW=2SEW和EMUL=2LMUL。缩小指令的源操作数具有EEW=2SEW和EMUL=2LMUL,但其目标操作数的EEW=SEW且EMUL=LMUL。
向量操作数或结果可能根据EMUL占用一个或多个向量寄存器,但总是使用组中的最低编号向量寄存器进行指定。使用除最低编号向量寄存器以外的其他寄存器来指定向量寄存器组是保留编码。
目标向量寄存器组只有在以下情况之一成立时才能与源向量寄存器组重叠:
- 目标EEW等于源EEW。
- 目标EEW小于源EEW,并且重叠位于源寄存器组的最低编号部分(例如,当LMUL=1时,vnsrl.w v0, v0, 3是合法的,但目标为v1则不是)。
- 目标EEW大于源EEW,源EMUL至少为1,并且重叠位于目标寄存器组的最高编号部分(例如,当LMUL=8时,vzext.vf4 v0, v6是合法的,但源为v0、v2或v4则不是)。
为了确定寄存器组重叠约束,掩码元素具有EEW=1。
注意:重叠约束旨在支持没有寄存器重命名的机器中的可恢复异常。
任何违反重叠约束的指令编码都是保留的。
指令使用的最大向量寄存器组不能超过8个向量寄存器(即EMUL=8),如果向量指令需要一个组中的向量寄存器超过8个,则该指令编码是保留的。例如,当LMUL=8时,产生加宽向量寄存器组结果的加宽操作是保留的,因为这意味着结果EMUL=16。
加宽的标量值(例如,加宽归约操作的输入和输出)保存在向量寄存器的第一个元素中,并且具有EMUL=1。
5.3 向量掩码
许多向量指令支持屏蔽功能。被屏蔽(非活动)的元素操作永远不会生成异常。根据vtype中vma位(见“向量尾部不可知和向量屏蔽不可知vta和vma”部分)的设置,对与被屏蔽元素对应的目标向量寄存器元素的处理采用屏蔽不变或屏蔽不可知策略。
用于控制屏蔽向量指令执行的屏蔽值始终由向量寄存器v0提供。
注意:未来的向量扩展可能会提供更长的指令编码,其中包含完整的屏蔽寄存器指定器的空间。
除非正在用屏蔽值(例如,比较)或归约的标量结果写入目标向量寄存器,否则屏蔽向量指令的目标向量寄存器组不能与源屏蔽寄存器(v0)重叠。这些指令编码是保留的。
注意:此约束支持使用非零vstart值进行重新启动。
其他向量寄存器可用于保存工作屏蔽值,并提供了屏蔽向量逻辑操作来执行谓词计算。
如“向量尾部不可知和向量屏蔽不可知vta和vma”部分中所述,无论vta的设置如何,屏蔽目标值始终被视为尾部不可知。
5.3.1 掩码编码
如果可用,屏蔽功能在指令中的单比特vm字段(inst[25])中进行编码。
VM |
描述 |
0 |
vector result, only where v0.mask[i] = 1 |
1 |
unmasked |
在汇编代码中,向量屏蔽被表示为另一个向量操作数,其中“.t”表示当v0.mask[i]为1(t表示“true”)时进行操作。如果没有指定屏蔽操作数,则假定为非屏蔽向量执行(vm=1)。
vop.v* v1, v2, v3, v0.t # enabled where v0.mask[i]=1, vm=0
vop.v* v1, v2, v3 # unmasked vector operation, vm=1
注意
尽管当前的向量扩展只支持一个向量屏蔽寄存器v0和仅支持真实形式的谓词判断,但汇编语法还是将其完整写出,以便与未来的扩展兼容,这些扩展可能会添加一个屏蔽寄存器指定器并支持真实和补码屏蔽值。屏蔽操作数上的“.t”后缀也有助于从视觉上编码屏蔽的使用。
“.mask”后缀不是汇编语法的一部分。我们只在屏蔽向量被下标的情况下附加它,例如v0.mask[i]。
5.4 其他
在执行向量指令期间操作的目标元素索引可以分为三个不相交的子集。
预启动元素是指那些元素索引小于vstart寄存器中初始值的元素。预启动元素不会引发异常,也不会更新目标向量寄存器。
主体元素是指那些元素索引大于或等于vstart寄存器中的初始值,并且小于vl中当前向量长度设置的元素。主体可以分为两个不相交的子集:
在执行向量指令期间,活动元素是指主体内的元素,并且在该元素位置上启用了当前屏蔽。活动元素可以引发异常并更新目标向量寄存器组。
非活动元素是指主体内的元素,但在该元素位置上禁用了当前屏蔽。非活动元素不会引发异常,也不会更新任何目标向量寄存器组,除非指定了屏蔽不可知(vtype.vma=1),在这种情况下,非活动元素可能会被1覆盖。
在执行向量指令期间的尾部元素是指超过vl中指定的当前向量长度设置的元素。尾部元素不会引发异常,也不会更新任何目标向量寄存器组,除非指定了尾部不可知(vtype.vta=1),在这种情况下,尾部元素可能会被1覆盖,或者在产生屏蔽的指令(除了屏蔽加载)的情况下,被指令的结果覆盖。当LMUL<1时,尾部包括在同一向量寄存器中超过VLMAX的元素。
for element index x
prestart(x) = (0 <= x < vstart)
body(x) = (vstart <= x < vl)
tail(x) = (vl <= x < max(VLMAX,VLEN/SEW))
mask(x) = unmasked || v0.mask[x] == 1
active(x) = body(x) && mask(x)
inactive(x) = body(x) && !mask(x)
当vstart = vl时,不存在主体元素,且任何目标向量寄存器组中都不会有元素被更新,包括尾部元素也不会被不可知值更新。
备注:
因此,当vl=0时,无论vstart的值如何,目标向量寄存器组中都不会有任何元素(包括不可知元素)被更新。
即使vstart = vl(包括vl=0的情况),写入x寄存器或f寄存器的指令也会执行写入操作。
备注:
某些指令(如vslidedown和vrgather)可能会从源向量寄存器组中读取超过vl甚至VLMAX的索引。一般的策略是,当源向量寄存器组中的索引大于VLMAX时,返回值为0。