This patch adds emulation for the conditional branch (b.cond) instruction. Signed-off-by: Alexander Graf <ag...@suse.de> --- target-arm/helper-a64.c | 41 +++++++++++++++++++++++++++++++++++++++++ target-arm/helper-a64.h | 1 + target-arm/translate-a64.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+)
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c index bc575a2..9aaf181 100644 --- a/target-arm/helper-a64.c +++ b/target-arm/helper-a64.c @@ -146,3 +146,44 @@ uint64_t HELPER(sign_extend)(uint64_t x, uint64_t is_signed, uint64_t mask) return x; } + +uint32_t HELPER(cond)(uint32_t pstate, uint32_t cond) +{ + uint32_t r; + + switch (cond >> 1) { + case 0: + r = pstate & PSTATE_Z; + break; + case 1: + r = pstate & PSTATE_C; + break; + case 2: + r = pstate & PSTATE_N; + break; + case 3: + r = pstate & PSTATE_V; + break; + case 4: + r = (pstate & PSTATE_C) && !(pstate & PSTATE_Z); + break; + case 5: + r = (((pstate & PSTATE_N) ? 1 : 0) == ((pstate & PSTATE_V) ? 1 : 0)); + break; + case 6: + r = (((pstate & PSTATE_N) ? 1 : 0) == ((pstate & PSTATE_V) ? 1 : 0)) + && !(pstate & PSTATE_Z); + break; + case 7: + default: + /* ALWAYS */ + r = 1; + break; + } + + if ((cond & 1) && (cond != 0xf)) { + r = !r; + } + + return !!r; +} diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h index 7c5cdc6..99f4be7 100644 --- a/target-arm/helper-a64.h +++ b/target-arm/helper-a64.h @@ -22,3 +22,4 @@ DEF_HELPER_FLAGS_4(pstate_add32, TCG_CALL_NO_RWG_SE, i32, i32, i64, i64, i64) DEF_HELPER_FLAGS_4(pstate_sub, TCG_CALL_NO_RWG_SE, i32, i32, i64, i64, i64) DEF_HELPER_FLAGS_4(pstate_sub32, TCG_CALL_NO_RWG_SE, i32, i32, i64, i64, i64) DEF_HELPER_FLAGS_3(sign_extend, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) +DEF_HELPER_FLAGS_2(cond, TCG_CALL_NO_RWG_SE, i32, i32, i32) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 229b467..d5cc199 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -268,6 +268,32 @@ static void handle_cb(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_zero); } +static void handle_condb(DisasContext *s, uint32_t insn) +{ + uint64_t addr = s->pc - 4 + (get_sbits(insn, 5, 19) << 2); + int cond = get_bits(insn, 0, 4); + int no_match; + TCGv_i32 tcg_zero = tcg_const_i32(0); + TCGv_i32 tcg_cond = tcg_const_i32(cond); + TCGv_i32 tcg_condmatch = tcg_temp_new_i32(); + + no_match = gen_new_label(); + + gen_helper_cond(tcg_condmatch, pstate, tcg_cond); + tcg_gen_brcond_i32(TCG_COND_EQ, tcg_condmatch, tcg_zero, no_match); + + gen_goto_tb(s, 0, addr); + + gen_set_label(no_match); + gen_goto_tb(s, 1, s->pc); + + tcg_temp_free_i32(tcg_zero); + tcg_temp_free_i32(tcg_cond); + tcg_temp_free_i32(tcg_condmatch); + + s->is_jmp = DISAS_TB_JUMP; +} + static void ldst_do_vec_int(DisasContext *s, int freg_offs, TCGv_i64 tcg_addr, int size, bool is_store) { @@ -1743,6 +1769,8 @@ void disas_a64_insn(CPUARMState *env, DisasContext *s) handle_svc(s, insn); } else if (get_bits(insn, 29, 2) == 0x1) { handle_cb(s, insn); + } else if (get_bits(insn, 29, 3) == 0x2) { + handle_condb(s, insn); } else { unallocated_encoding(s); } -- 1.7.12.4