RISCV 向量指令集和NICE接口学习笔记

本文档链接 https://blog.csdn.net/weixin_42487906/article/details/115437890

RISCV向量指令集学习

参考链接

https://github.com/riscv/riscv-v-spec
RSIC-V——指令集spec阅读笔记——向量扩展0.9
RISC-V Vector Extension学习笔记

向量指令集用例

可以对照下面的说明来看这个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.text
.balign 4
.global vvaddint32
# vector-vector add routine of 32-bit integers
# void vvaddint32(size_t n, const int*x, const int*y, int*z)
# { for (size_t i=0; i<n; i++) { z[i]=x[i]+y[i]; } }
#
# a0 = n, a1 = x, a2 = y, a3 = z
# Non-vector instructions are indented
vvaddint32:
vsetvli t0, a0, e32, ta,ma # Set vector length based on 32-bit vectors
vle32.v v0, (a1) # Get first vector
sub a0, a0, t0 # Decrement number done
slli t0, t0, 2 # Multiply number done by 4 bytes
add a1, a1, t0 # Bump pointer
vle32.v v1, (a2) # Get second vector
add a2, a2, t0 # Bump pointer
vadd.vv v2, v0, v1 # Sum vectors
vse32.v v2, (a3) # Store result
add a3, a3, t0 # Bump pointer
bnez a0, vvaddint32 # Loop back
ret # Finished

名词解释

ELEN 向量中单个元素的最大长度,bit为单位,要求ELEN>=8,且为2的幂
VLEN 向量寄存器的位数,bit为单位,要求VLEN ≥ ELEN,并且必须是2的幂
SLEN 分段距离(The striping distance in bits),要求必须为VLEN ≥ SLEN ≥ 32,并且必须为2的幂,这个暂时没懂
SEW 标准元素宽度,以bit为单位,指向量中一个元素占向量寄存器中的位数
LMUL 向量寄存器分组数
寄存器定义
v0-v31 向量数据寄存器,共32个,固定位宽为VLEN位
vtype 向量数据类型寄存器,并且只能通过vsetvl{i}指令进行更新,向量类型还决定了每个向量寄存器中元素的排布,以及如何对多个向量寄存器进行分组。
vsew[2:0] 变化的标准元素宽度(SEW, standard element width)值通过vsew中的值设置。默认情况下,向量寄存器被视为分成 VLEN / SEW 个标准宽度元素。
vlmul[2:0 ] 向量寄存器分组,分成一组的多个向量寄存器可以当作一个操作数来用,用来存放一个向量,该值也可以是小数,用来等效增加向量数据寄存器的数量
VLMAX VLMAX = LMUL * VLEN / SEW,
vta和vma 这两位元素值在执行向量指令期间分别修改了目标尾部元素(Tail Elements)和非活跃的掩码元素(Inactive masked-off Elements)的行为。
vill vill位用于编码先前的vsetvl{i} 指令试图向vtype写入不支持的值
vl 向量长度寄存器,以存放向量总共有多少个元素,只能通过vsetvli和vsetvl指令进行更新。
vlen 向量寄存器长度寄存器,是一个常数,保存值 VLEN / 8,即向量寄存器长度(以字节为单位)。
vstart vstart是一个可读可写的CSR寄存器,指定向量指令要执行的第一个元素的索引。每个向量指令执行完后,该寄存器清零。
vcsr 向量控制和状态寄存器vcsr,保存定点舍入的方式和饱和状态

向量元素到向量寄存器的映射

根据当前的 SEW 和 LMUL 设置以及 ELEN,VLEN 和 SLEN 的值,怎么将不同宽度的元素存放到矢量寄存器的字节中。并且使用最少位数的最低有效字节将元素放到每个向量寄存器中。
当 VLEN=SLEN , LMUL=1 时,从向量寄存器的最低有效位到最高有效位依次对元素进行简单排布。当 LMUL <1 时,仅使用向量寄存器中的第一个 LMUL * VLEN / SEW 元素。 向量寄存器中的剩余空间被视为尾部的一部分。



