RISC-Vのベクトル命令について勉強している。ベクトル拡張の仕様はv0.8をベースにしている。命令のエンコーディングについて調べているが、理解に時間がかかっているのでまとめてみる。
公式の仕様書には、以下のようなエンコーディングのリストが載っているが、何が何だか分からない。

まず、この表について理解する必要がある。この表はfunct3のエンコーディングによって複数の命令の分類があることを示している。そしてそれぞれの命令分類(OPIVV, OPIVX, ... など)は別の表で命令エンコーディングの定義がなされている。
- 整数ベクトル命令1
OPIVVOPIVXOPIVI
- 整数ベクトル命令2
OPMVVOPMVX
- 浮動小数点ベクトル命令
OPFVVOPFVF
それぞれの命令フォーマットは以下のように定義されている。
Formats for Vector Arithmetic Instructions under OP-V major opcode
31 26 25 24 20 19 15 14 12 11 7 6 0
funct6 | vm | vs2 | vs1 | 0 0 0 | vd |1010111| OP-V (OPIVV)
funct6 | vm | vs2 | vs1 | 0 0 1 | vd/rd |1010111| OP-V (OPFVV)
funct6 | vm | vs2 | vs1 | 0 1 0 | vd/rd |1010111| OP-V (OPMVV)
funct6 | vm | vs2 | simm5 | 0 1 1 | vd |1010111| OP-V (OPIVI)
funct6 | vm | vs2 | rs1 | 1 0 0 | vd |1010111| OP-V (OPIVX)
funct6 | vm | vs2 | rs1 | 1 0 1 | vd |1010111| OP-V (OPFVF)
funct6 | vm | vs2 | rs1 | 1 1 0 | vd/rd |1010111| OP-V (OPMVX)
6 1 5 5 3 5 7
つまり、命令のエンコーディングとしては以下の手順を取ることになる。
- まずは
opcode[6:0]でベクトル命令であることを認識する。 funct3でベクトル命令を7種類に分類する。funct6で命令を分類する。
さらに、もう一つ大きな分類として25ビット目にvmというビットが定義されている。vmビットによってベクトルレジスタに対してマスクを適用するかを決定する。
さて、もう一度命令一覧表に戻ってみると3種類の分類(OPIVV, OPIVV, OPIVIとOPMVV, OPMVXとOPFVV, OPFVF)によって命令が定義されていることが分かる。

たとえばvadd命令だとV, X, Iの場合はOPIVV, OPIVX, OPIVIの3種類にチェックが付いているので、3種類の命令フォーマットが定義可能だ。
# 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
一方でvsub命令はVとXつまりOPIVV, OPIVXのフォーマットが定義可能である。
# Integer subtract vsub.vv vd, vs2, vs1, vm # Vector-vector vsub.vx vd, vs2, rs1, vm # vector-scalar
さらに、vrsub命令はXとIつまりOPIVX, OPIVIのフォーマットが定義可能である。
# 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]
これらをベクトル命令の一覧表をまとめた。命令の分類とfunct[5:4]で表を作った。
