gem5の公式リポジトリにはRISC-VのRVV実装は入っていないのだが、ARMにおけるNEONやSVEのベクトル・レジスタの実装は入っている。 これをどのように実装するのかについて調査した。
SVEのベクトル・レジスタサイズを決めているのは以下のコードのようだ:
src/arch/arm/regs/vec.hh
// Number of VecElem per Vector Register considering only pre-SVE // Advanced SIMD registers. constexpr unsigned NumVecElemPerNeonVecReg = 4; // Number of VecElem per Vector Register, computed based on the vector length constexpr unsigned NumVecElemPerVecReg = MaxSveVecLenInWords;
MaxSveVecLenInWords
は、SVEで最大で指定できる値が使用されている。
src/arch/arm/types.hh
constexpr unsigned MaxSveVecLenInBits = 2048; static_assert(MaxSveVecLenInBits >= 128 && MaxSveVecLenInBits <= 2048 && MaxSveVecLenInBits % 128 == 0, "Unsupported max. SVE vector length"); constexpr unsigned MaxSveVecLenInBytes = MaxSveVecLenInBits >> 3; constexpr unsigned MaxSveVecLenInWords = MaxSveVecLenInBits >> 5; constexpr unsigned MaxSveVecLenInDWords = MaxSveVecLenInBits >> 6;
SVEの最大長までベクトル・レジスタを指定できるようになっている。
同様に、RISC-VのRVVの実装(まだ本流にマージされていないもの)の実装を調査する:
同様にRVVのレジスタ・ファイルが定義されているが、これはVLEN=256ビットに固定されているのかな?
src/arch/riscv/regs/vector.hh
constexpr unsigned ELEN = 64; constexpr unsigned VLEN = 256; constexpr unsigned VLENB = VLEN / 8;
この値は、完全に実装で固定されているので、変更しようとするとリコンパイルが必要になりそうだ。 これはどうにかならないものかなあ.... CPU側で定義して、コンフィグレーションで制御できるようにしたいのだけれども。
src/arch/riscv/isa/templates/vector_arith.isa
template<typename ElemType, typename IndexType> %(class_name)s<ElemType, IndexType>::%(class_name)s(ExtMachInst _machInst) : %(base_class)s("%(mnemonic)s", _machInst, %(op_class)s) { %(set_reg_idx_arr)s; %(constructor)s; constexpr uint32_t vd_eewb = sizeof(ElemType); constexpr uint32_t vs2_eewb = sizeof(ElemType); constexpr uint32_t vs1_eewb = sizeof(IndexType); constexpr bool vs1_split = vd_eewb > vs1_eewb; const int8_t lmul = vtype_vlmul(vtype); const int8_t vs1_emul = lmul + (vs1_split ? -(vs2_eewb / vs1_eewb) : vs1_eewb / vs2_eewb); const uint8_t vs2_vregs = lmul < 0 ? 1 : 1 << lmul; const uint8_t vs1_vregs = vs1_emul < 0 ? 1 : 1 << vs1_emul; const uint8_t vd_vregs = vs2_vregs; const int32_t micro_vlmax = VLENB / std::max(vd_eewb, vs1_eewb); int32_t remaining_vl = this->vl; int32_t micro_vl = std::min(remaining_vl, micro_vlmax); StaticInstPtr microop;