VLEN = SLEN 且 LMUL > 1时, 将向量寄存器分组后,根据向量寄存器组中的向量寄存器来划分组中的元素。当 SLEN = VLEN 时,按元素顺序将其放在组中的每个向量寄存器中,填满一个向量寄存器后,便移至组中下一个编号最高的向量寄存器。



向量 ISA 的设计目的是支持混合宽度操作,并且不需要大量显式的额外的重排指令,也不需要大量额外的数据路径(datapath)布线。在对不同精度值的向量进行操作时,推荐的做法是动态修改 vtype 值,从而使得 SEW/LMUL 为常量(因此 VLMAX 常量)。向量寄存器分组因子(LMUL)按相关元素大小增加,这样每个向量寄存器组可以保存相同数量的向量元素(本例中 VLMAX=16 ),从而简化 stripmining 代码。下表列出了执行混合宽度操作的循环的每个可能的 SEW / LMUL 操作点。 每列代表一个恒定的 SEW / LMUL 操作点。 表中列出的内容是 LMUL 值,该值生成该列的 SEW / LMUL 值。 在同一列中, LMUL 的值不同,但 VLMAX 值相同。(可以保证每个向量寄存器组中的向量元素数量相同)

配置寄存器操作指令

vsetvli/vsetvl

用例

1
2
vsetvli rd, rs1, vtypei # rd = new vl, rs1 = AVL, vtypei = new vtype setting
vsetvl rd, rs1, rs2 # rd = new vl, rs1 = AVL, rs2 = new vtype value

解释

指令根据其参数设置 vtype 和 vl CSRs,并将 vl 的新值写入 rd。
两个指令的区别:vtypei是个立即数,rs2是个寄存器
AVL=应用程序向量长度

vsetvl{i}指令首先根据 vtype 参数,设定 VLMAX ,然后设置vl服从以下约束:

  • 如果 AVL ≤ VLMAX ,则 vl = AVL
  • 如果 AVL < (2 * VLMAX),则ceil(AVL / 2) ≤ vl ≤ VLMAX
  • 如果 AVL ≥ (2 * VLMAX),则 vl = VLMAX
  • 如果输入相同的 AVL 和 VLMAX 值,则任何实现中,v1 都是确定的
    满足之前提及的规则:
    如果 AVL = 0,则 vl = 0
    如果 AVL > 0,vl > 0
    vl ≤ VLMAX
    vl ≤ AVL
    从 vl 中读取的值(用作 vsetvl{i} 的 AVL 参数时)会在 vl 中产生相同的值,前提是所得的 VLMAX 等于读取vl时的 VLMAX 值

    向量操作指令中的掩码

掩码vm
在指令中占一位,使用v0寄存器存放掩码值,vm为1时不启动掩码,vm为0时,当v0的相应位为1,目标向量寄存器写入相应的值

掩码向量的加载操作不会更新目标向量寄存器组中的非活跃元素。掩码向量的存储操作只更新内存中的活跃元素。

向量加载和存储指令(访存)

mop 访存时选择访存模式


支持连续访存,跨步访存和按索引访存

lumop/sumop

还没搞懂是做什么用的 fault only first似乎可以简化循环操作

向量加载/存储的宽度编码

  • Mem bits(内存位)是内存中访问的每个元素的大小。
  • Reg bits(寄存器位)是寄存器中访问的每个元素的大小。

向量单步幅跨步(Unit-Stride)指令

1
2
#vd destination, rs1 base address, vm is mask encoding (v0.t or <missing>)
vle32.v vd, (rs1), vm # 32-bit loads

l代表load,e32代表向量元素长32

1
2
#vs3 store data, rs1 base address, vm is mask encoding (v0.t or <missing>)
vse64.v vs3, (rs1), vm # 64-bit stores

s代表save

向量跨步(Strided)指令

1
2
# vd destination, rs1 base address, rs2 byte stride
vlse8.v vd, (rs1), rs2, vm # Load bytes separated by stride

vls中l代表load,s代表stride,rs2存放跨步值

1
2
# vs3 store data, rs1 base address, rs2 byte stride
vsse128.v vs3, (rs1), rs2, vm # Store 128b values separated by stride.

