diff options
Diffstat (limited to 'target-arm/translate-a64.c')
-rw-r--r-- | target-arm/translate-a64.c | 140 |
1 files changed, 118 insertions, 22 deletions
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index ce8141a442..f5e29d20a1 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -308,6 +308,20 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) } } +static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) +{ + /* We don't need to save all of the syndrome so we mask and shift + * out uneeded bits to help the sleb128 encoder do a better job. + */ + syn &= ARM_INSN_START_WORD2_MASK; + syn >>= ARM_INSN_START_WORD2_SHIFT; + + /* We check and clear insn_start_idx to catch multiple updates. */ + assert(s->insn_start_idx != 0); + tcg_set_insn_param(s->insn_start_idx, 2, syn); + s->insn_start_idx = 0; +} + static void unallocated_encoding(DisasContext *s) { /* Unallocated and reserved encodings are uncategorized */ @@ -723,23 +737,47 @@ static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1) * Store from GPR register to memory. */ static void do_gpr_st_memidx(DisasContext *s, TCGv_i64 source, - TCGv_i64 tcg_addr, int size, int memidx) + TCGv_i64 tcg_addr, int size, int memidx, + bool iss_valid, + unsigned int iss_srt, + bool iss_sf, bool iss_ar) { g_assert(size <= 3); tcg_gen_qemu_st_i64(source, tcg_addr, memidx, s->be_data + size); + + if (iss_valid) { + uint32_t syn; + + syn = syn_data_abort_with_iss(0, + size, + false, + iss_srt, + iss_sf, + iss_ar, + 0, 0, 0, 0, 0, false); + disas_set_insn_syndrome(s, syn); + } } static void do_gpr_st(DisasContext *s, TCGv_i64 source, - TCGv_i64 tcg_addr, int size) + TCGv_i64 tcg_addr, int size, + bool iss_valid, + unsigned int iss_srt, + bool iss_sf, bool iss_ar) { - do_gpr_st_memidx(s, source, tcg_addr, size, get_mem_index(s)); + do_gpr_st_memidx(s, source, tcg_addr, size, get_mem_index(s), + iss_valid, iss_srt, iss_sf, iss_ar); } /* * Load from memory to GPR register */ -static void do_gpr_ld_memidx(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr, - int size, bool is_signed, bool extend, int memidx) +static void do_gpr_ld_memidx(DisasContext *s, + TCGv_i64 dest, TCGv_i64 tcg_addr, + int size, bool is_signed, + bool extend, int memidx, + bool iss_valid, unsigned int iss_srt, + bool iss_sf, bool iss_ar) { TCGMemOp memop = s->be_data + size; @@ -755,13 +793,30 @@ static void do_gpr_ld_memidx(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr, g_assert(size < 3); tcg_gen_ext32u_i64(dest, dest); } + + if (iss_valid) { + uint32_t syn; + + syn = syn_data_abort_with_iss(0, + size, + is_signed, + iss_srt, + iss_sf, + iss_ar, + 0, 0, 0, 0, 0, false); + disas_set_insn_syndrome(s, syn); + } } -static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr, - int size, bool is_signed, bool extend) +static void do_gpr_ld(DisasContext *s, + TCGv_i64 dest, TCGv_i64 tcg_addr, + int size, bool is_signed, bool extend, + bool iss_valid, unsigned int iss_srt, + bool iss_sf, bool iss_ar) { do_gpr_ld_memidx(s, dest, tcg_addr, size, is_signed, extend, - get_mem_index(s)); + get_mem_index(s), + iss_valid, iss_srt, iss_sf, iss_ar); } /* @@ -1817,6 +1872,22 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, } #endif +/* Update the Sixty-Four bit (SF) registersize. This logic is derived + * from the ARMv8 specs for LDR (Shared decode for all encodings). + */ +static bool disas_ldst_compute_iss_sf(int size, bool is_signed, int opc) +{ + int opc0 = extract32(opc, 0, 1); + int regsize; + + if (is_signed) { + regsize = opc0 ? 32 : 64; + } else { + regsize = size == 3 ? 64 : 32; + } + return regsize == 64; +} + /* C3.3.6 Load/store exclusive * * 31 30 29 24 23 22 21 20 16 15 14 10 9 5 4 0 @@ -1868,10 +1939,15 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) } } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); + bool iss_sf = disas_ldst_compute_iss_sf(size, false, 0); + + /* Generate ISS for non-exclusive accesses including LASR. */ if (is_store) { - do_gpr_st(s, tcg_rt, tcg_addr, size); + do_gpr_st(s, tcg_rt, tcg_addr, size, + true, rt, iss_sf, is_lasr); } else { - do_gpr_ld(s, tcg_rt, tcg_addr, size, false, false); + do_gpr_ld(s, tcg_rt, tcg_addr, size, false, false, + true, rt, iss_sf, is_lasr); } } } @@ -1923,7 +1999,11 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn) if (is_vector) { do_fp_ld(s, rt, tcg_addr, size); } else { - do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false); + /* Only unsigned 32bit loads target 32bit registers. */ + bool iss_sf = opc == 0 ? 32 : 64; + + do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false, + true, rt, iss_sf, false); } tcg_temp_free_i64(tcg_addr); } @@ -2042,9 +2122,11 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); if (is_load) { - do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false); + do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false, + false, 0, false, false); } else { - do_gpr_st(s, tcg_rt, tcg_addr, size); + do_gpr_st(s, tcg_rt, tcg_addr, size, + false, 0, false, false); } } tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size); @@ -2057,9 +2139,11 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) } else { TCGv_i64 tcg_rt2 = cpu_reg(s, rt2); if (is_load) { - do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false); + do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false, + false, 0, false, false); } else { - do_gpr_st(s, tcg_rt2, tcg_addr, size); + do_gpr_st(s, tcg_rt2, tcg_addr, size, + false, 0, false, false); } } @@ -2102,6 +2186,7 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, bool is_store = false; bool is_extended = false; bool is_unpriv = (idx == 2); + bool iss_valid = !is_vector; bool post_index; bool writeback; @@ -2169,12 +2254,15 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); int memidx = is_unpriv ? get_a64_user_mem_index(s) : get_mem_index(s); + bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc); if (is_store) { - do_gpr_st_memidx(s, tcg_rt, tcg_addr, size, memidx); + do_gpr_st_memidx(s, tcg_rt, tcg_addr, size, memidx, + iss_valid, rt, iss_sf, false); } else { do_gpr_ld_memidx(s, tcg_rt, tcg_addr, size, - is_signed, is_extended, memidx); + is_signed, is_extended, memidx, + iss_valid, rt, iss_sf, false); } } @@ -2272,10 +2360,14 @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn, } } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); + bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc); if (is_store) { - do_gpr_st(s, tcg_rt, tcg_addr, size); + do_gpr_st(s, tcg_rt, tcg_addr, size, + true, rt, iss_sf, false); } else { - do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended); + do_gpr_ld(s, tcg_rt, tcg_addr, size, + is_signed, is_extended, + true, rt, iss_sf, false); } } } @@ -2352,10 +2444,13 @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn, } } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); + bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc); if (is_store) { - do_gpr_st(s, tcg_rt, tcg_addr, size); + do_gpr_st(s, tcg_rt, tcg_addr, size, + true, rt, iss_sf, false); } else { - do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended); + do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended, + true, rt, iss_sf, false); } } } @@ -11102,7 +11197,8 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb) tcg_clear_temp_count(); do { - tcg_gen_insn_start(dc->pc, 0); + dc->insn_start_idx = tcg_op_buf_count(); + tcg_gen_insn_start(dc->pc, 0, 0); num_insns++; if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { |