サイクル精度シミュレータSniperは、トレースファイルをベースとしたサイクル精度解析シミュレータだ。 RISC-Vのサポートにおいては、SpikeからSIFTファイルを生成し、それをSniperに加えることでサイクル計算を行う。 これだけだとSniper側にRISC-Vのデコード情報は必要ないように思われるが、実際にはSniper側にデコーダを用意し、それに基づいてサイクル計算のルーチンを動かす必要がある。
SniperのRISC-Vサポートにおいては、RV8のデコードエンジンが採用されている。
https://github.com/michaeljclark/rv8
これは基本命令とFPU命令は備わっているが、ベクトル命令は備わっていない。したがって、ベクトル命令サポートを追加する必要がある。
meta/opcodes
の改造
といっても、meta/opcodes
を直接編集してしまうと、生成される命令IDがずれてしまい面倒なので、別のファイルを用意してこちらにベクトル命令のオペコードを追加していく。
meta/vector_opcodes
# format of a line in this file: # <instruction name> [<args> ...] <opcode> <codec> <extension> # # <args> is one of rd, rs1, rs2, frd, frs1, frs2, frs3, imm20, imm12, # sbimm12, simm12, shamt5, shamt6, rm, aq, rl, pred, succ # # <opcode> is given by specifying one or more range/value pairs: # hi..lo=value or bit=value or arg=value (e.g. 6..2=0x45 10=1) # # <codec> is one of r, i, s, sb, u, uj, ... # # <extension> is one of { rv32, rv64, rv128 } \u00B7 { i, m, a, f, d, s, c } # RVV (actually its rvv but temporary assigned to F) # lumop = 24..20 vsetvli rd rs1 oimm12 31..31=0 14..12=7 6..2=21 1..0=3 i rv64v vsetivli rd imm12 oimm12 31..30=3 14..12=7 6..2=21 1..0=3 i+ii rv64v vsetvl rd rs1 rs2 31..25=64 14..12=7 6..2=21 1..0=3 r rv64v vle8.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=0 14..12=0 6..2=1 1..0=3 i+v rv64v vse8.v vs3 rs1 31..29=0 28..28=0 27..26=0 24..20=0 14..12=0 6..2=9 1..0=3 s+v rv64v vle16.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=0 14..12=5 6..2=1 1..0=3 i+v rv64v vse16.v vs3 rs1 31..29=0 28..28=0 27..26=0 24..20=0 14..12=5 6..2=9 1..0=3 s+v rv64v vle32.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=0 14..12=6 6..2=1 1..0=3 i+v rv64v vse32.v vs3 rs1 31..29=0 28..28=0 27..26=0 24..20=0 14..12=6 6..2=9 1..0=3 s+v rv64v vle64.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=0 14..12=7 6..2=1 1..0=3 i+v rv64v vse64.v vs3 rs1 31..29=0 28..28=0 27..26=0 24..20=0 14..12=7 6..2=9 1..0=3 s+v rv64v # Fault-only first load instruction vleff8.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=16 14..12=0 6..2=1 1..0=3 i+v rv64v vleff16.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=16 14..12=5 6..2=1 1..0=3 i+v rv64v vleff32.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=16 14..12=6 6..2=1 1..0=3 i+v rv64v vleff64.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=16 14..12=7 6..2=1 1..0=3 i+v rv64v # Whole Register load instruction vl1re8.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=8 14..12=0 6..2=1 1..0=3 i+v rv64v vl1re16.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=8 14..12=5 6..2=1 1..0=3 i+v rv64v vl1re32.v vd rs1 31..29=0 28..28=0 27..26=0 24..20=8 14..12=6 6..2=1 1..0=3 i+v rv64v
この情報から、src/asm/switch.h
というデコード関数が作られることになり、これがSniperのデコードエンジンに輸入される。
template <bool rv32, bool rv64, bool rv128, bool rvi, bool rvm, bool rva, bool rvs, bool rvf, bool rvd, bool rvq, bool rvc, bool rvv> inline opcode_t decode_inst_op(riscv::inst_t inst) { opcode_t op = rv_op_illegal; switch (((inst >> 0) & 0b11) /* inst[1:0] */) { case 0: // c.addi4spn c.fld c.lw c.flw c.fsd c.sw c.fsw c.ld c.sd c.lq c.sq switch (((inst >> 13) & 0b111) /* inst[15:13] */) { case 0: if (rvc) op = rv_op_c_addi4spn; break; case 1: if (rvc) op = rv_op_c_fld; break; // c.fld c.lq case 2: if (rvc) op = rv_op_c_lw; break; case 3: if (rvc && rv32) op = rv_op_c_flw; else if (rvc && rv64) op = rv_op_c_ld; break; case 5: if (rvc) op = rv_op_c_fsd; break; // c.fsd c.sq case 6: if (rvc) op = rv_op_c_sw; break; case 7: if (rvc && rv32) op = rv_op_c_fsw; else if (rvc && rv64) op = rv_op_c_sd; break; } break; case 1: // c.nop c.addi c.jal c.li c.addi16sp c.lui c.srli c.srai c.andi c.sub c.xor c.or ... switch (((inst >> 13) & 0b111) /* inst[15:13] */) { case 0: // c.nop c.addi switch (((inst >> 2) & 0b11111111111) /* inst[12:2] */) { case 0: if (rvc) op = rv_op_c_nop; break; default: if (rvc) op = rv_op_c_addi; break; } break;
meta/codec
の追加
上記のmeta/opcodes
では、i+v
などという記法が追加されているが、これはmeta/codecs
に定義されている。
meta/codecs
i+v vd,rs1 vd rs1 s+v vs3,rs1 vs3 rs1 i+vs vd,rs1,rs2 vd rs1 rs2 s+vs vs3,rs1,rs2 vs3 rs1 rs2 i+vv vd,vs2,vs1 vd vs2 vs1 i+vr vd,vs2,rs1 vd vs2 rs1 i+vi vd,vs2,simm5 vd vs2 simm5 i+v vd,vs2 vd vs2 i+ii rd,imm12,oimm12 rd imm12 oimm12
まあこの記法はよくわからないのだが、要するに命令毎のオペランドリストに対して固有のコーデックを記述するらしい。
それぞれのオペランドリスト形式については、meta/formats
に記述しておく。
meta/formats
# Vector vd,rs1 vs3,rs1 vd,rs1,rs2 vs3,rs1,rs2 vd,vs2,vs1 vd,vs2,rs1 vd,vs2,simm5 vd,vs2,simm5 vd,vs2 rd,imm12,oimm12
meta/registers
の追加
ベクトルレジスタを追加する。
v0 v0 vreg caller "Vector Registers" v1 v1 vreg caller "Vector Registers" v2 v2 vreg caller "Vector Registers" v3 v3 vreg caller "Vector Registers" v4 v4 vreg caller "Vector Registers" v5 v5 vreg caller "Vector Registers" v6 v6 vreg caller "Vector Registers" v7 v7 vreg caller "Vector Registers" v8 v8 vreg callee "Vector Registers" v9 v9 vreg callee "Vector Registers" v10 v10 vreg caller "Vector Registers" v11 v11 vreg caller "Vector Registers" v12 v12 vreg caller "Vector Registers" v13 v13 vreg caller "Vector Registers" v14 v14 vreg caller "Vector Registers" v15 v15 vreg caller "Vector Registers" v16 v16 vreg caller "Vector Registers" v17 v17 vreg caller "Vector Registers" v18 v18 vreg callee "Vector Registers" v19 v19 vreg callee "Vector Registers" v20 v20 vreg callee "Vector Registers" v21 v21 vreg callee "Vector Registers" v22 v22 vreg callee "Vector Registers" v23 v23 vreg callee "Vector Registers" v24 v24 vreg callee "Vector Registers" v25 v25 vreg callee "Vector Registers" v26 v26 vreg callee "Vector Registers" v27 v27 vreg callee "Vector Registers" v28 v28 vreg caller "Vector Registers" v29 v29 vreg caller "Vector Registers" v30 v30 vreg caller "Vector Registers" v31 v31 vreg caller "Vector Registers"
ここまでで、RV8に対する基本的な追加は完了となる。次は、Sniperに対してデコード情報を追加で記述していくことになる。