FPGA開発日記

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

Binary Translation型エミュレータを作る(ジャンプ命令の修正)

Binary Translation型のエミュレータを開発している。変数の定義方法抜本的に作り直したので、命令の生成方法を修正している。ロードストア命令については修正が完了したので、次はジャンプ命令などの修正を行っていく。

JALR命令

JALR命令は書き込みレジスタx0が指定してあるかどうかで動作を変える。

    pub fn translate_jalr(&mut self, inst: &InstrInfo) -> Vec<TCGOp> {
        let rs1_addr = get_rs1_addr!(inst.inst);
        let imm_const: u64 = ((inst.inst as i32) >> 20) as u64;
        let rd_addr  = get_rd_addr!(inst.inst);

        let mut tcg_lists = vec![];

        let source1 = self.tcg_temp_new();
        let dest = self.tcg_temp_new();
        tcg_lists.push(TCGOp::tcg_get_gpr(source1, rs1_addr));

        let imm = TCGv::new_imm(imm_const);

        if rd_addr != 0 {
            let zero = self.tcg_temp_new();
            tcg_lists.push(TCGOp::tcg_get_gpr(zero, 0));
            let next_pc = TCGv::new_imm((inst.addr as u64).wrapping_add(4));
            tcg_lists.push(TCGOp::new_2op(TCGOpcode::MOV_IMM_64BIT, dest, next_pc));
            self.tcg_temp_free(zero);
            tcg_lists.push(TCGOp::tcg_set_gpr(rd_addr, dest));
        }
        tcg_lists.push(TCGOp::new_3op(TCGOpcode::JMPR, dest, source1, imm));
        tcg_lists.push(TCGOp::new_0op(TCGOpcode::EXIT_TB, None));

        self.tcg_temp_free(source1);
        self.tcg_temp_free(dest);

        tcg_lists
    }

JMPRTCGは、PCにimmで指定してある値を設定するTCGである。x86側の命令生成は以下の通りとなる。

    fn tcg_gen_jmpr(emu: &EmuEnv, pc_address: u64, tcg: &TCGOp, mc: &mut Vec<u8>) -> usize {
        let op = tcg.op.unwrap();
        let dest = tcg.arg0.unwrap();
        let src1 = tcg.arg1.unwrap();
        let src2 = tcg.arg2.unwrap();

        assert_eq!(dest.t, TCGvType::TCGTemp);
        assert_eq!(src1.t, TCGvType::TCGTemp);
        assert_eq!(src2.t, TCGvType::Immediate);
        assert_eq!(op, TCGOpcode::JMPR);

        let mut gen_size: usize = pc_address as usize;

        let src1_x86reg = Self::convert_x86_reg(src1.value);

        gen_size += Self::tcg_modrm_64bit_raw_out(X86Opcode::MOV_GV_EV, X86ModRM::MOD_11_DISP_RAX as u8 + src1_x86reg as u8, X86TargetRM::RAX as u8, mc);
        gen_size += Self::tcg_64bit_out(X86Opcode::ADD_EAX_IV, mc);
        gen_size += Self::tcg_out(src2.value as u64, 4, mc);
        // RAX --> PC
        gen_size += Self::tcg_modrm_64bit_out(X86Opcode::MOV_EV_GV, X86ModRM::MOD_10_DISP_RBP, X86TargetRM::RAX, mc);
        gen_size += Self::tcg_out(emu.calc_pc_address() as u64, 4, mc); // Set Program Counter

        return gen_size;
    }

JALR命令で生成されるx86命令は以下のようになる。

00007FE701EC0000 488B9538000000       mov       0x38(%rbp),%rdx
00007FE701EC0007 488B8D08000000       mov       8(%rbp),%rcx
00007FE701EC000E 48B81001008000000000 movabs    $0x8000_0110,%rax
00007FE701EC0018 488BD8               mov       %rax,%rbx
00007FE701EC001B 48899D30000000       mov       %rbx,0x30(%rbp)
00007FE701EC0022 488BC2               mov       %rdx,%rax
00007FE701EC0025 480500000000         add       $0,%rax
00007FE701EC002B 48898508020000       mov       %rax,0x208(%rbp)
00007FE701EC0032 E9D8FF2600           jmp       0x0000_7FE7_0213_000F

JAL命令

JAL命令は以下のようなTCG列で命令を生成する。

    pub fn translate_jal(&mut self, inst: &InstrInfo) -> Vec<TCGOp> {
        let imm_const = extract_j_field!(inst.inst);
        let rd_addr = get_rd_addr!(inst.inst);

        let imm_const = ((imm_const as i32) << (32 - 21)) >> (32 - 21);
        let imm = TCGv::new_imm(((imm_const as i64).wrapping_add(inst.addr as i64)) as u64);

        let mut tcg_lists = vec![];

        let dest_temp = self.tcg_temp_new();
        let next_pc = TCGv::new_imm(inst.addr.wrapping_add(4));
        if rd_addr != 0 {
            tcg_lists.push(TCGOp::new_2op(TCGOpcode::MOV_IMM_64BIT, dest_temp, next_pc));
            tcg_lists.push(TCGOp::tcg_set_gpr(rd_addr, dest_temp));
        }
        tcg_lists.push(TCGOp::new_2op(TCGOpcode::JMPIM, dest_temp, imm));
        tcg_lists.push(TCGOp::new_0op(TCGOpcode::EXIT_TB, None));
        self.tcg_temp_free(dest_temp);

        tcg_lists
    }

以下のようなx86命令に変換される。

00007FE872DA0000 48B80801008000000000 movabs    $0x8000_0108,%rax
00007FE872DA000A 488BD0               mov       %rax,%rdx
00007FE872DA000D 48899528000000       mov       %rdx,0x28(%rbp)
00007FE872DA0014 48B81401008000000000 movabs    $0x8000_0114,%rax
00007FE872DA001E 48898508020000       mov       %rax,0x208(%rbp)
00007FE872DA0025 E9E5FF2400           jmp       0x0000_7FE8_72FF_000F