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のチームに質問している。彼らはどういう理由でこの命令を追加したんだろうね?