【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(五)- 向量加载和存储

  1. 引言

以下是《riscv-v-spec-1.0.pdf》文档的关键内容:
这是一份关于向量扩展的详细技术文档,内容覆盖了向量指令集的多个关键方面,如向量寄存器状态映射、向量指令格式、向量加载和存储操作、向量内存对齐约束、向量内存一致性模型、向量算术指令格式、向量整数和浮点算术指令、向量归约操作、向量掩码指令、向量置换指令、异常处理以及标准向量扩展等。
首先,文档定义了向量元素和向量寄存器状态之间的映射关系,并阐述了向量指令的格式。在此基础上,提出了配置设置指令,如vsetvl、ivsetiv和vlsetvl,用于设定向量长度(VL)和向量对齐长度(AVL)。
接着,文档详细说明了向量加载和存储操作,以及向量内存对齐和一致性模型。这些模型确保了向量操作的高效性和准确性。
然后,文档介绍了向量算术指令格式,包括向量整数、固定点和浮点算术指令。这些指令支持广泛的数学运算,为高性能计算提供了强大的支持。
此外,文档还涉及向量归约操作、掩码指令和置换指令,这些指令增强了向量操作的灵活性和功能性。
最后,文档讨论了异常处理机制,并列举了标准向量扩展指令列表。这些扩展指令为向量处理器提供了丰富的功能集,使其能够适应不同的应用场景和性能需求。
综上所述,这份文档为向量指令集的设计和实现提供了全面的指导和参考,有助于开发者更好地理解和利用向量处理器的能力。

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(一)-向量扩展编程模型-CSDN博客

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(二)-向量元素到向量寄存器状态的映射-CSDN博客【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(三)-向量指令格式-CSDN博客

7 向量加载和存储

向量加载和存储操作在向量寄存器和内存之间移动值。向量加载和存储操作是掩蔽的,不会在非活动元素上引发异常。被掩蔽的向量加载操作不会更新目标向量寄存器组中的非活动元素,除非指定了掩蔽不可知(vtype.vma=1)。被掩蔽的向量存储只会更新活动的内存元素。所有的向量加载和存储操作都可能会生成并接受一个非零的vstart值。

7.1 向量加载和存储指令编码

向量加载和存储操作在标量浮点加载和存储的主要操作码(LOAD-FP/STORE-FP)中进行编码。向量加载和存储编码重新利用了标准标量浮点加载/存储的12位立即数字段的一部分,以提供进一步的向量指令编码,其中第25位保存标准的向量掩码位(见掩码编码)。

以下是LOAD-FP主要操作码下的向量加载指令格式:

以下是STORE-FP主要操作码下的向量存储指令格式:

Field

Description

rs1[4:0]

speciies x register holding base address

rs2[4:0]

speciies x register holding stride

vs2[4:0]

speciies v register holding address offsets

vs3[4:0]

speciies v register holding store data

vd[4:0]

speciies v register destination of load

vm

speciies whether vector masking is enabled (0 = mask enabled, 1 = mask disabled)

width[2:0]

speciies size of memory elements, and distinguishes from FP scalar

mew

extended memory element width. See Vector Load/Store Width Encoding

mop[1:0]

speciies memory addressing mode

nf[2:0]

speciies the number of ields in each segment, for segment load/stores

lumop[4:0]/sumop[4:0]

are additional ields encoding variants of unit-stride instructions

向量内存单元跨度和固定跨度的操作在指令中静态地直接编码要传输的数据的EEW(元素宽度),以减少在混合宽度例程中访问内存时vtype更改的次数。索引操作使用指令中的显式EEW编码来设置所使用的索引的大小,并使用SEW/LMUL来指定数据宽度。

7.2 向量加载存储地址模型

向量扩展支持单元跨度、固定跨度和索引(分散/收集)寻址模式。向量加载/存储基寄存器和跨度取自GPR x寄存器。

所有向量访问的基本有效地址由rs1中指定的x寄存器的内容给出。

向量单元跨度操作访问从基本有效地址开始连续存储在内存中的元素。

向量固定跨度操作访问基本有效地址的第一个内存元素,然后访问后续元素,地址增量由rs2指定的x寄存器中包含的字节偏移量给出。

向量索引操作将vs2指定的向量偏移操作数的每个元素的内容添加到基本有效地址中,以给出每个元素的有效地址。数据向量寄存器组具有EEW=SEW,EMUL=LMUL,而偏移向量寄存器组具有在指令中编码的EEW和EMUL=(EEW/SEW)*LMUL。

向量偏移操作数被视为字节地址偏移量的向量。

