FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

QEMUに入門してみる(6. translateに必要な関数の確認)

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はオペレーションかな?