This adds handling for the b and bl instructions. Signed-off-by: Alexander Graf <ag...@suse.de> --- target-arm/translate-a64.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 73ccade..267fd4d 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -133,6 +133,58 @@ static void real_unallocated_encoding(DisasContext *s) real_unallocated_encoding(s); \ } while (0) +static int get_bits(uint32_t inst, int start, int len) +{ + return (inst >> start) & ((1 << len) - 1); +} + +static int get_sbits(uint32_t inst, int start, int len) +{ + int r = get_bits(inst, start, len); + if (r & (1 << (len - 1))) { + /* Extend the MSB 1 to the higher bits */ + r |= -1 & ~((1ULL << len) - 1); + } + return r; +} + +static TCGv_i64 cpu_reg(int reg) +{ + if (reg == 31) { + /* XXX leaks temps */ + return tcg_const_i64(0); + } else { + return cpu_X[reg]; + } +} + +static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) +{ + TranslationBlock *tb; + + tb = s->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + tcg_gen_goto_tb(n); + gen_a64_set_pc_im(dest); + tcg_gen_exit_tb((tcg_target_long)tb + n); + } else { + gen_a64_set_pc_im(dest); + tcg_gen_exit_tb(0); + } +} + +static void handle_b(DisasContext *s, uint32_t insn) +{ + uint64_t addr = s->pc - 4 + (get_sbits(insn, 0, 26) << 2); + + if (get_bits(insn, 31, 1)) { + /* BL */ + tcg_gen_movi_i64(cpu_reg(30), s->pc); + } + gen_goto_tb(s, 0, addr); + s->is_jmp = DISAS_TB_JUMP; +} + void disas_a64_insn(CPUARMState *env, DisasContext *s) { uint32_t insn; @@ -141,12 +193,21 @@ void disas_a64_insn(CPUARMState *env, DisasContext *s) s->insn = insn; s->pc += 4; + /* One-off branch instruction layout */ + switch (insn >> 26) { + case 0x25: + case 0x5: + handle_b(s, insn); + goto insn_done; + } + switch ((insn >> 24) & 0x1f) { default: unallocated_encoding(s); break; } +insn_done: if (unlikely(s->singlestep_enabled) && (s->is_jmp == DISAS_TB_JUMP)) { /* go through the main loop for single step */ s->is_jmp = DISAS_JUMP; -- 1.7.12.4