aboutsummaryrefslogtreecommitdiff
path: root/target/arm/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/translate.c')
-rw-r--r--target/arm/translate.c714
1 files changed, 49 insertions, 665 deletions
diff --git a/target/arm/translate.c b/target/arm/translate.c
index d4ad2028f1..025747c0bd 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -1313,8 +1313,9 @@ static TCGv_ptr vfp_reg_ptr(bool dp, int reg)
#define ARM_CP_RW_BIT (1 << 20)
-/* Include the VFP decoder */
+/* Include the VFP and Neon decoders */
#include "translate-vfp.inc.c"
+#include "translate-neon.inc.c"
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
{
@@ -2609,8 +2610,6 @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn)
}
#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n))
-#define VFP_SREG(insn, bigbit, smallbit) \
- ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1))
#define VFP_DREG(reg, insn, bigbit, smallbit) do { \
if (dc_isar_feature(aa32_simd_r32, s)) { \
reg = (((insn) >> (bigbit)) & 0x0f) \
@@ -2621,11 +2620,8 @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn)
reg = ((insn) >> (bigbit)) & 0x0f; \
}} while (0)
-#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22)
#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22)
-#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7)
#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7)
-#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5)
#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5)
static void gen_neon_dup_low16(TCGv_i32 var)
@@ -3217,274 +3213,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
tcg_temp_free_i32(rd);
}
-
-static struct {
- int nregs;
- int interleave;
- int spacing;
-} const neon_ls_element_type[11] = {
- {1, 4, 1},
- {1, 4, 2},
- {4, 1, 1},
- {2, 2, 2},
- {1, 3, 1},
- {1, 3, 2},
- {3, 1, 1},
- {1, 1, 1},
- {1, 2, 1},
- {1, 2, 2},
- {2, 1, 1}
-};
-
-/* Translate a NEON load/store element instruction. Return nonzero if the
- instruction is invalid. */
-static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
-{
- int rd, rn, rm;
- int op;
- int nregs;
- int interleave;
- int spacing;
- int stride;
- int size;
- int reg;
- int load;
- int n;
- int vec_size;
- int mmu_idx;
- MemOp endian;
- TCGv_i32 addr;
- TCGv_i32 tmp;
- TCGv_i32 tmp2;
- TCGv_i64 tmp64;
-
- /* FIXME: this access check should not take precedence over UNDEF
- * for invalid encodings; we will generate incorrect syndrome information
- * for attempts to execute invalid vfp/neon encodings with FP disabled.
- */
- if (s->fp_excp_el) {
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
- syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
- return 0;
- }
-
- if (!s->vfp_enabled)
- return 1;
- VFP_DREG_D(rd, insn);
- rn = (insn >> 16) & 0xf;
- rm = insn & 0xf;
- load = (insn & (1 << 21)) != 0;
- endian = s->be_data;
- mmu_idx = get_mem_index(s);
- if ((insn & (1 << 23)) == 0) {
- /* Load store all elements. */
- op = (insn >> 8) & 0xf;
- size = (insn >> 6) & 3;
- if (op > 10)
- return 1;
- /* Catch UNDEF cases for bad values of align field */
- switch (op & 0xc) {
- case 4:
- if (((insn >> 5) & 1) == 1) {
- return 1;
- }
- break;
- case 8:
- if (((insn >> 4) & 3) == 3) {
- return 1;
- }
- break;
- default:
- break;
- }
- nregs = neon_ls_element_type[op].nregs;
- interleave = neon_ls_element_type[op].interleave;
- spacing = neon_ls_element_type[op].spacing;
- if (size == 3 && (interleave | spacing) != 1) {
- return 1;
- }
- /* For our purposes, bytes are always little-endian. */
- if (size == 0) {
- endian = MO_LE;
- }
- /* Consecutive little-endian elements from a single register
- * can be promoted to a larger little-endian operation.
- */
- if (interleave == 1 && endian == MO_LE) {
- size = 3;
- }
- tmp64 = tcg_temp_new_i64();
- addr = tcg_temp_new_i32();
- tmp2 = tcg_const_i32(1 << size);
- load_reg_var(s, addr, rn);
- for (reg = 0; reg < nregs; reg++) {
- for (n = 0; n < 8 >> size; n++) {
- int xs;
- for (xs = 0; xs < interleave; xs++) {
- int tt = rd + reg + spacing * xs;
-
- if (load) {
- gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size);
- neon_store_element64(tt, n, size, tmp64);
- } else {
- neon_load_element64(tmp64, tt, n, size);
- gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size);
- }
- tcg_gen_add_i32(addr, addr, tmp2);
- }
- }
- }
- tcg_temp_free_i32(addr);
- tcg_temp_free_i32(tmp2);
- tcg_temp_free_i64(tmp64);
- stride = nregs * interleave * 8;
- } else {
- size = (insn >> 10) & 3;
- if (size == 3) {
- /* Load single element to all lanes. */
- int a = (insn >> 4) & 1;
- if (!load) {
- return 1;
- }
- size = (insn >> 6) & 3;
- nregs = ((insn >> 8) & 3) + 1;
-
- if (size == 3) {
- if (nregs != 4 || a == 0) {
- return 1;
- }
- /* For VLD4 size==3 a == 1 means 32 bits at 16 byte alignment */
- size = 2;
- }
- if (nregs == 1 && a == 1 && size == 0) {
- return 1;
- }
- if (nregs == 3 && a == 1) {
- return 1;
- }
- addr = tcg_temp_new_i32();
- load_reg_var(s, addr, rn);
-
- /* VLD1 to all lanes: bit 5 indicates how many Dregs to write.
- * VLD2/3/4 to all lanes: bit 5 indicates register stride.
- */
- stride = (insn & (1 << 5)) ? 2 : 1;
- vec_size = nregs == 1 ? stride * 8 : 8;
-
- tmp = tcg_temp_new_i32();
- for (reg = 0; reg < nregs; reg++) {
- gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
- s->be_data | size);
- if ((rd & 1) && vec_size == 16) {
- /* We cannot write 16 bytes at once because the
- * destination is unaligned.
- */
- tcg_gen_gvec_dup_i32(size, neon_reg_offset(rd, 0),
- 8, 8, tmp);
- tcg_gen_gvec_mov(0, neon_reg_offset(rd + 1, 0),
- neon_reg_offset(rd, 0), 8, 8);
- } else {
- tcg_gen_gvec_dup_i32(size, neon_reg_offset(rd, 0),
- vec_size, vec_size, tmp);
- }
- tcg_gen_addi_i32(addr, addr, 1 << size);
- rd += stride;
- }
- tcg_temp_free_i32(tmp);
- tcg_temp_free_i32(addr);
- stride = (1 << size) * nregs;
- } else {
- /* Single element. */
- int idx = (insn >> 4) & 0xf;
- int reg_idx;
- switch (size) {
- case 0:
- reg_idx = (insn >> 5) & 7;
- stride = 1;
- break;
- case 1:
- reg_idx = (insn >> 6) & 3;
- stride = (insn & (1 << 5)) ? 2 : 1;
- break;
- case 2:
- reg_idx = (insn >> 7) & 1;
- stride = (insn & (1 << 6)) ? 2 : 1;
- break;
- default:
- abort();
- }
- nregs = ((insn >> 8) & 3) + 1;
- /* Catch the UNDEF cases. This is unavoidably a bit messy. */
- switch (nregs) {
- case 1:
- if (((idx & (1 << size)) != 0) ||
- (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) {
- return 1;
- }
- break;
- case 3:
- if ((idx & 1) != 0) {
- return 1;
- }
- /* fall through */
- case 2:
- if (size == 2 && (idx & 2) != 0) {
- return 1;
- }
- break;
- case 4:
- if ((size == 2) && ((idx & 3) == 3)) {
- return 1;
- }
- break;
- default:
- abort();
- }
- if ((rd + stride * (nregs - 1)) > 31) {
- /* Attempts to write off the end of the register file
- * are UNPREDICTABLE; we choose to UNDEF because otherwise
- * the neon_load_reg() would write off the end of the array.
- */
- return 1;
- }
- tmp = tcg_temp_new_i32();
- addr = tcg_temp_new_i32();
- load_reg_var(s, addr, rn);
- for (reg = 0; reg < nregs; reg++) {
- if (load) {
- gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
- s->be_data | size);
- neon_store_element(rd, reg_idx, size, tmp);
- } else { /* Store */
- neon_load_element(tmp, rd, reg_idx, size);
- gen_aa32_st_i32(s, tmp, addr, get_mem_index(s),
- s->be_data | size);
- }
- rd += stride;
- tcg_gen_addi_i32(addr, addr, 1 << size);
- }
- tcg_temp_free_i32(addr);
- tcg_temp_free_i32(tmp);
- stride = nregs * (1 << size);
- }
- }
- if (rm != 15) {
- TCGv_i32 base;
-
- base = load_reg(s, rn);
- if (rm == 13) {
- tcg_gen_addi_i32(base, base, stride);
- } else {
- TCGv_i32 index;
- index = load_reg(s, rm);
- tcg_gen_add_i32(base, base, index);
- tcg_temp_free_i32(index);
- }
- store_reg(s, rn, base);
- }
- return 0;
-}
-
static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src)
{
switch (size) {
@@ -5002,6 +4730,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
TCGv_ptr ptr1, ptr2, ptr3;
TCGv_i64 tmp64;
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return 1;
+ }
+
/* FIXME: this access check should not take precedence over UNDEF
* for invalid encodings; we will generate incorrect syndrome information
* for attempts to execute invalid vfp/neon encodings with FP disabled.
@@ -5116,128 +4848,20 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
}
return 1;
- case NEON_3R_LOGIC: /* Logic ops. */
- switch ((u << 2) | size) {
- case 0: /* VAND */
- tcg_gen_gvec_and(0, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 1: /* VBIC */
- tcg_gen_gvec_andc(0, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 2: /* VORR */
- tcg_gen_gvec_or(0, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 3: /* VORN */
- tcg_gen_gvec_orc(0, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 4: /* VEOR */
- tcg_gen_gvec_xor(0, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 5: /* VBSL */
- tcg_gen_gvec_bitsel(MO_8, rd_ofs, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- break;
- case 6: /* VBIT */
- tcg_gen_gvec_bitsel(MO_8, rd_ofs, rm_ofs, rn_ofs, rd_ofs,
- vec_size, vec_size);
- break;
- case 7: /* VBIF */
- tcg_gen_gvec_bitsel(MO_8, rd_ofs, rm_ofs, rd_ofs, rn_ofs,
- vec_size, vec_size);
- break;
- }
- return 0;
-
case NEON_3R_VADD_VSUB:
- if (u) {
- tcg_gen_gvec_sub(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- } else {
- tcg_gen_gvec_add(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- }
- return 0;
-
- case NEON_3R_VQADD:
- tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc),
- rn_ofs, rm_ofs, vec_size, vec_size,
- (u ? uqadd_op : sqadd_op) + size);
- return 0;
-
- case NEON_3R_VQSUB:
- tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc),
- rn_ofs, rm_ofs, vec_size, vec_size,
- (u ? uqsub_op : sqsub_op) + size);
- return 0;
-
- case NEON_3R_VMUL: /* VMUL */
- if (u) {
- /* Polynomial case allows only P8. */
- if (size != 0) {
- return 1;
- }
- tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size,
- 0, gen_helper_gvec_pmul_b);
- } else {
- tcg_gen_gvec_mul(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- }
- return 0;
-
- case NEON_3R_VML: /* VMLA, VMLS */
- tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size,
- u ? &mls_op[size] : &mla_op[size]);
- return 0;
-
+ case NEON_3R_LOGIC:
+ case NEON_3R_VMAX:
+ case NEON_3R_VMIN:
case NEON_3R_VTST_VCEQ:
- if (u) { /* VCEQ */
- tcg_gen_gvec_cmp(TCG_COND_EQ, size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- } else { /* VTST */
- tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size, &cmtst_op[size]);
- }
- return 0;
-
case NEON_3R_VCGT:
- tcg_gen_gvec_cmp(u ? TCG_COND_GTU : TCG_COND_GT, size,
- rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size);
- return 0;
-
case NEON_3R_VCGE:
- tcg_gen_gvec_cmp(u ? TCG_COND_GEU : TCG_COND_GE, size,
- rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size);
- return 0;
-
- case NEON_3R_VMAX:
- if (u) {
- tcg_gen_gvec_umax(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- } else {
- tcg_gen_gvec_smax(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- }
- return 0;
- case NEON_3R_VMIN:
- if (u) {
- tcg_gen_gvec_umin(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- } else {
- tcg_gen_gvec_smin(size, rd_ofs, rn_ofs, rm_ofs,
- vec_size, vec_size);
- }
- return 0;
-
+ case NEON_3R_VQADD:
+ case NEON_3R_VQSUB:
+ case NEON_3R_VMUL:
+ case NEON_3R_VML:
case NEON_3R_VSHL:
- /* Note the operation is vshl vd,vm,vn */
- tcg_gen_gvec_3(rd_ofs, rm_ofs, rn_ofs, vec_size, vec_size,
- u ? &ushl_op[size] : &sshl_op[size]);
- return 0;
+ /* Already handled by decodetree */
+ return 1;
}
if (size == 3) {
@@ -6016,7 +5640,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
{0, 0, 0, 0}, /* VMLSL */
{0, 0, 0, 9}, /* VQDMLSL */
{0, 0, 0, 0}, /* Integer VMULL */
- {0, 0, 0, 1}, /* VQDMULL */
+ {0, 0, 0, 9}, /* VQDMULL */
{0, 0, 0, 0xa}, /* Polynomial VMULL */
{0, 0, 0, 7}, /* Reserved: always UNDEF */
};
@@ -7023,232 +6647,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
return 0;
}
-/* Advanced SIMD three registers of the same length extension.
- * 31 25 23 22 20 16 12 11 10 9 8 3 0
- * +---------------+-----+---+-----+----+----+---+----+---+----+---------+----+
- * | 1 1 1 1 1 1 0 | op1 | D | op2 | Vn | Vd | 1 | o3 | 0 | o4 | N Q M U | Vm |
- * +---------------+-----+---+-----+----+----+---+----+---+----+---------+----+
- */
-static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn)
-{
- gen_helper_gvec_3 *fn_gvec = NULL;
- gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL;
- int rd, rn, rm, opr_sz;
- int data = 0;
- int off_rn, off_rm;
- bool is_long = false, q = extract32(insn, 6, 1);
- bool ptr_is_env = false;
-
- if ((insn & 0xfe200f10) == 0xfc200800) {
- /* VCMLA -- 1111 110R R.1S .... .... 1000 ...0 .... */
- int size = extract32(insn, 20, 1);
- data = extract32(insn, 23, 2); /* rot */
- if (!dc_isar_feature(aa32_vcma, s)
- || (!size && !dc_isar_feature(aa32_fp16_arith, s))) {
- return 1;
- }
- fn_gvec_ptr = size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah;
- } else if ((insn & 0xfea00f10) == 0xfc800800) {
- /* VCADD -- 1111 110R 1.0S .... .... 1000 ...0 .... */
- int size = extract32(insn, 20, 1);
- data = extract32(insn, 24, 1); /* rot */
- if (!dc_isar_feature(aa32_vcma, s)
- || (!size && !dc_isar_feature(aa32_fp16_arith, s))) {
- return 1;
- }
- fn_gvec_ptr = size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh;
- } else if ((insn & 0xfeb00f00) == 0xfc200d00) {
- /* V[US]DOT -- 1111 1100 0.10 .... .... 1101 .Q.U .... */
- bool u = extract32(insn, 4, 1);
- if (!dc_isar_feature(aa32_dp, s)) {
- return 1;
- }
- fn_gvec = u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
- } else if ((insn & 0xff300f10) == 0xfc200810) {
- /* VFM[AS]L -- 1111 1100 S.10 .... .... 1000 .Q.1 .... */
- int is_s = extract32(insn, 23, 1);
- if (!dc_isar_feature(aa32_fhm, s)) {
- return 1;
- }
- is_long = true;
- data = is_s; /* is_2 == 0 */
- fn_gvec_ptr = gen_helper_gvec_fmlal_a32;
- ptr_is_env = true;
- } else {
- return 1;
- }
-
- VFP_DREG_D(rd, insn);
- if (rd & q) {
- return 1;
- }
- if (q || !is_long) {
- VFP_DREG_N(rn, insn);
- VFP_DREG_M(rm, insn);
- if ((rn | rm) & q & !is_long) {
- return 1;
- }
- off_rn = vfp_reg_offset(1, rn);
- off_rm = vfp_reg_offset(1, rm);
- } else {
- rn = VFP_SREG_N(insn);
- rm = VFP_SREG_M(insn);
- off_rn = vfp_reg_offset(0, rn);
- off_rm = vfp_reg_offset(0, rm);
- }
-
- if (s->fp_excp_el) {
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
- syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
- return 0;
- }
- if (!s->vfp_enabled) {
- return 1;
- }
-
- opr_sz = (1 + q) * 8;
- if (fn_gvec_ptr) {
- TCGv_ptr ptr;
- if (ptr_is_env) {
- ptr = cpu_env;
- } else {
- ptr = get_fpstatus_ptr(1);
- }
- tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, ptr,
- opr_sz, opr_sz, data, fn_gvec_ptr);
- if (!ptr_is_env) {
- tcg_temp_free_ptr(ptr);
- }
- } else {
- tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm,
- opr_sz, opr_sz, data, fn_gvec);
- }
- return 0;
-}
-
-/* Advanced SIMD two registers and a scalar extension.
- * 31 24 23 22 20 16 12 11 10 9 8 3 0
- * +-----------------+----+---+----+----+----+---+----+---+----+---------+----+
- * | 1 1 1 1 1 1 1 0 | o1 | D | o2 | Vn | Vd | 1 | o3 | 0 | o4 | N Q M U | Vm |
- * +-----------------+----+---+----+----+----+---+----+---+----+---------+----+
- *
- */
-
-static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn)
-{
- gen_helper_gvec_3 *fn_gvec = NULL;
- gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL;
- int rd, rn, rm, opr_sz, data;
- int off_rn, off_rm;
- bool is_long = false, q = extract32(insn, 6, 1);
- bool ptr_is_env = false;
-
- if ((insn & 0xff000f10) == 0xfe000800) {
- /* VCMLA (indexed) -- 1111 1110 S.RR .... .... 1000 ...0 .... */
- int rot = extract32(insn, 20, 2);
- int size = extract32(insn, 23, 1);
- int index;
-
- if (!dc_isar_feature(aa32_vcma, s)) {
- return 1;
- }
- if (size == 0) {
- if (!dc_isar_feature(aa32_fp16_arith, s)) {
- return 1;
- }
- /* For fp16, rm is just Vm, and index is M. */
- rm = extract32(insn, 0, 4);
- index = extract32(insn, 5, 1);
- } else {
- /* For fp32, rm is the usual M:Vm, and index is 0. */
- VFP_DREG_M(rm, insn);
- index = 0;
- }
- data = (index << 2) | rot;
- fn_gvec_ptr = (size ? gen_helper_gvec_fcmlas_idx
- : gen_helper_gvec_fcmlah_idx);
- } else if ((insn & 0xffb00f00) == 0xfe200d00) {
- /* V[US]DOT -- 1111 1110 0.10 .... .... 1101 .Q.U .... */
- int u = extract32(insn, 4, 1);
-
- if (!dc_isar_feature(aa32_dp, s)) {
- return 1;
- }
- fn_gvec = u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b;
- /* rm is just Vm, and index is M. */
- data = extract32(insn, 5, 1); /* index */
- rm = extract32(insn, 0, 4);
- } else if ((insn & 0xffa00f10) == 0xfe000810) {
- /* VFM[AS]L -- 1111 1110 0.0S .... .... 1000 .Q.1 .... */
- int is_s = extract32(insn, 20, 1);
- int vm20 = extract32(insn, 0, 3);
- int vm3 = extract32(insn, 3, 1);
- int m = extract32(insn, 5, 1);
- int index;
-
- if (!dc_isar_feature(aa32_fhm, s)) {
- return 1;
- }
- if (q) {
- rm = vm20;
- index = m * 2 + vm3;
- } else {
- rm = vm20 * 2 + m;
- index = vm3;
- }
- is_long = true;
- data = (index << 2) | is_s; /* is_2 == 0 */
- fn_gvec_ptr = gen_helper_gvec_fmlal_idx_a32;
- ptr_is_env = true;
- } else {
- return 1;
- }
-
- VFP_DREG_D(rd, insn);
- if (rd & q) {
- return 1;
- }
- if (q || !is_long) {
- VFP_DREG_N(rn, insn);
- if (rn & q & !is_long) {
- return 1;
- }
- off_rn = vfp_reg_offset(1, rn);
- off_rm = vfp_reg_offset(1, rm);
- } else {
- rn = VFP_SREG_N(insn);
- off_rn = vfp_reg_offset(0, rn);
- off_rm = vfp_reg_offset(0, rm);
- }
- if (s->fp_excp_el) {
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
- syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
- return 0;
- }
- if (!s->vfp_enabled) {
- return 1;
- }
-
- opr_sz = (1 + q) * 8;
- if (fn_gvec_ptr) {
- TCGv_ptr ptr;
- if (ptr_is_env) {
- ptr = cpu_env;
- } else {
- ptr = get_fpstatus_ptr(1);
- }
- tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, ptr,
- opr_sz, opr_sz, data, fn_gvec_ptr);
- if (!ptr_is_env) {
- tcg_temp_free_ptr(ptr);
- }
- } else {
- tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm,
- opr_sz, opr_sz, data, fn_gvec);
- }
- return 0;
-}
-
static int disas_coproc_insn(DisasContext *s, uint32_t insn)
{
int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
@@ -10941,33 +10339,21 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
/* Unconditional instructions. */
/* TODO: Perhaps merge these into one decodetree output file. */
if (disas_a32_uncond(s, insn) ||
- disas_vfp_uncond(s, insn)) {
+ disas_vfp_uncond(s, insn) ||
+ disas_neon_dp(s, insn) ||
+ disas_neon_ls(s, insn) ||
+ disas_neon_shared(s, insn)) {
return;
}
/* fall back to legacy decoder */
if (((insn >> 25) & 7) == 1) {
/* NEON Data processing. */
- if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
- goto illegal_op;
- }
-
if (disas_neon_data_insn(s, insn)) {
goto illegal_op;
}
return;
}
- if ((insn & 0x0f100000) == 0x04000000) {
- /* NEON load/store. */
- if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
- goto illegal_op;
- }
-
- if (disas_neon_ls_insn(s, insn)) {
- goto illegal_op;
- }
- return;
- }
if ((insn & 0x0e000f00) == 0x0c000100) {
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
/* iWMMXt register transfer. */
@@ -10977,18 +10363,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
}
}
}
- } else if ((insn & 0x0e000a00) == 0x0c000800
- && arm_dc_feature(s, ARM_FEATURE_V8)) {
- if (disas_neon_insn_3same_ext(s, insn)) {
- goto illegal_op;
- }
- return;
- } else if ((insn & 0x0f000a00) == 0x0e000800
- && arm_dc_feature(s, ARM_FEATURE_V8)) {
- if (disas_neon_insn_2reg_scalar_ext(s, insn)) {
- goto illegal_op;
- }
- return;
}
goto illegal_op;
}
@@ -11102,6 +10476,33 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
ARCH(6T2);
}
+ if ((insn & 0xef000000) == 0xef000000) {
+ /*
+ * T32 encodings 0b111p_1111_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq
+ * transform into
+ * A32 encodings 0b1111_001p_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq
+ */
+ uint32_t a32_insn = (insn & 0xe2ffffff) |
+ ((insn & (1 << 28)) >> 4) | (1 << 28);
+
+ if (disas_neon_dp(s, a32_insn)) {
+ return;
+ }
+ }
+
+ if ((insn & 0xff100000) == 0xf9000000) {
+ /*
+ * T32 encodings 0b1111_1001_ppp0_qqqq_qqqq_qqqq_qqqq_qqqq
+ * transform into
+ * A32 encodings 0b1111_0100_ppp0_qqqq_qqqq_qqqq_qqqq_qqqq
+ */
+ uint32_t a32_insn = (insn & 0x00ffffff) | 0xf4000000;
+
+ if (disas_neon_ls(s, a32_insn)) {
+ return;
+ }
+ }
+
/*
* TODO: Perhaps merge these into one decodetree output file.
* Note disas_vfp is written for a32 with cond field in the
@@ -11109,6 +10510,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
*/
if (disas_t32(s, insn) ||
disas_vfp_uncond(s, insn) ||
+ disas_neon_shared(s, insn) ||
((insn >> 28) == 0xe && disas_vfp(s, insn))) {
return;
}
@@ -11138,19 +10540,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
break;
}
- if ((insn & 0xfe000a00) == 0xfc000800
- && arm_dc_feature(s, ARM_FEATURE_V8)) {
- /* The Thumb2 and ARM encodings are identical. */
- if (disas_neon_insn_3same_ext(s, insn)) {
- goto illegal_op;
- }
- } else if ((insn & 0xff000a00) == 0xfe000800
- && arm_dc_feature(s, ARM_FEATURE_V8)) {
- /* The Thumb2 and ARM encodings are identical. */
- if (disas_neon_insn_2reg_scalar_ext(s, insn)) {
- goto illegal_op;
- }
- } else if (((insn >> 24) & 3) == 3) {
+ if (((insn >> 24) & 3) == 3) {
/* Translate into the equivalent ARM encoding. */
insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
if (disas_neon_data_insn(s, insn)) {
@@ -11168,12 +10558,6 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
break;
case 12:
- if ((insn & 0x01100000) == 0x01000000) {
- if (disas_neon_ls_insn(s, insn)) {
- goto illegal_op;
- }
- break;
- }
goto illegal_op;
default:
illegal_op: