RISC-V vector扩展

1. 一些参数定义:
  • ELEN:一个向量元素的最大位宽,须为2的指数。
  • VLEN:一个单独的向量寄存器的宽度,须为2的指数,最宽为2^{16},VLEN \geqslant ELEN。
  • LMUL:组合在一起的向量寄存器的数量。
  • SEW:实际一个向量元素的宽度。
  • VL:一条指令可以操作的向量元素的数量,VLMAX=LMUL*VLEN/SEW,由于SEWmin=8,LMULmax=8,因此 VLMAX 等于VLEN。 
  • AVL:一个应用程序要处理的向量元素的个数。
2. Vector扩展编程模型

        向量扩展在RISC-V基础标量指令集的基础上增加了32个向量寄存器7个非特权CSR寄存器。CSR寄存器如下表所示,关键的是vtype和vl寄存器。

RISC-V vector扩展_第1张图片

        mstatus寄存器中添加了一个向量上下文状态域 VS(mstatus[10:9]),类似于其中的浮点上下文状态域 FS。当 VS 关闭时,任何试图执行向量指令、或访问向量CSR寄存器的操作都会引起非法指令异常。当存在 hypervisor 扩展时,vsstatus寄存器也需要添加一个向量上下文状态域。

2.1 vtype 寄存器(Vector typer register)

  • 只读,XLEN-wide,只能通过 vset{i}vl{i} 指令更新;
  • 用于解释向量寄存器组的内容,指明了每个向量寄存器中的元素是如何组织的、多个向量寄存器是如何组合的,以及masked-off元素和超出向量长度的元素在一个向量结果中如何被处理。
  • 如下图所示,包括五个域,其中[XLEN-2:8]为0。

RISC-V vector扩展_第2张图片

  •  vsew[2:0]:用于设置动态向量元素宽度,可设置8~64位宽;
  • vlmul[2:0]:可以组合多个向量寄存器将其视为一个寄存器,该字段用于表示组合的寄存器的数量。基础地可以设为1,2,4,8(最大值),此外也可以设为分数1/2,1/4,1/8,表示只占用一个向量寄存器的一部分。分组的寄存器必须是连续的几个寄存器,例如LMUL为2时,一个寄存器组由Vn和Vn+1构成。
  • vta/vma:vector tail agnostic/vector mask agnostic,“agnostic”表示在指令执行过程中不必须保持寄存器中该部分的旧值。因此这两位分别表示在向量指令执行过程中对于寄存器中的tail元素和非活跃masked-off元素的处理方式(覆盖写 or 保留旧值 or 其他方式)。如果置为1则表示不必须保持旧值。
  •  vill:非法配置时置位,置位时任何依赖于vtype的向量指令的执行都会导致非法指令异常。

向量元素索引划分:在一条向量指令执行过程中,要操作的所有向量元素可以分为三部分,如下图所示(划分的单位是一个向量元素)。

RISC-V vector扩展_第3张图片

  • prestart:元素索引低于 vstart 寄存器起始值的向量元素,这部分内容不会引起异常也不会更新目标寄存器。
  • body:元素索引不低于 vstart 寄存器起始值,且小于当前向量长度的向量元素。这部分内容又可分为两部分:active 和 inactive部分,active部分指 mask 使能的元素位,inactive指 mask 未使能的元素位,inactive 内容不会引起异常且只在 vtype.vma 为1时更新目标寄存器。
  • tail:超出vl指示的向量个数的向量元素部分。

2.2 vl 寄存器(vector length register)

  • 这里的 “length” 指的是向量元素个数;
  • 只读,XLEN-width,只能被 vset{i}vl{i} 指令、fault-only-first 向量 load指令及其变种更新;
  • 用于指示一条指令需要处理的向量元素的个数。

2.3 vstart 寄存器(vector start  index CSR)

  • 指示一条要执行的向量指令首元素的索引;
  • 通常只能被硬件通过一条向量指令的 trap 写,vstart 值表示发生 trap 的元素,指示 trap 处理结束后应该从哪个元素继续执行;
  • 所有的向量指令根据 vstart 寄存器所给的元素数开始执行,每次向量指令执行结束后 vstart 被重置为0(包括 vset{i}vl{i} 指令);

3. 向量元素到向量寄存器状态的映射

        根据当前的 VLEN、SEW 和 LMUL 配置将不同宽度的向量元素打包到一个向量寄存器中,小端模式。

  • LMUL=1
  • LMUL<1:只有第一个LMUL*VLEN/SEW元素有用,其余元素位被视为 tail;
  • LMUL>1:从该组编号最低的寄存器开始打包
  • 混合宽度操作的映射:当对宽度不同的向量进行操作时,通过修改 vtype 保持 vl 一致,即保证操作元素个数相同。