vsse128中,第一个s是save,第二个是stride

向量索引(indexed)指令

1
2
# vd destination, rs1 base address, vs2 indices
vlxei16.v vd, (rs1), vs2, vm # vs2 data EEW = SEW, indices EEW = 16b

有序加载,vs2存放索引,vs2中元素大小为16bit

1
2
# Vector unordered-indexed store instructions
vsuxei64.v vs3, (rs1), vs2, vm # SEW data, 64b indices

无序存储,vs2中元素大小为64bit

向量原子操作

原子操作指令 暂时用不到

向量计算指令

向量的算术指令使用与 OP-FP 相邻的新的主要操作码1010111。 funct3 字段的三位用于定义向量指令的子类。

向量与标量之间的运算可以采取三种可能的形式,但无论采取哪种形式,都要从 vs2 指定的向量寄存器组中获取一个操作数向量,并从三个替代源之一获取第二个标量源操作数。

  • 对于整数运算,标量可以是编码在 rs1 字段中5位立即数。该值通过符号扩展或加零扩展到SEW 位。
  • 对于整数运算,可以从rs1 指定的标量寄存器x中提取标量。如果 XLEN > SEW,则使用x的最低有效SEW位。如果 XLEN < SEW,则x 寄存器的值通过符号扩展到 SEW 位。
  • 对于浮点运算,可以从标量寄存器f中获取标量。如果 FLEN> SEW,则检查f寄存器中的值是否为有效的 NaN-boxed 值,如果是,则使用f寄存器的最低有效SEW位,否则将使用规范的 NaN 值。如果执行向量指令时,任何浮点向量操作数的 EEW 都不是支持的浮点类型宽度(包括 FLEN <SEW 时),则会引发非法指令异常。

    向量算术指令在vm 字段下被掩码。

1
2
3
4
# Operations returning vector results, masked by vm (v0.t, <nothing>)
vop.vv vd, vs2, vs1, vm # integer vector-vector vd[i] = vs2[i] op vs1[i]
vop.vx vd, vs2, rs1, vm # integer vector-scalar vd[i] = vs2[i] op x[rs1]
vop.vi vd, vs2, imm, vm # integer vector-immediate vd[i] = vs2[i] op imm

浮点指令

1
2
vfop.vv  vd, vs2, vs1, vm # FP vector-vector operation vd[i] = vs2[i] fop vs1[i]
vfop.vf vd, vs2, rs1, vm # FP vector-scalar operation vd[i] = vs2[i] fop f[rs1]4

不同的指令格式

1
2
3
4
5
6
7
# Integer operations overwriting sum input
vop.vv vd, vs1, vs2, vm # vd[i] = vs1[i] * vs2[i] + vd[i]
vop.vx vd, rs1, vs2, vm # vd[i] = x[rs1] * vs2[i] + vd[i]

# Integer operations overwriting product input
vop.vv vd, vs1, vs2, vm # vd[i] = vs1[i] * vd[i] + vs2[i]
vop.vx vd, rs1, vs2, vm # vd[i] = x[rs1] * vd[i] + vs2[i]

从指令上看没有什么区别,怎么区分二者呢
通过vop的不同来区分

Widening向量算术指令

一些矢量算术指令被定义为加宽(widening) 操作,其中 EEW = 2 * SEW ,EMUL = 2 * LMUL。
第一个操作数可以是单宽度或双宽度。这些通常在操作码上具有前缀 vw,或对于矢量浮点运算具有前缀 vfw

1
2
3
# Double-width result, two single-width sources: 2*SEW = SEW op SEW
vwop.vv vd, vs2, vs1, vm # integer vector-vector vd[i] = vs2[i] op vs1[i]
vwop.vx vd, vs2, rs1, vm # integer vector-scalar vd[i] = vs2[i] op x[rs1]

结果为双宽度,两个源操作数均为单宽度

1
2
3
# Double-width result, first source double-width, second source single-width: 2*SEW = 2*SEW op SEW
vwop.wv vd, vs2, vs1, vm # integer vector-vector vd[i] = vs2[i] op vs1[i]
vwop.wx vd, vs2, rs1, vm # integer vector-scalar vd[i] = vs2[i] op x[rs1]