索引操作也可以用于访问对象向量中的字段,其中vs2向量保存指向对象基部的指针,而标量x寄存器保存每个对象中成员字段的偏移量。支持这种情况是索引操作没有根据数据EEW对元素索引进行缩放的原因。

如果向量偏移元素比XLEN窄,则在添加到基本有效地址之前,它们将被零扩展到XLEN。如果向量偏移元素比XLEN宽,则在地址计算中使用最低有效XLEN位。如果EEW不支持偏移元素,则实现必须引发非法指令异常。

注意,配置文件可能会对最大支持的索引EEW(例如,仅达到XLEN)设置上限,该上限小于ELEN。

向量寻址模式使用2位mop[1:0]字段进行编码。

Table 9. encoding for loads

Mop[1:0]

Description

Opcodes

0

0

unit-stride

VLE<EEW>

0

1

indexed-unordered

VLUXEI<EEW>

1

0

strided

VLSE<EEW>

1

1

indexed-ordered

VLOXEI<EEW>

Table 10. encoding for stores

Mop[1:0]

Description

Opcodes

0

0

unit-stride

VSE<EEW>

0

1

indexed-unordered

VSUXEI<EEW>

1

0

strided

VSSE<EEW>

1

1

indexed-ordered

VSOXEI<EEW>

向量单元跨度和固定跨度内存访问不保证单个元素访问之间的顺序。向量索引加载和存储内存操作有两种形式:有序和无序。有序索引变体在内存访问中保留元素顺序。

对于无序指令(mop[1:0]!=11),不保证元素访问顺序。如果访问的是强顺序IO区域,则可以以任何顺序启动元素访问。

注意:要对强顺序IO区域进行有序向量访问,应使用有序索引指令。

对于具有精确向量陷阱的实现,无序索引存储上的异常也必须是精确的。

使用单元跨度加载和存储指令编码中的5位lumop和sumop字段分别编码额外的单元跨度向量寻址模式。

Table 11. lumop

Lumop[4:0]

Description

0

0

0

0

0

unit-stride load

0

1

0

0

0

unit-stride, whole register load

0

1

0

1

1

unit-stride, mask load, EEW=8

1

0

0

0

0

unit-stride fault-only-irst

x

x

x

x

x

other encodings reserved

Table 12. sumop

Sumop[4:0]

Description

0

0

0

0

0

unit-stride store

0

1

0

0

0

unit-stride, whole register store

0

1

0

1

1

unit-stride, mask store, EEW=8

x

x

x

x

x

other encodings reserved

nf[2:0]字段编码每个段中的字段数。对于常规的向量加载和存储,nf=0,表示在每个元素位置,一个单一的值在向量寄存器组和内存之间移动。nf字段中的较大值用于访问段内的多个连续字段,如下面“向量加载/存储段指令”部分所述。

对于整个向量寄存器加载/存储指令,nf[2:0]字段还编码要传输的整个向量寄存器的数量。

7.3 向量加载/存储宽带编码

向量加载和存储在指令中直接编码有EEW(元素宽度)。相应的EMUL(元素乘法单位)计算为EMUL = (EEW/SEW)*LMUL。如果EMUL超出范围(EMUL>8EMUL<1/8),则指令编码是保留的。向量寄存器组必须具有选定EMUL的合法寄存器指定符,否则指令编码是保留的。

向量单元跨度和固定跨度使用指令中编码的EEW/EMUL用于数据值,而向量索引加载和存储使用指令中编码的EEW/EMUL用于索引值,以及vtype中编码的SEW/LMUL用于数据值。

向量加载和存储使用标准标量浮点加载和存储未声明的宽度值进行编码。

实现必须提供与所有支持的SEW设置相对应的EEW的向量加载和存储。不支持的EEW宽度的向量加载/存储编码必须引发非法指令异常。

Table 13. Width encoding for vector loads and stores.

new

width[2:0]

Mem bits

Data Reg bits

Index bits

Opcodes

Standard scalar FP

x

0

0

1

16

FLEN

-

FLH/FSH

Standard scalar FP

x

0

1

0

32

FLEN

-

FLW/FSW

Standard scalar FP

x

0

1

1

64

FLEN

-

FLD/FSD

Standard scalar FP

x

1

0

0

128

FLEN

-

FLQ/FSQ

Vector 8b element

0

0

0

0

8

8

-

VLxE8/VSxE8

Vector 16b element

0

1

0

1

16

16

-

VLxE16/VSxE16

Vector 32b element

0

1

1

0

32

32

-

VLxE32/VSxE32

Vector 64b element

0

1

1

1

