RISC-Vのベクトル命令について勉強している。ベクトル拡張の仕様はv0.8をベースにしている。命令のエンコーディングについて調べているが、理解に時間がかかっているのでまとめてみる。
公式の仕様書には、以下のようなエンコーディングのリストが載っているが、何が何だか分からない。
まず、この表について理解する必要がある。この表はfunct3
のエンコーディングによって複数の命令の分類があることを示している。そしてそれぞれの命令分類(OPIVV
, OPIVX
, ... など)は別の表で命令エンコーディングの定義がなされている。
- 整数ベクトル命令1
OPIVV
OPIVX
OPIVI
- 整数ベクトル命令2
OPMVV
OPMVX
- 浮動小数点ベクトル命令
OPFVV
OPFVF
それぞれの命令フォーマットは以下のように定義されている。
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]
で表を作った。