SniperのRISC-V向けデコーダは結構古いものが使われているので、 riscv-opcodes (https://github.com/riscv/riscv-opcodes) を使ってデコーダを最新版に更新することを考える。
まず、riscv-opcodes をダウンロードする。
if [ ! -d "$NEW_OPCODES_DIR" ]; then
echo "Error: Latest riscv-opcodes not found"
echo "Please fetch it with:"
echo " cd $RISCV_DIR && git clone https://github.com/riscv/riscv-opcodes.git riscv-opcodes-latest"
exit 1
fi
ターゲットとなる命令拡張をもとに、Sniper用のopcodesを作っていく。最初はrv8のフォーマットに準じながらデコーダを作ろうかと考えたが、それは無駄な気がしてきたので、riscv-opcodeから直接デコーダを作る方法を探ることにした。
- riscv-opcodes (公式定義)
- generate_decoder.py (変換スクリプト)
- riscv_decoder_generated.h (生成ヘッダ)
- riscv_decoder_simple.{h,cc} (デコーダ実装)
1. 生成スクリプト
生成スクリプトによって、riscv-opcodeから必要な情報を抽出していく。
#!/usr/bin/env python3 """ RISC-V Decoder Header Generator riscv-opcodesからRISC-Vデコーダヘッダーを直接生成 """ def classify_instruction(name): """命令を分類""" if name.startswith(('beq', 'bne', 'blt', 'bge')): return 'branch' elif name.startswith(('jal', 'jalr')): return 'jump' elif name.startswith(('lb', 'lh', 'lw', 'ld')): return 'load' # ... その他の分類
2. 生成されるデータ構造
抽出した情報をもとに、 riscv_decoder_generated.h を吐き出す。
decode構造体
namespace riscv { struct decode { int32_t imm; // 即値 uint8_t rd; // デスティネーションレジスタ uint8_t rs1; // ソースレジスタ1 uint8_t rs2; // ソースレジスタ2 uint8_t rs3; // ソースレジスタ3 uint16_t op : 10; // オペレーション uint16_t codec : 6; // コーデック uint8_t rm : 3; // 丸めモード uint8_t aq : 1; // acquire uint8_t rl : 1; // release uint8_t pred : 4; // fence predecessor uint8_t succ : 4; // fence successor }; }
命令enum
enum rv_op { rv_op_illegal = 0, rv_op_beq = 1, // branch rv_op_bne = 2, // branch rv_op_add = 20, // alu rv_op_c_addi = 204, // compressed // ... };
3. デコーダ実装
riscv_decoder_generated.h をもとに、Sniper向けのRISC-Vデコーダのクラスを作成する。
class RISCVDecoderSimple : public Decoder { public: void decode(DecodedInst * inst) override { riscv::decode dec; riscv::inst_t r_inst; memcpy(&r_inst, inst->get_code(), 8); // 命令長判定 uint32_t inst_bits = r_inst & 0xFFFFFFFF; inst->get_size() = ((inst_bits & 0x3) != 0x3) ? 2 : 4; // デコード riscv::decode_inst_rv64(dec, r_inst); ((RISCVDecodedInstSimple *)inst)->set_decode(dec); } // その他の仮想関数実装... };
以下のようなコマンドで、riscv_decoder_generated.hを生成する。
# riscv-opcodesから直接生成
cat riscv/riscv-tools/riscv-opcodes/opcodes \\
riscv/riscv-tools/riscv-opcodes/opcodes-rvc | \\
python3 riscv/scripts/generate_decoder.py /dev/stdin \\
> decoder_lib/riscv_decoder_generated.h
RISC-Vの拡張を増やしたい場合、以下のようにしてターゲットとなるファイルの指定を増やす。
cat riscv/riscv-tools/riscv-opcodes/opcodes \\
riscv/riscv-tools/riscv-opcodes/opcodes-rvc \\
riscv/riscv-tools/riscv-opcodes/rv_zba \\
riscv/riscv-tools/riscv-opcodes/rv_zbb | \\
python3 riscv/scripts/generate_decoder.py /dev/stdin \\
> decoder_lib/riscv_decoder_generated.h
分類の関数は、さすがに自分で組まないといけないが…
def classify_instruction(name): # ...既存の分類... elif name.startswith(('andn', 'orn', 'clz', 'ctz')): return 'bitmanip' # ...