64

64

-

VLxE64/VSxE64

Vector 8b index

0

0

0

0

SEW

SEW

8

VLxEI8/VSxEI8

Vector 16b index

0

1

0

1

SEW

SEW

16

VLxEI16/VSxEI16

Vector 32b index

0

1

1

0

SEW

SEW

32

VLxEI32/VSxEI32

Vector 64b index

0

1

1

1

SEW

SEW

64

VLxEI64/VSxEI64

Reserved

1

X

X

X

-

-

-

Mem bits 是在内存中访问的每个元素的大小。

Data reg bits 是在寄存器中访问的每个数据元素的大小。

Index bits 是在寄存器中访问的每个索引的大小。

当设置 mew 位(inst[28])时,预计将其用于编码 128 位及以上的扩展内存大小,但这些编码当前是保留的。

7.4 向量单元跨度加载和存储指令

# Vector unit-stride loads and stores
# vd destination, rs1 base address, vm is mask encoding (v0.t or <missing>)
vle8.v    vd, (rs1), vm  #    8-bit unit-stride load
vle16.v   vd, (rs1), vm  #   16-bit unit-stride load
vle32.v   vd, (rs1), vm  #   32-bit unit-stride load
vle64.v   vd, (rs1), vm  #   64-bit unit-stride load
# vs3 store data, rs1 base address, vm is mask encoding (v0.t or <missing>)
vse8.v    vs3, (rs1), vm  #    8-bit unit-stride store
vse16.v   vs3, (rs1), vm  #   16-bit unit-stride store
vse32.v   vs3, (rs1), vm  #   32-bit unit-stride store
vse64.v   vs3, (rs1), vm  #   64-bit unit-stride store

提供了额外的单元跨度掩码加载和存储指令,用于将掩码值传输到内存或从内存中传输。这些指令的操作与未屏蔽的字节加载或存储(EEW=8)类似,不同之处在于有效向量长度为evl=ceil(vl/8)(即EMUL=1),并且目标寄存器始终使用尾部不可知策略写入。

# Vector unit-stride	mask	load
vlm.v vd, (rs1)   #	Load	byte vector of length ceil(vl/8)
# Vector unit-stride	mask	store
vsm.v vs3, (rs1)  #	Store byte vector of length ceil(vl/8)

vlm.v 和 vsm.v 指令使用与 vle8.v 和 vse8.v 相同的 width[2:0]=0 编码,但通过不同的 lumop 和 sumop 编码来区分。由于 vlm.v 和 vsm.v 指令作为字节加载和存储操作,因此对于这些指令,vstart 是以字节为单位的。

注意:

以前的汇编助记符 vle1.v 和 vse1.v 容易造成混淆,因为这些指令与其他元素加载/存储指令的长度处理方式不同。为了避免软件混乱,这些旧的汇编助记符将作为别名保留。

提供掩码加载和存储的主要动机是支持内部重新排列数据的机器,以减少跨数据路径的布线。然而,这些指令还提供了一种方便的机制,可以在内存中使用打包的位向量作为掩码值,并减少了更改 vl 的需求,从而降低了掩码溢出/填充的成本。

7.5 向量步长指令

# Vector strided loads and stores
# vd destination, rs1 base address, rs2 byte stride
vlse8.v    vd, (rs1), rs2, vm  #    8-bit strided load
vlse16.v   vd, (rs1), rs2, vm  #   16-bit strided load
vlse32.v   vd, (rs1), rs2, vm  #   32-bit strided load
vlse64.v   vd, (rs1), rs2, vm  #   64-bit strided load

 
# vs3 store data, rs1 base address,rs2 byte stride
vsse8.v    vs3, (rs1), rs2, vm  #    8-bit strided load
vsse16.v   vs3, (rs1), rs2, vm  #   16-bit strided load
vsse32.v   vs3, (rs1), rs2, vm  #   32-bit strided load    
vsse64.v   vs3, (rs1), rs2, vm  #   64-bit strided load

支持负步长和零步长。在有步长指令中,元素访问之间是无序的。

当rs2=x0时,允许(但不要求)实现执行比活动元素数量更少的内存操作,并且在相同静态指令的不同动态执行中可能会执行不同数量的内存操作。

注意:

编译器必须注意,如果意图是要求执行所有内存访问,那么当立即步长为0时,不要对rs2使用x0形式。

当rs2!=x0且x[rs2]=0时,实现必须对每个活动元素执行一次内存访问(但这些访问将不会排序)。

注意:

