RISC-V Vector Extension


  • RISC-V 向量扩展(RVV, RISC-V Vector Extension)中的指令可以大致分为三大类:设置向量长度setvl)、加载/存储load/store)、和 数学运算mathematical operations)。以下是这三类指令的详细描述:

    setvl 指令

    setvl 指令用于设置向量长度,并返回当前向量长度。它是 RVV 中的核心指令,用于动态地控制每条指令处理的向量元素数量。通过设置向量长度寄存器(vl),可以使得后续的指令在处理数据时,按照给定的向量长度来处理。

    • 指令格式

      1
      setvl  xlen, rs1
    • 功能

      • 设置向量长度(vl)。
      • rs1 寄存器的值决定了目标向量长度(vl)。
      • 返回的向量长度会被存储在 vlen 寄存器中。
    • 示例

      1
      setvl   x0, x1  // 设置向量长度

    加载/存储指令(Load/Store)

    加载和存储指令用于将数据从内存加载到向量寄存器中,或者将向量寄存器中的数据存储回内存。这些指令的操作对象是向量寄存器,可以处理多个数据元素。

    • 加载指令(Vector Load)

      • 用于从内存中加载数据到向量寄存器。
      • 支持不同的访问模式,包括按字节、按字、按双字等。

      示例指令:

      1
      2
      3
      vlb    vd, (rs1)      // 加载字节数据到向量寄存器
      vlh vd, (rs1) // 加载半字数据到向量寄存器
      vld vd, (rs1) // 加载双字数据到向量寄存器
    • 存储指令(Vector Store)

      • 用于将向量寄存器的数据存储回内存。

      示例指令:

      1
      2
      3
      vsb    (rs1), vs      // 将向量寄存器中的字节存储到内存
      vsh (rs1), vs // 将向量寄存器中的半字存储到内存
      vsd (rs1), vs // 将向量寄存器中的双字存储到内存

    数学运算指令(Mathematical Operations)

    数学运算指令用于执行向量运算,包括加法、减法、乘法、除法、按元素操作、以及向量间的点积等。这些指令通常操作向量寄存器中的数据。

    • 加法/减法指令

      • 用于执行向量元素之间的加法或减法。

      示例指令:

      1
      2
      vadd   vd, vs, vt   // 向量加法,vd = vs + vt
      vsub vd, vs, vt // 向量减法,vd = vs - vt
    • 乘法/除法指令

      • 用于执行向量元素之间的乘法或除法。

      示例指令:

      1
      2
      vmul   vd, vs, vt   // 向量乘法,vd = vs * vt
      vdiv vd, vs, vt // 向量除法,vd = vs / vt
    • 按元素操作

      • 例如按位与、按位或、按位异或等操作。

      示例指令:

      1
      2
      3
      vand   vd, vs, vt   // 向量按位与
      vor vd, vs, vt // 向量按位或
      vxor vd, vs, vt // 向量按位异或
    • 归约操作

      • 执行归约操作,如计算向量元素的总和、最小值、最大值等。

      示例指令:

      1
      2
      3
      vredsum  rd, vs     // 向量元素求和
      vredmin rd, vs // 向量元素求最小值
      vredmax rd, vs // 向量元素求最大值
    • 比较和掩码操作

      • 用于比较向量元素,生成掩码或标志。

      示例指令:

      1
      2
      vcmpeq  vd, vs, vt  // 向量元素相等比较
      vcmpgt vd, vs, vt // 向量元素大于比较

    RISC-V 向量扩展(RVV)指令集包括三大类指令:

    1. setvl:设置向量长度。
    2. 加载/存储:用于向量数据的加载和存储操作。
    3. 数学运算:进行加法、减法、乘法、除法、按位运算、比较等操作。

    这些指令的组合使得 RISC-V 向量扩展能够高效地处理并行数据,适用于大规模的数据处理任务,如矩阵计算、科学计算等。

在 RISC-V 向量扩展(RVV)中,加载/存储(load/store)指令按照内存寻址模型(memory addressing model)的不同,可以进一步分为以下三类:


Unit Strided Load/Store