结果为双宽度,源操作数1为双宽度,源操作数2为单宽度

Narrowing向量算术指令

和加宽指令类似
这些指令将 EEW/EMUL = 2 * SEW / 2 * LMUL 的向量寄存器组转换为具有当前 LMUL/SEW 向量/元素的向量寄存器组。
如果 EEW> ELEN 或 EMUL> 8,则会引发非法指令异常。

向量单宽度加减

1
2
3
4
5
6
7
8
9
10
11
12
# Integer adds.
vadd.vv vd, vs2, vs1, vm # Vector-vector
vadd.vx vd, vs2, rs1, vm # vector-scalar
vadd.vi vd, vs2, imm, vm # vector-immediate

# Integer subtract
vsub.vv vd, vs2, vs1, vm # Vector-vector
vsub.vx vd, vs2, rs1, vm # vector-scalar

# Integer reverse subtract
vrsub.vx vd, vs2, rs1, vm # vd[i] = rs1 - vs2[i]
vrsub.vi vd, vs2, imm, vm # vd[i] = imm - vs2[i]

向量结果加宽加减,包括有符号数和无符号数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Widening unsigned integer add/subtract, 2*SEW = SEW +/- SEW
vwaddu.vv vd, vs2, vs1, vm # vector-vector
vwaddu.vx vd, vs2, rs1, vm # vector-scalar
vwsubu.vv vd, vs2, vs1, vm # vector-vector
vwsubu.vx vd, vs2, rs1, vm # vector-scalar

# Widening signed integer add/subtract, 2*SEW = SEW +/- SEW
vwadd.vv vd, vs2, vs1, vm # vector-vector
vwadd.vx vd, vs2, rs1, vm # vector-scalar
vwsub.vv vd, vs2, vs1, vm # vector-vector
vwsub.vx vd, vs2, rs1, vm # vector-scalar

# Widening unsigned integer add/subtract, 2*SEW = 2*SEW +/- SEW
vwaddu.wv vd, vs2, vs1, vm # vector-vector
vwaddu.wx vd, vs2, rs1, vm # vector-scalar
vwsubu.wv vd, vs2, vs1, vm # vector-vector
vwsubu.wx vd, vs2, rs1, vm # vector-scalar

# Widening signed integer add/subtract, 2*SEW = 2*SEW +/- SEW
vwadd.wv vd, vs2, vs1, vm # vector-vector
vwadd.wx vd, vs2, rs1, vm # vector-scalar
vwsub.wv vd, vs2, vs1, vm # vector-vector
vwsub.wx vd, vs2, rs1, vm # vector-scalar

向量有,无符号数元素位数扩展

1
2
3
4
5
6
7
vzext.vf2 vd, vs2, vm  # Zero-extend SEW/2 source to SEW destination
vsext.vf2 vd, vs2, vm # Sign-extend SEW/2 source to SEW destination
vzext.vf4 vd, vs2, vm # Zero-extend SEW/4 source to SEW destination
vsext.vf4 vd, vs2, vm # Sign-extend SEW/4 source to SEW destination
vzext.vf8 vd, vs2, vm # Zero-extend SEW/8 source to SEW destination
vsext.vf8 vd, vs2, vm # Sign-extend SEW/8 source to SEW destination

带进位借位加减法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Produce sum with carry.

# vd[i] = vs2[i] + vs1[i] + v0.mask[i]
vadc.vvm vd, vs2, vs1, v0 # Vector-vector

# vd[i] = vs2[i] + x[rs1] + v0.mask[i]
vadc.vxm vd, vs2, rs1, v0 # Vector-scalar

# vd[i] = vs2[i] + imm + v0.mask[i]
vadc.vim vd, vs2, imm, v0 # Vector-immediate

# Produce difference with borrow.

# vd[i] = vs2[i] - vs1[i] - v0.mask[i]
vsbc.vvm vd, vs2, vs1, v0 # Vector-vector

# vd[i] = vs2[i] - x[rs1] - v0.mask[i]
vsbc.vxm vd, vs2, rs1, v0 # Vector-scalar