与其他架构要求一样,实现必须看起来执行了每个内存访问。微架构可以自由优化掉不会被其他代理观察到的访问,例如在遵守RVWMO的幂等内存区域中。对于非幂等内存区域,根据定义,每个访问都可以被设备观察到,因此无法进行这种优化。

当需要对同一内存地址进行重复有序向量访问时,可以使用有序索引操作。

7.6 向量索引指令

# Vector indexed loads and stores
# Vector indexed-unordered load instructions
# vd destination, rs1 base address, vs2 byte
vluxei8.v    vd, (rs1), vs2, vm  # unordered
vluxei16.v   vd, (rs1), vs2, vm  # unordered
vluxei32.v   vd, (rs1), vs2, vm  # unordered
vluxei64.v   vd, (rs1), vs2, vm  # unordered	

offsets
8-bit indexed load of SEW data
16-bit indexed load of SEW data
32-bit indexed load of SEW data
64-bit indexed load of SEW data
# Vector indexed-ordered load instructions
# vd destination, rs1 base address, vs2 byte offsets
vloxei8.v    vd, (rs1), vs2, vm  # ordered  8-bit indexed load of SEW data
vloxei16.v   vd, (rs1), vs2, vm  # ordered 16-bit indexed load of SEW data
vloxei32.v   vd, (rs1), vs2, vm  # ordered 32-bit indexed load of SEW data
vloxei64.v   vd, (rs1), vs2, vm  # ordered 64-bit indexed load of SEW data
# Vector indexed-unordered store instructions
# vs3 store data, rs1 base address, vs2 byte offsets
vsuxei8.v   vs3, (rs1), vs2, vm # unordered  8-bit indexed store of SEW data
vsuxei16.v  vs3, (rs1), vs2, vm # unordered 16-bit indexed store of SEW data
vsuxei32.v  vs3, (rs1), vs2, vm # unordered 32-bit indexed store of SEW data
vsuxei64.v  vs3, (rs1), vs2, vm # unordered 64-bit indexed store of SEW data
# Vector indexed-ordered store instructions
# vs3 store data, rs1 base address, vs2 byte offsets
vsoxei8.v    vs3, (rs1), vs2, vm  # ordered  8-bit indexed store of SEW data
vsoxei16.v   vs3, (rs1), vs2, vm  # ordered 16-bit indexed store of SEW data
vsoxei32.v   vs3, (rs1), vs2, vm  # ordered 32-bit indexed store of SEW data
vsoxei64.v   vs3, (rs1), vs2, vm  # ordered 64-bit indexed store of SEW data

索引加载和存储的汇编语法使用eix而不是ex来表示静态编码的EEW属于索引而不是数据。

索引操作助记符使用“U”或“O”来区分无序和有序,而其他向量寻址模式则没有字符。虽然这可能有点不一致,但这种方法可以最大程度地减少对现有软件的干扰,因为VSXEI以前表示“有序”,并且在过渡到新指令时,操作码可以作为别名保留,以帮助减少软件的变动。

7.7 单元跨度“仅首个错误”加载指令

单元跨度“仅首个错误”加载指令用于向量化具有数据依赖退出条件的循环(如“while”循环)。这些指令将作为常规加载执行,但只会捕获由元素0上的同步异常导致的陷阱。如果元素0引发异常,则vl不会被修改,并触发陷阱。如果元素>0引发异常,则不会触发相应的陷阱,而是将向量长度vl减小到会引发异常的元素的索引。

加载指令可能会覆盖在报告陷阱的元素索引之后的活跃目标向量寄存器组元素。同样,“仅首个错误”加载指令可能会更新导致向量长度缩减的元素之后(但不超过原始向量长度)的活跃目标元素。这些虚假更新的值不必与所寻址内存位置中的内存值相对应。只有当已知相应的元素加载操作不会由于陷阱或向量长度缩减而重新开始时,才能访问非幂等内存位置。

# Vector unit-stride fault-only-first loads
# vd destination, rs1 base address, vm is mask encoding (v0.t or <missing>)
vle8ff.v    vd, (rs1), vm  #    8-bit unit-stride fault-only-first load
vle16ff.v   vd, (rs1), vm  #   16-bit unit-stride fault-only-first load
vle32ff.v   vd, (rs1), vm  #   32-bit unit-stride fault-only-first load
vle64ff.v   vd, (rs1), vm  #   64-bit unit-stride fault-only-first load
 
strlen example using unit-stride fault-only-first instruction

# size_t strlen(const char *str)
# a0 holds *str
strlen:
mv a3, a0             # Save start
loop:
vsetvli a1, x0, e8, m8, ta, ma  # Vector of bytes of maximum length
vle8ff.v v8, (a3)      # Load bytes
csr r a1, vl           # Get bytes read
vmseq.vi v0, v8, 0    # Set v0[i] where v8[i] = 0
vfirst.m a2, v0       # Find first set bit
add a3, a3, a1        # Bump pointer
bltz a2, loop         # Not found?
add a0, a0, a1        # Sum start + bump
add a3, a3, a2        # Add index
sub a0, a3, a0        # Subtract start address+bump
ret

“仅首个错误”加载存在安全问题,因为它们可以用来探测有效的实际地址。单元跨度版本只允许探测与已知区域紧邻的区域,因此在非特权代码中使用时可降低安全影响。但是,在S模式下运行的代码可以建立任意的页面转换,从而允许探测由虚拟机管理程序提供的随机客户物理地址。由于没有足够的编码空间,因此不提供有跨度的和分散/聚集的“仅首个错误”指令,但它们也可能代表一个更大的安全漏洞,允许非特权软件轻松检查多个随机页面的可访问性,而不会遇到陷阱。本标准没有解决“仅首个错误”指令可能的安全缓解措施。即使没有引发异常,也允许实现处理少于vl的元素并相应地减少vl,但是如果vstart=0且vl>0,则必须至少处理一个元素。

当“仅首个错误”指令由于中断而陷入陷阱时,实现不应减少vl,而应设置一个vstart值。

当“仅首个错误”指令在首个元素之后触发调试数据观察点陷阱时,实现不应减少vl,而应触发调试陷阱,否则可能会丢失事件。

7.8 向量加载/存储段指令

向量加载/存储段指令可以在内存中移动多个连续字段,并在连续编号的向量寄存器之间进行传输。

“段”这个名字反映了所移动的项目是具有同类元素的子数组。这些操作可用于在内存和寄存器之间转置数组,并可以通过将结构中的每个字段解包到单独的向量寄存器中来支持对“结构数组”数据类型的操作。

向量指令编码中的三位nf字段是一个无符号整数,其包含的数值比每个段的字段数NFIELDS少1。

Table 14. NFIELDS Encoding

 nf[2:0]

  NFIELDS

0

0

0

1

0

0

1

2

0

1

0

3

0

1

1

4

1

0

0

5

1

0

1

6

1

1

0

7

1

1

1

8

EMUL设置必须满足EMUL * NFIELDS = 8,否则指令编码是保留的。

EMUL * NFIELDS的乘积表示分段加载或存储指令将触及的底层向量寄存器的数量。这一约束使得总数不大于体系寄存器文件的1/4,与EMUL=8的常规操作相同。

每个字段将被保存在连续编号的向量寄存器组中。当EMUL>1时,每个字段将占用多个连续编号的向量寄存器中的一个向量寄存器组,并且每个字段的向量寄存器组必须遵循通常的向量寄存器对齐约束(例如,当EMUL=2和NFIELDS=4时,每个字段的向量寄存器组必须从偶数向量寄存器开始,但不必从8的倍数向量寄存器编号开始)。

如果分段加载或存储访问的向量寄存器编号递增超过31,则指令编码是保留的。

这一约束有助于为可能的未来更长的指令编码提供更多的可寻址向量寄存器,以实现向前兼容性。

vl寄存器给出了要移动的段数,这等于传输到每个向量寄存器组的元素数量。掩蔽也应用于整个段级别。

对于分段加载和存储,即使在有序的索引分段加载和存储中,用于访问每个段内字段的各个内存访问也是无序的。

vstart值的单位是整个段。如果在访问段期间发生陷阱,则在陷阱发生之前是否执行故障段访问的子集是由实现定义的。

7.8.1 向量单位步长加载和存储段指令

向量单位步长加载和存储段指令将打包的连续段移动到多个目标向量寄存器组中。

当段中包含大小不同的字段的结构时,软件可以在段加载将数据带入向量寄存器后,使用额外的指令来解包单个结构字段。

汇编器前缀vlseg/vsseg分别用于单位步长段加载和存储。

# Format
vlseg<nf>e<eew>.v vd, (rs1), vm     # Unit-stride segment load template
vsseg<nf>e<eew>.v vs3, (rs1), vm    # Unit-stride segment store template
# Examples
vlseg8e8.v vd, (rs1), vm   # Load eight vector registers with eight byte fields.
vsseg3e32.v vs3, (rs1), vm  # Store packed vector of 3*4-byte segments from vs3,vs3+1,vs3+2 to mem

对于加载操作,vd寄存器将保存从段中加载的第一个字段。对于存储操作,读取vs3寄存器以提供要存储到每个段的第一个字段。