Unit strided 是最简单的内存寻址模型,数据在内存中是连续存储的,每个元素占据固定的内存字节大小(如字节、半字、字或双字)。这种模型假设内存地址是以固定步幅(stride=1)递增的。

指令格式:

  • 加载指令

    1
    2
    3
    4
    vle8   vd, (rs1)      // 加载连续的 8-bit 数据到向量寄存器
    vle16 vd, (rs1) // 加载连续的 16-bit 数据到向量寄存器
    vle32 vd, (rs1) // 加载连续的 32-bit 数据到向量寄存器
    vle64 vd, (rs1) // 加载连续的 64-bit 数据到向量寄存器
  • 存储指令

    1
    2
    3
    4
    vse8   (rs1), vd      // 存储向量寄存器中的 8-bit 数据到连续的内存
    vse16 (rs1), vd // 存储 16-bit 数据
    vse32 (rs1), vd // 存储 32-bit 数据
    vse64 (rs1), vd // 存储 64-bit 数据

特点:

  • 数据在内存中以连续地址存储。
  • 使用场景:矩阵或向量的逐元素处理,如密集向量运算。

Strided Load/Store

Strided 寻址模型允许内存地址以固定步幅(stride)递增。这种模型用于处理间隔存储的数据,例如二维数组中的一行数据。

指令格式:

  • 加载指令

    1
    2
    3
    4
    vlse8  vd, (rs1), rs2   // 加载具有固定步幅的 8-bit 数据
    vlse16 vd, (rs1), rs2 // 加载 16-bit 数据
    vlse32 vd, (rs1), rs2 // 加载 32-bit 数据
    vlse64 vd, (rs1), rs2 // 加载 64-bit 数据
  • 存储指令

    1
    2
    3
    4
    vsse8  (rs1), rs2, vd   // 存储 8-bit 数据到具有固定步幅的内存
    vsse16 (rs1), rs2, vd // 存储 16-bit 数据
    vsse32 (rs1), rs2, vd // 存储 32-bit 数据
    vsse64 (rs1), rs2, vd // 存储 64-bit 数据

参数说明:

  • rs1 是基地址寄存器。
  • rs2 是步幅寄存器(stride),指定每个元素之间的字节距离。

特点:

  • 数据在内存中以固定步幅分布。
  • 使用场景:处理稀疏矩阵行、二维数组或其他非连续存储的数据。

Indexed Load/Store

Indexed 寻址模型允许每个元素的地址由基地址加上一个偏移量(offsets)决定。偏移量可以存储在一个单独的向量寄存器中,使得可以自由访问内存中的任意位置。

指令格式:

  • 加载指令

    1
    2
    3
    4
    vluxei8  vd, (rs1), vs2   // 加载 8-bit 数据,地址由索引寄存器决定
    vluxei16 vd, (rs1), vs2 // 加载 16-bit 数据
    vluxei32 vd, (rs1), vs2 // 加载 32-bit 数据
    vluxei64 vd, (rs1), vs2 // 加载 64-bit 数据
  • 存储指令

    1
    2
    3
    4
    vsuxei8  (rs1), vs2, vd   // 存储 8-bit 数据到索引指定的地址
    vsuxei16 (rs1), vs2, vd // 存储 16-bit 数据
    vsuxei32 (rs1), vs2, vd // 存储 32-bit 数据
    vsuxei64 (rs1), vs2, vd // 存储 64-bit 数据

参数说明:

  • rs1 是基地址寄存器。
  • vs2 是索引寄存器,存储相对基地址的偏移量。

特点:

  • 数据地址可以完全动态控制,适合处理非规则的数据布局。
  • 使用场景:稀疏矩阵列访问、图处理、或不规则存储数据的加载和存储。
类别 内存分布 特点 适用场景
Unit Strided 连续存储 地址递增步幅为 1 密集向量运算
Strided 固定步幅分布 地址递增步幅由寄存器 rs2 指定 稀疏矩阵行处理
Indexed 任意分布 地址偏移由索引向量决定 稀疏矩阵列、不规则数据处理

7个CSR(Context Status Register)寄存器

Vstart(Vector Start)寄存器

存储向量指令中被执行第一个元素的索引值。

