FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

gem5のベクトル・レジスタファイルの構成を調べる

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の実装(まだ本流にマージされていないもの)の実装を調査する:

github.com

同様に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;