RISC-Vのオープンソースベクトル実装のリファレンスとしてAraというものが公開されている。
ベクトル実装のポイントとして、複数のデータサイズに対して1つのデータパスで対応しなければならないというのがあるのだが、これがどのように実装されているのかを確認した。
まず一番基本となるVMV.V.X
の実装などを確認したかったのだが、これはVMERGE
命令に結合されているので、その辺の実装を確認していく。
まず、VMERGEのデータパスを確認した。
// Merge instructions VMERGE: unique case (vew_i) EW8 : for (int b = 0; b < 8; b++) res.w8 [b] = mask_i[1*b] ? opa.w8 [b] : opb.w8 [b]; EW16: for (int b = 0; b < 4; b++) res.w16[b] = mask_i[2*b] ? opa.w16[b] : opb.w16[b]; EW32: for (int b = 0; b < 2; b++) res.w32[b] = mask_i[4*b] ? opa.w32[b] : opb.w32[b]; EW64: for (int b = 0; b < 1; b++) res.w64[b] = mask_i[8*b] ? opa.w64[b] : opb.w64[b]; endcase
データサイズに応じてそれぞれデータパスが定義されているのか。なるほど。オペランドは以下のようなデータとして定義されている。
typedef union packed { logic [0:0][63:0] w64; logic [1:0][31:0] w32; logic [3:0][15:0] w16; logic [7:0][ 7:0] w8; } alu_operand_t; alu_operand_t opa, opb, res;
なるほど、union
でそれぞれのデータサイズを表現するように定義されているのか。
それでもって、データサイズの大きさは最大で64-bitになっており、これをレーンで接続するようになっている。
ちなみに、ベクトル命令のデコーダは非常にベタにデコーダ内に書いてあった。
6'b010111: begin ara_req_d.op = ara_pkg::VMERGE; ara_req_d.use_vs2 = !insn.varith_type.vm; // vmv.v.v does not use vs2 // With a normal vmv.v.v, copy input eew to output // to avoid unnecessary reshuffles if (insn.varith_type.vm) begin ara_req_d.eew_vs1 = eew_q[ara_req_d.vs1]; ara_req_d.vtype.vsew = eew_q[ara_req_d.vs1]; ara_req_d.vl = (vl_q << vtype_q.vsew[1:0]) >> ara_req_d.eew_vs1[1:0]; end end