|
@@ -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)
|
|
static void unallocated_encoding(DisasContext *s)
|
|
{
|
|
{
|
|
/* Unallocated and reserved encodings are uncategorized */
|
|
/* 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.
|
|
* Store from GPR register to memory.
|
|
*/
|
|
*/
|
|
static void do_gpr_st_memidx(DisasContext *s, TCGv_i64 source,
|
|
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);
|
|
g_assert(size <= 3);
|
|
tcg_gen_qemu_st_i64(source, tcg_addr, memidx, s->be_data + size);
|
|
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,
|
|
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
|
|
* 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;
|
|
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);
|
|
g_assert(size < 3);
|
|
tcg_gen_ext32u_i64(dest, dest);
|
|
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,
|
|
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
|
|
#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
|
|
/* C3.3.6 Load/store exclusive
|
|
*
|
|
*
|
|
* 31 30 29 24 23 22 21 20 16 15 14 10 9 5 4 0
|
|
* 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 {
|
|
} else {
|
|
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
|
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) {
|
|
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 {
|
|
} 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) {
|
|
if (is_vector) {
|
|
do_fp_ld(s, rt, tcg_addr, size);
|
|
do_fp_ld(s, rt, tcg_addr, size);
|
|
} else {
|
|
} 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);
|
|
tcg_temp_free_i64(tcg_addr);
|
|
}
|
|
}
|
|
@@ -2042,9 +2122,11 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
|
|
} else {
|
|
} else {
|
|
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
|
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
|
if (is_load) {
|
|
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 {
|
|
} 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);
|
|
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 {
|
|
} else {
|
|
TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
|
|
TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
|
|
if (is_load) {
|
|
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 {
|
|
} 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_store = false;
|
|
bool is_extended = false;
|
|
bool is_extended = false;
|
|
bool is_unpriv = (idx == 2);
|
|
bool is_unpriv = (idx == 2);
|
|
|
|
+ bool iss_valid = !is_vector;
|
|
bool post_index;
|
|
bool post_index;
|
|
bool writeback;
|
|
bool writeback;
|
|
|
|
|
|
@@ -2169,12 +2254,15 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
|
|
} else {
|
|
} else {
|
|
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
|
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
|
int memidx = is_unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
|
|
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) {
|
|
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 {
|
|
} else {
|
|
do_gpr_ld_memidx(s, tcg_rt, tcg_addr, size,
|
|
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 {
|
|
} else {
|
|
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
|
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
|
|
|
+ bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
|
|
if (is_store) {
|
|
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 {
|
|
} 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 {
|
|
} else {
|
|
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
|
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
|
|
|
+ bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
|
|
if (is_store) {
|
|
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 {
|
|
} 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();
|
|
tcg_clear_temp_count();
|
|
|
|
|
|
do {
|
|
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++;
|
|
num_insns++;
|
|
|
|
|
|
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
|
|
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
|