# Example 1
# Memory structure holds packed RGB pixels (24-bit data structure, 8bpp)
vsetvli a1, t0, e8, ta, ma
vlseg3e8.v v8, (a0), vm
# v8 holds the red pixels
# v9 holds the green pixels
# v10 holds the blue pixels
# Example 2
# Memory structure holds complex values, 32b for real and 32b for imaginary
vsetvli a1, t0, e32, ta, ma
vlseg2e32.v v8, (a0), vm
# v8 holds real
# v9 holds imaginary

还有单位步长指令的“仅首个错误”版本。

# Template for vector fault-only-first unit-stride segment loads.
vlseg<nf>e<eew>ff.v vd, (rs1),  vm    # Unit-stride fault-only-first segment loads

对于“仅首个错误”的分段加载,如果在访问段的过程中检测到异常,无论元素索引是否为零,是否加载段的一个子集是由实现定义的。

这些指令可能会覆盖在报告陷阱的点之后或在修剪向量长度的点之后的目标向量寄存器组元素。

7.8.2 向量跨步段加载和存储

向量跨步段加载和存储会移动连续段,其中每个段由rs2 GPR参数中给出的字节跨步偏移量分隔。

注:支持负跨步和零跨步。

# Format
vlsseg<nf>e<eew>.v vd, (rs1), rs2, vm     # Strided segment loads
vssseg<nf>e<eew>.v vs3, (rs1), rs2, vm	  # Strided	segment	stores
# Examples
vsetvli a1, t0, e8, ta, ma
vlsseg3e8.v v4, (x5), x6    # Load bytes at addresses x5+i*x6   into v4[i],
                            #  and bytes at addresses x5+i*x6+1 into v5[i],
                            #  and bytes at addresses x5+i*x6+2 into v6[i] .
# Examples
vsetvli a1, t0, e32, ta, ma
vssseg2e32.v v2, (x5), x6   # Store words from v2[i] to address x5+i*x6
                            #   and words from v3[i] to address x5+i*x6+4

对每个段内的字段的访问可以以任何顺序发生,包括字节跨步使得段在内存中重叠的情况。

7.8.3 向量索引段加载和存储

向量索引段加载和存储会移动连续段,其中每个段位于由向量寄存器vs2中的字节偏移量与rs1字段中的标量基地址相加得到的地址处。提供了有序和无序两种形式,其中有序形式按照元素顺序访问段。然而,即使对于有序形式,对单个段内的字段的访问也是无序的。

数据向量寄存器组的EEW=SEW,EMUL=LMUL,而索引向量寄存器组的EEW在指令中编码,且EMUL=(EEW/SEW)*LMUL。

# Format
vluxseg<nf>ei<eew>.v vd, (rs1), vs2, vm   # Indexed-unordered segment loads
vloxseg<nf>ei<eew>.v vd, (rs1), vs2, vm   # Indexed-ordered segment loads
vsuxseg<nf>ei<eew>.v vs3, (rs1), vs2, vm  # Indexed-unordered segment stores
vsoxseg<nf>ei<eew>.v vs3, (rs1), vs2, vm  # Indexed-ordered segment stores
# Examples
vsetvli a1, t0, e8, ta, ma
vluxseg3ei32.v v4, (x5), v3     # Load bytes at addresses x5+v3[i]   into v4[i],
                                # and bytes at addresses x5+v3[i]+1 into v5[i],
                                # and bytes at addresses x5+v3[i]+2 into v6[i] .
# Examples
vsetvli a1, t0, e32, ta, ma
vsuxseg2ei32.v v2, (x5), v5     # Store words from v2[i] to address x5+v5[i]
                                # and words from v3[i] to address x5+v5[i]+4
 

对于向量索引段加载,目标向量寄存器组不能与源向量寄存器组(由vs2指定)重叠,否则指令编码将被保留。

注:此约束支持在加载结构过程中引发异常的索引段加载的重新启动。

7.9 向量加载/存储全寄存器指令

向量全寄存器加载指令的格式(LOAD-FP 主操作码下)

向量全寄存器存储指令的格式(STORE-FP 主操作码下)

这些指令加载和存储整个向量寄存器组。

这些指令旨在用于在不知道向量寄存器的当前内容类型或长度,或者修改vl和vtype成本较高时,保存和恢复向量寄存器。示例包括编译器寄存器溢出、在向量函数调用中通过向量寄存器传递值、中断处理程序和操作系统上下文切换。软件可以通过读取vlenb寄存器来确定传输的字节数。

加载指令在mew和width字段中编码了一个EEW,遵循常规单位步长加载的模式。