通常在向量指令执行过程中产生了陷阱被写入,记录了陷阱时向量指令操作元素的索引,以便跳出陷阱之后能够继续执行剩下的元素。当向量指令产生非法指令异常时,vstart寄存器将不会被改写。

如果vstart数值大于vl的值,说明vstart指向的元素索引已经超过当前所有元素的范围,该指令不会执行,同事寄存器复位0

Vxsat寄存器

vxsat为可读可写寄存器,该寄存器不仅有独立的寄存器地址,并且在vcsr寄存器中也有对应的域。该寄存器有效表示输出结果做了饱和截位以适应目的寄存器格式。比如当运算发生正溢出时,保留结果为能取到的最大正值;当运算发生负溢出时,保留结果为负数最小值。

vxrm寄存器

vxrm[1:0]为可读可写寄存器,该寄存器不仅有独立的寄存器地址,并且在vcsr寄存器中也有对应的域。该寄存器控制定点舍入模式,一共四种模式,分别是round-to-nearest-up(rnu)、round-to-nearest-even(rne)、round-down(rdn)、round-to-odd(rod)。(问题:可否解释一下定点数在内存中的存放格式)
vxrm[1:0]寄存器通过单条csrwi指令写入值。
假如源操作数是v,有低d bit数据要被截掉,那么做完rounding-mode之后的最终结果应该是(v>>d)+r,r就是根据不同的rounding mode得到的增量值。
rnu:向距离近的方向进行舍入,当距离与两边都相等时,向上舍入。
rne:向距离近的方向进行舍入,当距离与两边都相等时,向偶数方向舍入。
rdn:向下舍入,直接取移位后的值。
rod:舍入到奇数值方向。
其中,v[d-1]表示权重位。当v[d-1]=0,表示距离舍的方向更近;当v[d-1]=1且v[d-2:0]=0时,距离舍入两个方向距离均相等;当v[d-1]=1,且v[d-2:0] != 0时,表示距离入的方向更近。

vcsr寄存器

vcsr[2:0]寄存器为可读可写寄存器,该寄存器由vxrm[1:0],以及vxsat组成。
riscv spec中fflags和frm寄存器也采用的这样的设计。这类状态寄存器,希望方便快速的读写,比如有时候希望一条指令能把这两个寄存器的值同时读出来。又或者写这两个寄存器,如果要同时写,就得先做移位拼接在写,那有的时候只想改变其中一个寄存器的值,也做移位在拼接然后写的操作就比较慢,因此单独写对应的地址就显得尤为方便快速。考虑到适应不同的需求,这类状态寄存器就设计为既有各自单独的寄存器存储空间,又集中在一个寄存集中划分各自的域。

vtype寄存器

vtype为只读寄存器,位宽同通用整型架构寄存器位宽(XLEN)。该寄存器提供了默认值用于解析向量寄存器中的内容,并且只能通过vsetvl{i}指令进行更新(这样做的目的是使得维护vtype寄存器的状态简单化)。
vtype寄存器用于解析向量寄存器文件中的内容、决定单个向量寄存器中元素的组成以及决定多个向量寄存器是如分组的。
vtype寄存器有五个域,分别是vill,vma,vta,vsew[2:0],vlmul[2:0]。

屏幕截图 2024 11 22 152517

vl寄存器

vl寄存器为只读寄存器,该寄存器存储着一个无符号整数,用来规定一条向量指令需要更新多少个元素。
该寄存器只能被vsetvli、vsetvl指令以及fault-only-first矢量读取指令的变体进行更新。
目的寄存器中元素索引大于等于vl的元素,将不会被修改。如果vstart大于等于vl,那么目的寄存器的任何元素都不会被修改。
vl的位宽由最小元素组成的最大向量长度决定。最小的元素位宽至少是8bit,最大的分组设置为LMUL等于8,那么VLMAX=LMUL * (VLEN / SEW) = VLEN。也就是说vl的位宽,直接由VLEN的大小决定。

vlenb寄存器

该寄存器为只读寄存器,表示以字节为单位的向量寄存器长度,vlenb=VLEN/8。vlenb是一个设计时常量,增加这个寄存器是为了减少一些需要直接用到vlenb的程序的额外计算指令的开销。