QEMUの続き。独自ターゲットでビルドしてみる。前回の続き
trans_xxx()
の関数がみんな消えてしまったのはおそらく最適化で消されたので、一応念のためDebugビルドしてオブジェクトをダンプしてみた。
$ ../configure --enable-debug --disable-pie --target-list=myriscvx64-softmmu,riscv64-softmmu $ make
$ objdump -d ./riscv64-softmmu/target/riscv/translate.o | grep "<trans_.*>:"
000000000000709f <trans_illegal>: 00000000000070c2 <trans_lui>: 0000000000007109 <trans_auipc>: 000000000000715e <trans_jal>: ... 000000000000c25f <trans_wfi>: 000000000000c272 <trans_sfence_vma>: 000000000000c285 <trans_sfence_vm>: 000000000000c298 <trans_hfence_gvma>: 000000000000c2ab <trans_hfence_bvma>:
例えば<trans_add>
はどのようになっているのか。
0000000000007b2d <trans_add>: 7b2d: 55 push %rbp 7b2e: 48 89 e5 mov %rsp,%rbp 7b31: 48 83 ec 10 sub $0x10,%rsp 7b35: 48 89 7d f8 mov %rdi,-0x8(%rbp) 7b39: 48 89 75 f0 mov %rsi,-0x10(%rbp) 7b3d: 48 8b 4d f0 mov -0x10(%rbp),%rcx 7b41: 48 8b 45 f8 mov -0x8(%rbp),%rax 7b45: ba 00 00 00 00 mov $0x0,%edx 7b4a: 48 89 ce mov %rcx,%rsi 7b4d: 48 89 c7 mov %rax,%rdi 7b50: e8 02 f4 ff ff callq 6f57 <gen_arith> 7b55: c9 leaveq 7b56: c3 retq
なんかすべてがテンプレート関数に飛ばされているような気がする。
qemu/target/riscv/insn_trans/trans_rvi.inc.c
static bool trans_add(DisasContext *ctx, arg_add *a) { return gen_arith(ctx, a, &tcg_gen_add_tl); }
このgen_arith
もRISC-V向けに実装しなければならないものらしい。
qemu/target/riscv/translate.c
static bool gen_arith(DisasContext *ctx, arg_r *a, void(*func)(TCGv, TCGv, TCGv)) { TCGv source1, source2; source1 = tcg_temp_new(); source2 = tcg_temp_new(); gen_get_gpr(source1, a->rs1); gen_get_gpr(source2, a->rs2); (*func)(source1, source1, source2); gen_set_gpr(a->rd, source1); tcg_temp_free(source1); tcg_temp_free(source2); return true; }
なるほど、このtcg_gen_xxx
というのがTiny Code Generatorの意味で、加算の機能を持っているのだろうか?
qemu/include/tcg/tcg-op.h
#if TARGET_LONG_BITS == 64 ... #define tcg_gen_addi_tl tcg_gen_addi_i64
qemu/include/tcg/tcg-op.h
static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { tcg_gen_op3_i64(INDEX_op_add_i64, ret, arg1, arg2); }
次にロード命令について見ておく。
qemu/target/riscv/insn_trans/trans_rvi.inc.c
static bool trans_lw(DisasContext *ctx, arg_lw *a) { return gen_load(ctx, a, MO_TESL); }
qemu/target/riscv/insn_trans/trans_rvi.inc.c
static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop) { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); gen_get_gpr(t0, a->rs1); tcg_gen_addi_tl(t0, t0, a->imm); tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, memop); gen_set_gpr(a->rd, t1); tcg_temp_free(t0); tcg_temp_free(t1); return true; }
このMO_TESL
とかの定義が良く分からんなあ。
qemu/include/exec/memop.h
#ifdef NEED_CPU_H MO_TEUW = MO_TE | MO_UW, MO_TEUL = MO_TE | MO_UL, MO_TESW = MO_TE | MO_SW, MO_TESL = MO_TE | MO_SL, MO_TEQ = MO_TE | MO_Q, #endif
MO_TE
はエンディアンだと思う。MO_UW, MO_UL, MO_SW, MO_SL, MO_Q
はオペレーションかな?