RISC-V vector扩展

1. 一些参数定义

  • ELEN:一个向量元素的最大位宽,须为2的指数。
  • VLEN:一个单独的向量寄存器的宽度,须为2的指数,最宽为2^{16},VLEN \geqslant ELEN。
  • LMUL:组合在一起的向量寄存器的数量。

vector register group:将一组向量寄存器视为一条vector指令的一个操作数。

  • SEW:实际一个向量元素的宽度。
  • VL:一条指令可以操作的向量元素的数量,VLMAX=LMUL*VLEN/SEW,由于SEWmin=8,LMULmax=8,因此 VLMAX 等于VLEN。 
  • AVL:一个应用程序要处理的向量元素的个数。

2. Vector扩展编程模型

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

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

        当存在 hypervisor 扩展时,vsstatus寄存器也需要添加一个向量上下文状态域。当V=1时,需要mstatus和vsstatus中的VS均为1,否则执行vector指令或访问vector csr寄存器会引起异常。

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

  • vsew[2:0](Vector Selected Elememt Width):用于设置动态向量元素宽度,可设置8~64位宽;
  • vlmul[2:0](Vector Length MULtiplier):可以组合多个向量寄存器将其视为一个寄存器,该字段用于表示组合的寄存器的数量。
    • LMUL=2^{vlmul[2:0]},vlmul是个有符号数。
    • 基础地可以设为1,2,4,8(最大值),此外也可以设为分数1/2,1/4,1/8,表示只占用一个向量寄存器的一部分。
    • 分组的寄存器必须是连续的几个寄存器,例如LMUL为2时,一个寄存器组由Vn和Vn+1构成。

一个向量操作的源和目的操作数可能具有不同的元素宽度,但元素数量是相同的。

一个向量操作有效的LUML是有目的操作数决定的。

  • vta/vma:vector tail agnostic/vector mask agnostic,“agnostic”表示在指令执行过程中不必须保持寄存器中该部分的旧值。
    • 这两位分别表示在向量指令执行过程中对于寄存器中的tail元素和非活跃masked-off元素的处理方式(覆盖写为1 or 保留旧值 or 其他方式)。如果置为1则表示不必须保持旧值。
    • mask类型指令的目标数据的 tail 元素总是按 tail-agnostic 的方式写入,无论 vta 的值是什么。

agnostic 主要是考虑到寄存器重命名,如果没有这个方式,则每次必须把旧物理寄存器中的所有元素都复制到新物理寄存器中,但 inactive 和 tail 部分可能并不需要。

  •  vill:对vtype寄存器进行非法配置时置位(比如SEW或LMUL配置为不支持的值),置位时任何依赖于vtype的向量指令的执行都会导致非法指令异常。

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

  • prestart:元素索引低于 vstart 寄存器起始值 的向量元素,这部分内容不会引起异常也不会更新目标寄存器。
  • body:元素索引大于等于 vstart 寄存器起始值,且小于 vl 寄存器中设定的当前向量长度的向量元素。这部分内容又可分为两部分:active 和 inactive部分:
    • active 部分指 mask 使能的元素位,会引发异常,并且会更新目标寄存器。
    • inactive 指 mask 未使能的元素位,inactive 内容不会引起异常且只在 vtype.vma 为1时更新目标寄存器(向目标寄存器中 inactive 部分写入 1)。
  • tail:超出vl指示的向量个数的向量元素部分。
    • 不更新目标寄存器,除非 vtype.vta=1,即 tail agnostic 时,此时向目标寄存器中这部分写入 1 或者指令结果(在 mask-producing 指令下,除了mask loads)
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 保持 \frac{SEW}{LMUL}(即vlmax) 一致,即保证每个向量组最多包含的元素个数相同。

混合宽度操作映射举例:

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

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

4. vector masking

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

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

        指令编码中的 vm 位(vinst[25])指示 mask 是否使能:

       vm=0 时表示 mask 使能,即只对 v0.mask[i]==1 的元素进行指令操作。    

在汇编指令上体现如下:

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

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

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

        指令格式如下图所示:

  •  新的 vtype 配置位于指令编码中的立即数域(vsetvli 和 vsetivli 指令中)或者 rs2(vsetvl指令)。
  • AVL 编码含义以对 vl 的配置影响如下:

  • vl 配置约束如下:
    • 如果 AVL ≤ VLMAX,vl = AVL;
    • 如果 AVL < (2 * VLMAX),ceil(AVL/2)≤ vl ≤ VLMAX;
    • 如果 AVL ≥ (2 * VLMAX),vl = VLMAX;
    • 在相同输入的 AVL 和 VLMAX 值下,每次给出的 vl 是相同的;

stripmining 过程举例:

6. 向量 load 和 store

        masked 的向量 load 不会更新向量寄存器组中的非活跃元素,除非开启 mask-agnostic 机制;masked 的向量 store 则只会更新活跃的memory element。 

6.1 指令编码

  • rs1:基址寄存器
  • rs2:stride 寄存器
  • vs2:地址偏移寄存器
  • vs3:保存 store data 的寄存器
  • vd:load 数据的目的寄存器
  • vm:指示 masking 是否使能,为 0 时使能
  • width[2:0]:指示存储元素的 size
  • mew:memory elememt 宽度
  • mop[1:0]:指示访存地址模式
  • nf[2:0]:指示每个段的区域数,用于 Vector load/store Segment 指令。                                 
  • 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 三种地址模式,基址寄存器和步幅来自通用寄存器组,在指令编码中通过rs1和rs2指定。在指令编码中通过 mop[1:0] 指示地址模式。

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

    unit-stride 地址模式又通过指令码中的 lumop(load 指令)和 sumop(store 指令)具体指定。 

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 编码。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值