rv8はRISC-VのシミュレータやJITの機能を持つ豊富なツール群だ。命令デコーダも搭載されており、Sniperもrv8のデコーダ機能を使って命令デコードを行っている。
が、実はこの機能が少しややこしい。正しく命令追加をしようとすると、rv8の中に仕込まれているmetaのフォーマットを理解する必要があり詰まっていた。 最近改めて読み直すとその意味が理解できて来たので、調整を行っていく。
まず、命令のオペコードを示すopecodes
を参照したとき、codecというものを理解する必要がある。
これは命令フォーマット時にどの命令フォーマットを使用するかというもので、例えばロード命令とストア命令のフォーマットは異なる。
lb rd rs1 oimm12 14..12=0 6..2=0x00 1..0=3 i+l rv32i rv64i rv128i lh rd rs1 oimm12 14..12=1 6..2=0x00 1..0=3 i+l rv32i rv64i rv128i lw rd rs1 oimm12 14..12=2 6..2=0x00 1..0=3 i+l rv32i rv64i rv128i lbu rd rs1 oimm12 14..12=4 6..2=0x00 1..0=3 i+l rv32i rv64i rv128i lhu rd rs1 oimm12 14..12=5 6..2=0x00 1..0=3 i+l rv32i rv64i rv128i sb rs1 rs2 simm12 14..12=0 6..2=0x08 1..0=3 s rv32i rv64i rv128i sh rs1 rs2 simm12 14..12=1 6..2=0x08 1..0=3 s rv32i rv64i rv128i sw rs1 rs2 simm12 14..12=2 6..2=0x08 1..0=3 s rv32i rv64i rv128i
このi+l
とかs
とかがコーデックを示すもので、とりあえず+l
はおいておいてi
とかs
とかが意味することは、どのような命令フォーマットで命令を成形し、どのオペランdおを使用するか、ということを示している。
codecs
i rd,rs1,imm rd rs1 imm12 s rs2,offset(rs1) rs1 rs2 simm12
さらにややこしいのが、このcodecは+
もしくは·
(. = ドットではないので注意!) でバリエーションを持つことができる。
+
は本質は変えずに表現方法のみを変える。·
はデコードの方式も変えてしまう。
例えば、i
とi·sh5
は本質的に何が違うのかというと、decode()
やり方が変わる。
/* Decode I */ template <typename T> inline void decode_i(T &dec, inst_t inst) { dec.rd = operand_rd::decode(inst); dec.rs1 = operand_rs1::decode(inst); dec.rs2 = rv_ireg_zero; dec.imm = operand_imm12::decode(inst); } /* Decode I sh5 */ template <typename T> inline void decode_i_sh5(T &dec, inst_t inst) { dec.rd = operand_rd::decode(inst); dec.rs1 = operand_rs1::decode(inst); dec.rs2 = rv_ireg_zero; dec.imm = operand_shamt5::decode(inst); }
というわけでデコーダの本質ができたところで、ベクトル命令のオペランド定義を変えていく。つまり、以下のようなデコードフォーマットを詰め込んでいく。
/* Decode Vector Unit-Stride Load */ template <typename T> inline void decode_i_lv(T &dec, inst_t inst) { dec.rd = operand_rd::decode(inst); dec.rs1 = operand_rs1::decode(inst); dec.rs2 = rv_ireg_zero; dec.imm = 0; } /* Decode Vector Unit-Stride Store */ template <typename T> inline void decode_s_v(T &dec, inst_t inst) { dec.rd = rv_ireg_zero; dec.rs1 = operand_rs1::decode(inst); dec.rs2 = rv_ireg_zero; dec.rs3 = operand_rd::decode(inst); dec.imm = 0; }
これで、とりあえず命令デコード情報がまともに表示できるようになった。