混合宽度操作映射举例:

        在下例中,同时对宽度为  8b、16b、32b 和 64b 的元素打包,VLEN=128b。

RISC-V vector扩展_第4张图片

         可以看到,通过对每个宽度的元素设置不同的 SEW 和 LMUL 值,打包后每个宽度的元素个数均为8。

4. vector masking

        许多向量指令都支持 masking,masked off 的元素不会导致异常,目标向量寄存器对应的元素根据 mask-undisturbedmask-agnostic 机制处理,根据 vtype.vma 确定采用哪种机制。

        用于控制掩码向量执行的掩码值由向量寄存器 v0 提供。寄存器 v0 的一位控制一个向量元素,元素数量不会超过 v0 宽度,因为 v0 宽度 VLEN 即为 VLMAX的最大值。

        指令编码中的 vm 位指示 masking 情况,当 vm 为 0 时表示 masked。

5. 配置设置指令(vsetvli/vsetivli/vsetvl)

        一个通用的处理大量元素的方法是“stripmining”,即通过循环迭代的方式,每次迭代处理一定数量的元素,直到所有元素处理完毕。RISC-V的向量扩展为这种方法提供了直接的、合适的支持。应用程序指定要处理的元素总数作为 vl 的候选值,硬件基于 vtype 的设置计算,通过一个通用目的寄存器返回硬件每次迭代处理的元素个数。

        基于上述思想,RISC-V 提供了一组指令用于快速配置 vl 和 vtype 的值以满足应用程序的需求。vset{i}vl{i} 指令基于参数设置 vtype 和 vl CSR寄存器,并将 vl 的新值写回 rd(vl 即为本次迭代要处理的元素数量)。

RISC-V vector扩展_第5张图片

stripmining 举例:

RISC-V vector扩展_第6张图片

6. 向量 load 和 store

        向量 load 和 store 在向量寄存器和存储器之间移动值,是 masked 的,非活跃元素不会引起异常。masked 的向量 load 不会更新向量寄存器组中的非活跃元素,除非开启 mask-agnostic 机制;masked 的向量 store 则只会更新活跃的存储器元素。 

6.1 指令编码

RISC-V vector扩展_第7张图片

  • rs1:基址寄存器
  • rs2/vs2:偏移标量/向量寄存器
  • vs3/vd:保存 store/load 数据的向量寄存器
  • vm:指示 masking 是否使能,为 0 时使能
  • width[2:0]:指示存储元素的 size
  • mop[1:0]:指示访存地址模式
  • nf[2:0]:指示每个段的区域数,用于段 load/store
  • lumop[4:0]/sumop[4:0]:编码 unit-stride 指令的变种指令

        unit-stride 和 constant-strided 方式直接将EEW编码为指令中静态传输的数据的宽度,以减少在混合宽度元素访存过程中 vtype 变化的次数。indexed 方式则。。。。

6.2 vertor load/store 地址模式

        支持 unit-stride 、constant-strided 和 indexed 三种地址模式,基址寄存器和步幅来自通用寄存器组。在指令编码中通过 mop[1:0] 指示地址模式。

  • unit-stride:访问从基址指示的连续的元素,具体可以分为四种(unit-stride load,whole register load,mask load,fault-only-first)。
  • constant-strided:从基址元素开始,访问固定增量地址的元素,地址偏移量存储在一个标量寄存器中;
  • indexed:类似于constant-stride,但地址偏移量存储在向量寄存器组中。指令执行时有一组数据向量寄存器组和一组偏移量向量寄存器组。可分为 ordered 和 unordered 模式,对于 unordered 指令,不保证元素的访问顺序。(PS.上述两种地址模式均不必保证访问顺序)

6.3 向量 load/store 宽度编码

        向量 load 和 store 指令直接在指令中编码了一个 EEW(字段width[2:0]),相应的 EMUL=(EEW/SEW)*LMUL,如果EMUL超出合法范围(大于8或小于1/8)则指令编码无效。

        其中,unit-stride 和 constant-stride 方式直接为数据值使用指令中的 EEW/EMUL 编码。而 indexed 方式则为索引值使用这一编码,数据值则使用 vtype 中的SEW/LMUL 编码。

你可能感兴趣的:(RISC-V,risc-v)