位逻辑指令

1
2
3
4
5
6
7
8
9
10
11
12
13
# Bitwise logical operations.
vand.vv vd, vs2, vs1, vm # Vector-vector
vand.vx vd, vs2, rs1, vm # vector-scalar
vand.vi vd, vs2, imm, vm # vector-immediate

vor.vv vd, vs2, vs1, vm # Vector-vector
vor.vx vd, vs2, rs1, vm # vector-scalar
vor.vi vd, vs2, imm, vm # vector-immediate

vxor.vv vd, vs2, vs1, vm # Vector-vector
vxor.vx vd, vs2, rs1, vm # vector-scalar
vxor.vi vd, vs2, imm, vm # vector-immediate

单宽度位移指令,逻辑左移,逻辑和算数右移

1
2
3
4
5
6
7
8
9
10
11
12
13
# Bit shift operations
vsll.vv vd, vs2, vs1, vm # Vector-vector
vsll.vx vd, vs2, rs1, vm # vector-scalar
vsll.vi vd, vs2, uimm, vm # vector-immediate

vsrl.vv vd, vs2, vs1, vm # Vector-vector
vsrl.vx vd, vs2, rs1, vm # vector-scalar
vsrl.vi vd, vs2, uimm, vm # vector-immediate

vsra.vv vd, vs2, vs1, vm # Vector-vector
vsra.vx vd, vs2, rs1, vm # vector-scalar
vsra.vi vd, vs2, uimm, vm # vector-immediate

向量比较指令,符号左右两边分别是vs2和vs1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# Set if equal
vmseq.vv vd, vs2, vs1, vm # Vector-vector
vmseq.vx vd, vs2, rs1, vm # vector-scalar
vmseq.vi vd, vs2, imm, vm # vector-immediate

# Set if not equal
vmsne.vv vd, vs2, vs1, vm # Vector-vector
vmsne.vx vd, vs2, rs1, vm # vector-scalar
vmsne.vi vd, vs2, imm, vm # vector-immediate

# Set if less than, unsigned
vmsltu.vv vd, vs2, vs1, vm # Vector-vector
vmsltu.vx vd, vs2, rs1, vm # Vector-scalar

# Set if less than, signed
vmslt.vv vd, vs2, vs1, vm # Vector-vector
vmslt.vx vd, vs2, rs1, vm # vector-scalar

# Set if less than or equal, unsigned
vmsleu.vv vd, vs2, vs1, vm # Vector-vector
vmsleu.vx vd, vs2, rs1, vm # vector-scalar
vmsleu.vi vd, vs2, imm, vm # Vector-immediate

# Set if less than or equal, signed
vmsle.vv vd, vs2, vs1, vm # Vector-vector
vmsle.vx vd, vs2, rs1, vm # vector-scalar
vmsle.vi vd, vs2, imm, vm # vector-immediate

# Set if greater than, unsigned
vmsgtu.vx vd, vs2, rs1, vm # Vector-scalar
vmsgtu.vi vd, vs2, imm, vm # Vector-immediate

# Set if greater than, signed
vmsgt.vx vd, vs2, rs1, vm # Vector-scalar
vmsgt.vi vd, vs2, imm, vm # Vector-immediate

# Following two instructions are not provided directly
# Set if greater than or equal, unsigned
# vmsgeu.vx vd, vs2, rs1, vm # Vector-scalar
# Set if greater than or equal, signed
# vmsge.vx vd, vs2, rs1, vm # Vector-scalar

向量找最大最小指令,最大/小结果放入vd中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Unsigned minimum
vminu.vv vd, vs2, vs1, vm # Vector-vector
vminu.vx vd, vs2, rs1, vm # vector-scalar

# Signed minimum
vmin.vv vd, vs2, vs1, vm # Vector-vector
vmin.vx vd, vs2, rs1, vm # vector-scalar

# Unsigned maximum
vmaxu.vv vd, vs2, vs1, vm # Vector-vector
vmaxu.vx vd, vs2, rs1, vm # vector-scalar