由于寄存器内的字节布局与内存中的字节布局相同,因此无论EEW如何,都会将相同的数据写入目标寄存器组。因此,本来只提供EEW=8的变体就足够了。提供完整的EEW变体集,以便编码的EEW可以用作提示,表明目标寄存器组接下来将使用此EEW进行访问,这有助于在内部重新排列数据的实现。

向量全寄存器存储指令的编码类似于EEW=8的元素的无掩码单位步长存储。

nf字段使用NFIELDS编码来编码要加载和存储的向量寄存器的数量(见图NFIELDS编码)。编码的寄存器数量必须是2的幂,并且向量寄存器编号必须与向量寄存器组对齐,否则指令编码将被保留。NFIELDS表示要传输的向量寄存器的数量,按基数连续编号。仅支持NFIELDS值为1、2、4、8,其他值保留。当传输多个寄存器时,编号最低的向量寄存器保存在编号最低的内存地址中,并且连续的向量寄存器编号在内存中连续放置。

这些指令以有效向量长度evl=NFIELDS*VLEN/EEW运行,无论vtype和vl的当前设置如何。如果vstart=vl,则不写入任何元素的通常属性不适用于这些指令。相反,如果vstart=evl,则不写入任何元素。

这些指令的操作类似于无掩码的单位步长加载和存储指令,其中基址通过rs1指定的标量x寄存器传递。

如果基址没有自然对齐到编码的EEW的大小(以字节为单位,即EEW/8)或实现的最小支持SEW大小(以字节为单位,即SEW MIN/8)中的较大值,则允许实现在全寄存器加载和存储时引发未对齐地址异常。

允许基于未对齐到编码的EEW来引发未对齐异常,从而简化了这些指令的实现。某些子集实现可能不支持较小的SEW宽度,因此即使大于编码的EEW,也允许为最小支持的SEW报告未对齐异常。例如,一个极端的非标准实现可能有SEW MIN>XLEN。软件环境可以规定支持ABI的最小对齐要求。

# Format of whole register load and store instructions.
vl1r.v v3, (a0)       # Pseudoinstruction equal to vl1re8.v
vl1re8.v    v3, (a0)  # Load v3 with VLEN/8 bytes held at address in a0
vl1re16.v   v3, (a0)  # Load v3 with VLEN/16 halfwords held at address in a0
vl1re32.v   v3, (a0)  # Load v3 with VLEN/32 words held at address in a0
vl1re64.v   v3, (a0)  # Load v3 with VLEN/64 doublewords held at address in a0
vl2r.v v2, (a0)       # Pseudoinstruction equal to vl2re8.v v2, (a0)
vl2re8.v    v2, (a0)  # Load v2-v3 with 2*VLEN/8 bytes from address in a0
vl2re16.v   v2, (a0)  # Load v2-v3 with 2*VLEN/16 halfwords held at address in a0
vl2re32.v   v2, (a0)  # Load v2-v3 with 2*VLEN/32 words held at address in a0
vl2re64.v   v2, (a0)  # Load v2-v3 with 2*VLEN/64 doublewords held at address in a0

vl4r.v v4, (a0)	# Pseudoinstruction equal to vl4re8.v
vl4re8.v    v4, (a0)	# Load v4-v7 with 4*VLEN/8 bytes from address in a0
vl4re16.v   v4, (a0)	
vl4re32.v   v4, (a0)	
vl4re64.v   v4, (a0)	
vl8r.v v8, (a0)	# Pseudoinstruction equal to vl8re8.v
vl8re8.v    v8, (a0)	# Load v8-v15 with 8*VLEN/8 bytes from address in a0
vl8re16.v   v8, (a0)	
vl8re32.v   v8, (a0)	
vl8re64.v   v8, (a0)	
vs1r.v v3, (a1)      # Store v3 to address in a1
vs2r.v v2, (a1)      # Store v2-v3 to address in a1
vs4r.v v4, (a1)      # Store v4-v7 to address in a1
vs8r.v v8, (a1)      # Store v8-v15 to address in a1

对于不支持的EEW值,实现在vl<nf>r指令上应引发非法指令异常。

我们曾考虑增加一个全寄存器掩码加载指令(vl1rm.v),但已决定从初始扩展中省略。其主要目的是通知微体系结构,该数据将用作掩码。使用以下代码序列可以达到相同的效果,其成本最多为四条指令。其中,第一条指令很可能可以删除,因为vl通常已经在一个标量寄存器中,而最后一条指令如果接下来的向量指令需要新的SEW/LMUL,则可能已经存在。因此,在最好的情况下,仅需要两条指令(其中只有一条执行向量操作)即可合成专用指令的效果:

csr r t0, vl               # Save current vl (potentially not needed)
vsetvli t1, x0, e8, m8     # Maximum VLMAX    
vlm.v v0, (a0)             # Load mask register
vsetvli x0, t0,	<new type> # Restore vl (potentially already present)

  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: RISC-V是一种开放的指令集架构,它是根据精简指令集计算机(RISC)的原则设计的。RISC-V指令集中文版是对RISC-V指令集进行中文翻译的版本。这个翻译版本的目的是为了方便中文用户理解和使用RISC-V指令集RISC-V指令集中文版包括了一系列指令,用于执行不同的计算和操作。这些指令可以分为几个类别,包括算术指令、逻辑指令、存储访问指令、控制转移指令等。 算术指令主要用于实现加法、减法、乘法和除法等算术运算。逻辑指令主要用于实现逻辑运算,如与、或和非等。存储访问指令用于访问存储器中的数据,包括读取和写入操作。控制转移指令用于控制程序的执行流程,如跳转、函数调用等。 RISC-V指令集中文版的设计遵循了精简指令集计算机的原则,它采用了固定长度的指令格式,每条指令都有相同数量的位数。这种设计简化了指令的解码和执行过程,提高了指令的执行效率。 通过使用RISC-V指令集中文版,开发者可以更容易地编写和调试程序。同时,由于RISC-V是开放的指令集架构,任何人都可以自由使用和扩展它,这为开发者提供了更大的灵活性和创造性。 总之,RISC-V指令集中文版是一种开放的、简洁而功能强大的指令集架构,它为中文用户提供了一种更加便捷和灵活的编程方式。 ### 回答2: RISC-V是一种开源的指令集架构,其设计目标是简洁、清晰和可扩展RISC-V指令集的中文版描述了指令的功能和操作方式,以便于中文用户理解和使用。 RISC-V指令集中包括了基本的指令和扩展指令。基本指令包括了加载存储、算术、逻辑、控制等常用的操作。例如,LOAD指令可以从内存中加载数据到寄存器中,STORE指令可以将寄存器的数据存储到内存中。算术指令比如ADD、SUB、MUL等可以执行加法、减法、乘法等运算。逻辑指令如AND、OR、XOR可以进行与、或、异或等逻辑运算。控制指令如BRANCH、JUMP可以用于条件判断和跳转。这些基本指令可以满足大部分应用的需求。 扩展指令则可根据应用需求进行定制。例如,浮点指令扩展可以添加浮点数运算指令,向量指令扩展可以添加向量运算指令。这些扩展指令能够满足不同应用领域的需求,提高了RISC-V指令集的通用性和灵活性。 RISC-V指令集中的指令使用类似于汇编语言的格式进行描述。每个指令由操作码和操作数组成。操作码表示指令的功能,操作数则是用于指定操作的寄存器或者内存地址。指令可以通过相应的汇编器进行编译,生成机器码后可以在RISC-V架构的处理器上执行。 总的来说,RISC-V指令集中文版提供了详细的指令描述和例子,使得中文用户可以理解和使用这个开源指令集,并且可以根据需要进行扩展,以满足不同应用场景的需求。 ### 回答3: RISC-V指令集是一种开源的、精简的指令集架构。其设计思想是为了简化处理器架构,提供更高的性能和灵活性。 RISC-V指令集的设计原则是简化和统一。它采用了固定大小的指令格式,指令长度为32位,其中包含指令操作码、操作数和地址等。这种设计能够提高指令的解码效率,并且使得指令的执行速度更快。 RISC-V指令集提供了丰富的指令集扩展方式,可以根据特定应用的需求进行扩展。这样的设计使得RISC-V成为了一种高度可定制化的指令集架构,适用于多种不同的应用领域。 另外,RISC-V指令集还提供了多种特权级别的支持。在特权级别方面,RISC-V定义了四个特权级别:用户模式、监管模式、机器模式和超级模式。这样的设计使得RISC-V可以适应不同的操作环境和安全需求。 最后,RISC-V指令集是一种开源的指令集架构,这意味着任何人都可以使用、修改和贡献代码。这种开源的特性促进了RISC-V的发展和创新,使得更多的人参与到指令集架构的设计和优化中。 总而言之,RISC-V指令集是一种开源的、精简的指令集架构,它具有简洁统一、可扩展性强、支持多种特权级别等特点。这些特性使得RISC-V成为了一种广泛应用的指令集架构,并在众多领域受到了广泛的关注和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值