aboutsummaryrefslogtreecommitdiff
path: root/target-arm/translate-a64.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-arm/translate-a64.c')
-rw-r--r--target-arm/translate-a64.c140
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))) {