# Signed maximum
vmax.vv vd, vs2, vs1, vm # Vector-vector
vmax.vx vd, vs2, rs1, vm # vector-scalar

向量单宽度整数乘法指​​令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Signed multiply, returning low bits of product
vmul.vv vd, vs2, vs1, vm # Vector-vector
vmul.vx vd, vs2, rs1, vm # vector-scalar

# Signed multiply, returning high bits of product
vmulh.vv vd, vs2, vs1, vm # Vector-vector
vmulh.vx vd, vs2, rs1, vm # vector-scalar

# Unsigned multiply, returning high bits of product
vmulhu.vv vd, vs2, vs1, vm # Vector-vector
vmulhu.vx vd, vs2, rs1, vm # vector-scalar

# Signed(vs2)-Unsigned multiply, returning high bits of product
vmulhsu.vv vd, vs2, vs1, vm # Vector-vector
vmulhsu.vx vd, vs2, rs1, vm # vector-scalar

向量单宽度整数除法及求余数指​​令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Unsigned divide.
vdivu.vv vd, vs2, vs1, vm # Vector-vector
vdivu.vx vd, vs2, rs1, vm # vector-scalar

# Signed divide
vdiv.vv vd, vs2, vs1, vm # Vector-vector
vdiv.vx vd, vs2, rs1, vm # vector-scalar

# Unsigned remainder
vremu.vv vd, vs2, vs1, vm # Vector-vector
vremu.vx vd, vs2, rs1, vm # vector-scalar

# Signed remainder
vrem.vv vd, vs2, vs1, vm # Vector-vector
vrem.vx vd, vs2, rs1, vm # vector-scalar

向量结果双宽度整数乘法指​​令

1
2
3
4
5
6
7
8
9
10
11
12
# Widening signed-integer multiply
vwmul.vv vd, vs2, vs1, vm # vector-vector
vwmul.vx vd, vs2, rs1, vm # vector-scalar

# Widening unsigned-integer multiply
vwmulu.vv vd, vs2, vs1, vm # vector-vector
vwmulu.vx vd, vs2, rs1, vm # vector-scalar

# Widening signed-unsigned integer multiply
vwmulsu.vv vd, vs2, vs1, vm # vector-vector
vwmulsu.vx vd, vs2, rs1, vm # vector-scalar

向量单宽度整数乘加指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Integer multiply-add, overwrite addend
vmacc.vv vd, vs1, vs2, vm # vd[i] = +(vs1[i] * vs2[i]) + vd[i]
vmacc.vx vd, rs1, vs2, vm # vd[i] = +(x[rs1] * vs2[i]) + vd[i]

# Integer multiply-sub, overwrite minuend
vnmsac.vv vd, vs1, vs2, vm # vd[i] = -(vs1[i] * vs2[i]) + vd[i]
vnmsac.vx vd, rs1, vs2, vm # vd[i] = -(x[rs1] * vs2[i]) + vd[i]

# Integer multiply-add, overwrite multiplicand
vmadd.vv vd, vs1, vs2, vm # vd[i] = (vs1[i] * vd[i]) + vs2[i]
vmadd.vx vd, rs1, vs2, vm # vd[i] = (x[rs1] * vd[i]) + vs2[i]

# Integer multiply-sub, overwrite multiplicand
vnmsub.vv vd, vs1, vs2, vm # vd[i] = -(vs1[i] * vd[i]) + vs2[i]
vnmsub.vx vd, rs1, vs2, vm # vd[i] = -(x[rs1] * vd[i]) + vs2[i]

向量加宽整数乘加指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Widening unsigned-integer multiply-add, overwrite addend
vwmaccu.vv vd, vs1, vs2, vm # vd[i] = +(vs1[i] * vs2[i]) + vd[i]
vwmaccu.vx vd, rs1, vs2, vm # vd[i] = +(x[rs1] * vs2[i]) + vd[i]

# Widening signed-integer multiply-add, overwrite addend
vwmacc.vv vd, vs1, vs2, vm # vd[i] = +(vs1[i] * vs2[i]) + vd[i]
vwmacc.vx vd, rs1, vs2, vm # vd[i] = +(x[rs1] * vs2[i]) + vd[i]

