FPGA開発日記

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

RISC-V のCSR転送命令は何故即値をデコードしないのか?

RISC-Vのシステム系命令には、CSRRSI, CSRCIという命令が存在する。

http://riscv.org/spec/riscv-privileged-spec-v1.7.pdf

The CSRRWI, CSRRSI, and CSRRCI variants are similar to CSRRW, CSRRS, and CSRRC respectively,
except they update the CSR using an XLEN-bit value obtained by zero-extending a 5-bit
immediate (zimm[4:0]) field encoded in the rs1 field instead of a value from an integer register. If
the zimm[4:0] field is zero, then these instructions will not write to the CSR, and shall not cause
any of the side effects that might otherwise occur on a CSR write.

つまり、zimm[4:0]のフィールドでどのCSRの値を更新するかを決定し、CSR値を更新する。 これだけ見れば、実装はこうなる。

void RISCV_INST_CSRRSI (uint32_t inst_hex, riscvEnv env)
{
    RegAddr_t rd_addr   = ExtractRDField (inst_hex);
    Word_t    csr_addr  = ExtractBitField (inst_hex, 31, 20);
    Word_t    bit_index = ExtractBitField (inst_hex, 19, 15);

    Word_t  csr_val  = CSRRead (csr_addr, env);

    if (bit_index != 0) {
        Word_t z_imm  = (1 << bit_index) | csr_val;
        CSRWrite (csr_addr, z_imm, env);
    }
    GRegWrite (rd_addr, csr_val, env);
}

つまり、bit_indexでzimm[4:0]をデコードし、どのビットに1を書き込むかを決定させる。この時点で書き込めるのは1ビットだけだが、それでも32ビットモードの場合は全てのフィールドを書き込むことができるので便利だと思っていた。

ところが、実際に上記の実装でriscv-testsのパタンを流してみるとFailとなる。何故だろうと思ってMLでも聞いてみると、実はbit_indexはインデックスではないらしい!

void RISCV_INST_CSRRSI (uint32_t inst_hex, riscvEnv env)
{
    RegAddr_t rd_addr   = ExtractRDField (inst_hex);
    Word_t    csr_addr  = ExtractBitField (inst_hex, 31, 20);
    Word_t    bit_index = ExtractBitField (inst_hex, 19, 15);

    Word_t  csr_val  = CSRRead (csr_addr, env);

    if (bit_index != 0) {
        Word_t z_imm  = bit_index| csr_val;
        CSRWrite (csr_addr, bit_index, env);
    }
    GRegWrite (rd_addr, csr_val, env);
}

デコードしてないじゃん!さらに、これだと理屈上でも下位5ビットしか書き込めない。 この5ビットしか書き込めない命令って、何か意味あるの?使いどころが無ければ、除去してもいいんじゃない?

っていうことを、RISC-Vのチームに質問している。彼らはどういう理由でこの命令を追加したんだろうね?