# Widening signed-unsigned-integer multiply-add, overwrite addend
vwmaccsu.vv vd, vs1, vs2, vm # vd[i] = +(signed(vs1[i]) * unsigned(vs2[i])) + vd[i]
vwmaccsu.vx vd, rs1, vs2, vm # vd[i] = +(signed(x[rs1]) * unsigned(vs2[i])) + vd[i]

# Widening unsigned-signed-integer multiply-add, overwrite addend
vwmaccus.vx vd, rs1, vs2, vm # vd[i] = +(unsigned(x[rs1]) * signed(vs2[i])) + vd[i]

向量整数合并指令

1
2
3
4
vmerge.vvm vd, vs2, vs1, v0  # vd[i] = v0.mask[i] ? vs1[i] : vs2[i]
vmerge.vxm vd, vs2, rs1, v0 # vd[i] = v0.mask[i] ? x[rs1] : vs2[i]
vmerge.vim vd, vs2, imm, v0 # vd[i] = v0.mask[i] ? imm : vs2[i]

向量整数移动指令

1
2
3
4
vmv.v.v vd, vs1 # vd[i] = vs1[i]
vmv.v.x vd, rs1 # vd[i] = rs1
vmv.v.i vd, imm # vd[i] = imm

整数标量移动指令

整数标量读/写指令在标量x寄存器和向量寄存器的元素0之间传输单个值。指令忽略LMUL和向量寄存器组。

1
2
3
vmv.xs rd,vs2#x [rd] = vs2 [0](vs1 = 0
vmv.sx vd,rs1#vd [0] = x [rs1](vs2 = 0

需求分析

  1. 向量的加载和存储,支持跨步,按索引范存(访存操作
  2. 向量单个元素位宽可指定(8bit,32bit)/可能支持向量寄存器分组
  3. 向量之间/向量和常数的加减乘除运算
  4. 向量之间/向量和常数的比较运算
  5. 向量自身所有元素求和
  6. 向量元素的位逻辑运算
  7. 求向量中,向量元素的最大最小值

RISCV指令格式


  • 给用户自定义的指令操作码为Custom-0, Custom-1, Custom-2, Custom-3
1
2
3
4
wire opcode_custom0 = (opcode == 7'b0001011); 
wire opcode_custom1 = (opcode == 7'b0101011);
wire opcode_custom2 = (opcode == 7'b1011011);
wire opcode_custom3 = (opcode == 7'b1111011);
  • 操作码如上,操作码定义为Custom-0, Custom-1, Custom-2, Custom-3,其余部分可仿照向量指令集,指令集主要由func3和func7区分
  • 根据NICE示例代码可知,指令格式可为任意种类指令格式,但是文档中给出,指令格式仅使用R格式指令

指令预设

访存指令

向量的加载和存储,支持跨步,按索引范存(访存操作
占用一个custom操作数,custom1

  1. 5bit保存要加载/存储的内存地址的寄存器编号
  2. 5bit保存若跨步访存的步长所在的寄存器编号/或按索引访存所存放索引的向量寄存器地址
  3. 5bit保存要存或取数据的向量寄存器的编号
  4. 2bit编码向量元素宽度
  5. 2bit编码采用连续访存还是跨步访存还是索引范存
  6. 1bit编码读操作还是写操作
    按上述要求,采用R指令,1.2.3分给rs1,rs2,rs3,456分给func7
3.4.5.6.

也可采用R型指令,可分给custom2.3.4,具体指令类型由fun7指定(待定

NICE接口学习

NICE接口官方给出了较详细的文档说明
芯来官方资料汇总 https://www.rvmcu.com/community-topic-id-340.html
官方文档说明 https://doc.nucleisys.com/hbirdv2/core/core.html#nice
nice协处理器实现示例 https://github.com/riscv-mcu/e203_hbirdv2/tree/master/rtl/e203/subsys
协处理器使用示例 https://github.com/Nuclei-Software/nuclei-board-labs/tree/master/e203_hbirdv2/common

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2021 张竞豪的小岛 All Rights Reserved.

UV : | PV :