diff options
Diffstat (limited to 'target/arm/translate.c')
| -rw-r--r-- | target/arm/translate.c | 1064 |
1 files changed, 6 insertions, 1058 deletions
diff --git a/target/arm/translate.c b/target/arm/translate.c index 6d18892ade..795964da1f 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -378,9 +378,9 @@ static void gen_revsh(TCGv_i32 dest, TCGv_i32 var) } /* Swap low and high halfwords. */ -static void gen_swap_half(TCGv_i32 var) +static void gen_swap_half(TCGv_i32 dest, TCGv_i32 var) { - tcg_gen_rotri_i32(var, var, 16); + tcg_gen_rotri_i32(dest, var, 16); } /* Dual 16-bit add. Result placed in t0 and t1 is marked as dead. @@ -1133,25 +1133,6 @@ neon_reg_offset (int reg, int n) return vfp_reg_offset(0, sreg); } -/* Return the offset of a 2**SIZE piece of a NEON register, at index ELE, - * where 0 is the least significant end of the register. - */ -static inline long -neon_element_offset(int reg, int element, MemOp size) -{ - int element_size = 1 << size; - int ofs = element * element_size; -#ifdef HOST_WORDS_BIGENDIAN - /* Calculate the offset assuming fully little-endian, - * then XOR to account for the order of the 8-byte units. - */ - if (element_size < 8) { - ofs ^= 8 - element_size; - } -#endif - return neon_reg_offset(reg, 0) + ofs; -} - static TCGv_i32 neon_load_reg(int reg, int pass) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -1159,94 +1140,12 @@ static TCGv_i32 neon_load_reg(int reg, int pass) return tmp; } -static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) -{ - long offset = neon_element_offset(reg, ele, mop & MO_SIZE); - - switch (mop) { - case MO_UB: - tcg_gen_ld8u_i32(var, cpu_env, offset); - break; - case MO_UW: - tcg_gen_ld16u_i32(var, cpu_env, offset); - break; - case MO_UL: - tcg_gen_ld_i32(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - -static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) -{ - long offset = neon_element_offset(reg, ele, mop & MO_SIZE); - - switch (mop) { - case MO_UB: - tcg_gen_ld8u_i64(var, cpu_env, offset); - break; - case MO_UW: - tcg_gen_ld16u_i64(var, cpu_env, offset); - break; - case MO_UL: - tcg_gen_ld32u_i64(var, cpu_env, offset); - break; - case MO_Q: - tcg_gen_ld_i64(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - static void neon_store_reg(int reg, int pass, TCGv_i32 var) { tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass)); tcg_temp_free_i32(var); } -static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) -{ - long offset = neon_element_offset(reg, ele, size); - - switch (size) { - case MO_8: - tcg_gen_st8_i32(var, cpu_env, offset); - break; - case MO_16: - tcg_gen_st16_i32(var, cpu_env, offset); - break; - case MO_32: - tcg_gen_st_i32(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - -static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) -{ - long offset = neon_element_offset(reg, ele, size); - - switch (size) { - case MO_8: - tcg_gen_st8_i64(var, cpu_env, offset); - break; - case MO_16: - tcg_gen_st16_i64(var, cpu_env, offset); - break; - case MO_32: - tcg_gen_st32_i64(var, cpu_env, offset); - break; - case MO_64: - tcg_gen_st_i64(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - static inline void neon_load_reg64(TCGv_i64 var, int reg) { tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg)); @@ -2934,377 +2833,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc) gen_rfe(s, pc, load_cpu_field(spsr)); } -#define CPU_V001 cpu_V0, cpu_V0, cpu_V1 - -static int gen_neon_unzip(int rd, int rm, int size, int q) -{ - TCGv_ptr pd, pm; - - if (!q && size == 2) { - return 1; - } - pd = vfp_reg_ptr(true, rd); - pm = vfp_reg_ptr(true, rm); - if (q) { - switch (size) { - case 0: - gen_helper_neon_qunzip8(pd, pm); - break; - case 1: - gen_helper_neon_qunzip16(pd, pm); - break; - case 2: - gen_helper_neon_qunzip32(pd, pm); - break; - default: - abort(); - } - } else { - switch (size) { - case 0: - gen_helper_neon_unzip8(pd, pm); - break; - case 1: - gen_helper_neon_unzip16(pd, pm); - break; - default: - abort(); - } - } - tcg_temp_free_ptr(pd); - tcg_temp_free_ptr(pm); - return 0; -} - -static int gen_neon_zip(int rd, int rm, int size, int q) -{ - TCGv_ptr pd, pm; - - if (!q && size == 2) { - return 1; - } - pd = vfp_reg_ptr(true, rd); - pm = vfp_reg_ptr(true, rm); - if (q) { - switch (size) { - case 0: - gen_helper_neon_qzip8(pd, pm); - break; - case 1: - gen_helper_neon_qzip16(pd, pm); - break; - case 2: - gen_helper_neon_qzip32(pd, pm); - break; - default: - abort(); - } - } else { - switch (size) { - case 0: - gen_helper_neon_zip8(pd, pm); - break; - case 1: - gen_helper_neon_zip16(pd, pm); - break; - default: - abort(); - } - } - tcg_temp_free_ptr(pd); - tcg_temp_free_ptr(pm); - return 0; -} - -static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) -{ - TCGv_i32 rd, tmp; - - rd = tcg_temp_new_i32(); - tmp = tcg_temp_new_i32(); - - tcg_gen_shli_i32(rd, t0, 8); - tcg_gen_andi_i32(rd, rd, 0xff00ff00); - tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); - tcg_gen_or_i32(rd, rd, tmp); - - tcg_gen_shri_i32(t1, t1, 8); - tcg_gen_andi_i32(t1, t1, 0x00ff00ff); - tcg_gen_andi_i32(tmp, t0, 0xff00ff00); - tcg_gen_or_i32(t1, t1, tmp); - tcg_gen_mov_i32(t0, rd); - - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(rd); -} - -static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) -{ - TCGv_i32 rd, tmp; - - rd = tcg_temp_new_i32(); - tmp = tcg_temp_new_i32(); - - tcg_gen_shli_i32(rd, t0, 16); - tcg_gen_andi_i32(tmp, t1, 0xffff); - tcg_gen_or_i32(rd, rd, tmp); - tcg_gen_shri_i32(t1, t1, 16); - tcg_gen_andi_i32(tmp, t0, 0xffff0000); - tcg_gen_or_i32(t1, t1, tmp); - tcg_gen_mov_i32(t0, rd); - - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(rd); -} - -static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_narrow_u8(dest, src); break; - case 1: gen_helper_neon_narrow_u16(dest, src); break; - case 2: tcg_gen_extrl_i64_i32(dest, src); break; - default: abort(); - } -} - -static inline void gen_neon_narrow_sats(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break; - case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break; - case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break; - default: abort(); - } -} - -static inline void gen_neon_narrow_satu(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break; - case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break; - case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break; - default: abort(); - } -} - -static inline void gen_neon_unarrow_sats(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break; - case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break; - case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break; - default: abort(); - } -} - -static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) -{ - if (u) { - switch (size) { - case 0: gen_helper_neon_widen_u8(dest, src); break; - case 1: gen_helper_neon_widen_u16(dest, src); break; - case 2: tcg_gen_extu_i32_i64(dest, src); break; - default: abort(); - } - } else { - switch (size) { - case 0: gen_helper_neon_widen_s8(dest, src); break; - case 1: gen_helper_neon_widen_s16(dest, src); break; - case 2: tcg_gen_ext_i32_i64(dest, src); break; - default: abort(); - } - } - tcg_temp_free_i32(src); -} - -static inline void gen_neon_addl(int size) -{ - switch (size) { - case 0: gen_helper_neon_addl_u16(CPU_V001); break; - case 1: gen_helper_neon_addl_u32(CPU_V001); break; - case 2: tcg_gen_add_i64(CPU_V001); break; - default: abort(); - } -} - -static void gen_neon_narrow_op(int op, int u, int size, - TCGv_i32 dest, TCGv_i64 src) -{ - if (op) { - if (u) { - gen_neon_unarrow_sats(size, dest, src); - } else { - gen_neon_narrow(size, dest, src); - } - } else { - if (u) { - gen_neon_narrow_satu(size, dest, src); - } else { - gen_neon_narrow_sats(size, dest, src); - } - } -} - -/* Symbolic constants for op fields for Neon 2-register miscellaneous. - * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B - * table A7-13. - */ -#define NEON_2RM_VREV64 0 -#define NEON_2RM_VREV32 1 -#define NEON_2RM_VREV16 2 -#define NEON_2RM_VPADDL 4 -#define NEON_2RM_VPADDL_U 5 -#define NEON_2RM_AESE 6 /* Includes AESD */ -#define NEON_2RM_AESMC 7 /* Includes AESIMC */ -#define NEON_2RM_VCLS 8 -#define NEON_2RM_VCLZ 9 -#define NEON_2RM_VCNT 10 -#define NEON_2RM_VMVN 11 -#define NEON_2RM_VPADAL 12 -#define NEON_2RM_VPADAL_U 13 -#define NEON_2RM_VQABS 14 -#define NEON_2RM_VQNEG 15 -#define NEON_2RM_VCGT0 16 -#define NEON_2RM_VCGE0 17 -#define NEON_2RM_VCEQ0 18 -#define NEON_2RM_VCLE0 19 -#define NEON_2RM_VCLT0 20 -#define NEON_2RM_SHA1H 21 -#define NEON_2RM_VABS 22 -#define NEON_2RM_VNEG 23 -#define NEON_2RM_VCGT0_F 24 -#define NEON_2RM_VCGE0_F 25 -#define NEON_2RM_VCEQ0_F 26 -#define NEON_2RM_VCLE0_F 27 -#define NEON_2RM_VCLT0_F 28 -#define NEON_2RM_VABS_F 30 -#define NEON_2RM_VNEG_F 31 -#define NEON_2RM_VSWP 32 -#define NEON_2RM_VTRN 33 -#define NEON_2RM_VUZP 34 -#define NEON_2RM_VZIP 35 -#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */ -#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */ -#define NEON_2RM_VSHLL 38 -#define NEON_2RM_SHA1SU1 39 /* Includes SHA256SU0 */ -#define NEON_2RM_VRINTN 40 -#define NEON_2RM_VRINTX 41 -#define NEON_2RM_VRINTA 42 -#define NEON_2RM_VRINTZ 43 -#define NEON_2RM_VCVT_F16_F32 44 -#define NEON_2RM_VRINTM 45 -#define NEON_2RM_VCVT_F32_F16 46 -#define NEON_2RM_VRINTP 47 -#define NEON_2RM_VCVTAU 48 -#define NEON_2RM_VCVTAS 49 -#define NEON_2RM_VCVTNU 50 -#define NEON_2RM_VCVTNS 51 -#define NEON_2RM_VCVTPU 52 -#define NEON_2RM_VCVTPS 53 -#define NEON_2RM_VCVTMU 54 -#define NEON_2RM_VCVTMS 55 -#define NEON_2RM_VRECPE 56 -#define NEON_2RM_VRSQRTE 57 -#define NEON_2RM_VRECPE_F 58 -#define NEON_2RM_VRSQRTE_F 59 -#define NEON_2RM_VCVT_FS 60 -#define NEON_2RM_VCVT_FU 61 -#define NEON_2RM_VCVT_SF 62 -#define NEON_2RM_VCVT_UF 63 - -static bool neon_2rm_is_v8_op(int op) -{ - /* Return true if this neon 2reg-misc op is ARMv8 and up */ - switch (op) { - case NEON_2RM_VRINTN: - case NEON_2RM_VRINTA: - case NEON_2RM_VRINTM: - case NEON_2RM_VRINTP: - case NEON_2RM_VRINTZ: - case NEON_2RM_VRINTX: - case NEON_2RM_VCVTAU: - case NEON_2RM_VCVTAS: - case NEON_2RM_VCVTNU: - case NEON_2RM_VCVTNS: - case NEON_2RM_VCVTPU: - case NEON_2RM_VCVTPS: - case NEON_2RM_VCVTMU: - case NEON_2RM_VCVTMS: - return true; - default: - return false; - } -} - -/* Each entry in this array has bit n set if the insn allows - * size value n (otherwise it will UNDEF). Since unallocated - * op values will have no bits set they always UNDEF. - */ -static const uint8_t neon_2rm_sizes[] = { - [NEON_2RM_VREV64] = 0x7, - [NEON_2RM_VREV32] = 0x3, - [NEON_2RM_VREV16] = 0x1, - [NEON_2RM_VPADDL] = 0x7, - [NEON_2RM_VPADDL_U] = 0x7, - [NEON_2RM_AESE] = 0x1, - [NEON_2RM_AESMC] = 0x1, - [NEON_2RM_VCLS] = 0x7, - [NEON_2RM_VCLZ] = 0x7, - [NEON_2RM_VCNT] = 0x1, - [NEON_2RM_VMVN] = 0x1, - [NEON_2RM_VPADAL] = 0x7, - [NEON_2RM_VPADAL_U] = 0x7, - [NEON_2RM_VQABS] = 0x7, - [NEON_2RM_VQNEG] = 0x7, - [NEON_2RM_VCGT0] = 0x7, - [NEON_2RM_VCGE0] = 0x7, - [NEON_2RM_VCEQ0] = 0x7, - [NEON_2RM_VCLE0] = 0x7, - [NEON_2RM_VCLT0] = 0x7, - [NEON_2RM_SHA1H] = 0x4, - [NEON_2RM_VABS] = 0x7, - [NEON_2RM_VNEG] = 0x7, - [NEON_2RM_VCGT0_F] = 0x4, - [NEON_2RM_VCGE0_F] = 0x4, - [NEON_2RM_VCEQ0_F] = 0x4, - [NEON_2RM_VCLE0_F] = 0x4, - [NEON_2RM_VCLT0_F] = 0x4, - [NEON_2RM_VABS_F] = 0x4, - [NEON_2RM_VNEG_F] = 0x4, - [NEON_2RM_VSWP] = 0x1, - [NEON_2RM_VTRN] = 0x7, - [NEON_2RM_VUZP] = 0x7, - [NEON_2RM_VZIP] = 0x7, - [NEON_2RM_VMOVN] = 0x7, - [NEON_2RM_VQMOVN] = 0x7, - [NEON_2RM_VSHLL] = 0x7, - [NEON_2RM_SHA1SU1] = 0x4, - [NEON_2RM_VRINTN] = 0x4, - [NEON_2RM_VRINTX] = 0x4, - [NEON_2RM_VRINTA] = 0x4, - [NEON_2RM_VRINTZ] = 0x4, - [NEON_2RM_VCVT_F16_F32] = 0x2, - [NEON_2RM_VRINTM] = 0x4, - [NEON_2RM_VCVT_F32_F16] = 0x2, - [NEON_2RM_VRINTP] = 0x4, - [NEON_2RM_VCVTAU] = 0x4, - [NEON_2RM_VCVTAS] = 0x4, - [NEON_2RM_VCVTNU] = 0x4, - [NEON_2RM_VCVTNS] = 0x4, - [NEON_2RM_VCVTPU] = 0x4, - [NEON_2RM_VCVTPS] = 0x4, - [NEON_2RM_VCVTMU] = 0x4, - [NEON_2RM_VCVTMS] = 0x4, - [NEON_2RM_VRECPE] = 0x4, - [NEON_2RM_VRSQRTE] = 0x4, - [NEON_2RM_VRECPE_F] = 0x4, - [NEON_2RM_VRSQRTE_F] = 0x4, - [NEON_2RM_VCVT_FS] = 0x4, - [NEON_2RM_VCVT_FU] = 0x4, - [NEON_2RM_VCVT_SF] = 0x4, - [NEON_2RM_VCVT_UF] = 0x4, -}; - static void gen_gvec_fn3_qc(uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz, gen_helper_gvec_3_ptr *fn) @@ -5016,573 +4544,6 @@ void gen_gvec_uaba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); } -/* Translate a NEON data processing instruction. Return nonzero if the - instruction is invalid. - We process data in a mixture of 32-bit and 64-bit chunks. - Mostly we use 32-bit chunks so we can use normal scalar instructions. */ - -static int disas_neon_data_insn(DisasContext *s, uint32_t insn) -{ - int op; - int q; - int rd, rm, rd_ofs, rm_ofs; - int size; - int pass; - int u; - int vec_size; - TCGv_i32 tmp, tmp2, tmp3; - - 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. - */ - 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; - q = (insn & (1 << 6)) != 0; - u = (insn >> 24) & 1; - VFP_DREG_D(rd, insn); - VFP_DREG_M(rm, insn); - size = (insn >> 20) & 3; - vec_size = q ? 16 : 8; - rd_ofs = neon_reg_offset(rd, 0); - rm_ofs = neon_reg_offset(rm, 0); - - if ((insn & (1 << 23)) == 0) { - /* Three register same length: handled by decodetree */ - return 1; - } else if (insn & (1 << 4)) { - /* Two registers and shift or reg and imm: handled by decodetree */ - return 1; - } else { /* (insn & 0x00800010 == 0x00800000) */ - if (size != 3) { - /* - * Three registers of different lengths, or two registers and - * a scalar: handled by decodetree - */ - return 1; - } else { /* size == 3 */ - if (!u) { - /* Extract: handled by decodetree */ - return 1; - } else if ((insn & (1 << 11)) == 0) { - /* Two register misc. */ - op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf); - size = (insn >> 18) & 3; - /* UNDEF for unknown op values and bad op-size combinations */ - if ((neon_2rm_sizes[op] & (1 << size)) == 0) { - return 1; - } - if (neon_2rm_is_v8_op(op) && - !arm_dc_feature(s, ARM_FEATURE_V8)) { - return 1; - } - if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) && - q && ((rm | rd) & 1)) { - return 1; - } - switch (op) { - case NEON_2RM_VREV64: - for (pass = 0; pass < (q ? 2 : 1); pass++) { - tmp = neon_load_reg(rm, pass * 2); - tmp2 = neon_load_reg(rm, pass * 2 + 1); - switch (size) { - case 0: tcg_gen_bswap32_i32(tmp, tmp); break; - case 1: gen_swap_half(tmp); break; - case 2: /* no-op */ break; - default: abort(); - } - neon_store_reg(rd, pass * 2 + 1, tmp); - if (size == 2) { - neon_store_reg(rd, pass * 2, tmp2); - } else { - switch (size) { - case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break; - case 1: gen_swap_half(tmp2); break; - default: abort(); - } - neon_store_reg(rd, pass * 2, tmp2); - } - } - break; - case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: - case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: - for (pass = 0; pass < q + 1; pass++) { - tmp = neon_load_reg(rm, pass * 2); - gen_neon_widen(cpu_V0, tmp, size, op & 1); - tmp = neon_load_reg(rm, pass * 2 + 1); - gen_neon_widen(cpu_V1, tmp, size, op & 1); - switch (size) { - case 0: gen_helper_neon_paddl_u16(CPU_V001); break; - case 1: gen_helper_neon_paddl_u32(CPU_V001); break; - case 2: tcg_gen_add_i64(CPU_V001); break; - default: abort(); - } - if (op >= NEON_2RM_VPADAL) { - /* Accumulate. */ - neon_load_reg64(cpu_V1, rd + pass); - gen_neon_addl(size); - } - neon_store_reg64(cpu_V0, rd + pass); - } - break; - case NEON_2RM_VTRN: - if (size == 2) { - int n; - for (n = 0; n < (q ? 4 : 2); n += 2) { - tmp = neon_load_reg(rm, n); - tmp2 = neon_load_reg(rd, n + 1); - neon_store_reg(rm, n, tmp2); - neon_store_reg(rd, n + 1, tmp); - } - } else { - goto elementwise; - } - break; - case NEON_2RM_VUZP: - if (gen_neon_unzip(rd, rm, size, q)) { - return 1; - } - break; - case NEON_2RM_VZIP: - if (gen_neon_zip(rd, rm, size, q)) { - return 1; - } - break; - case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: - /* also VQMOVUN; op field and mnemonics don't line up */ - if (rm & 1) { - return 1; - } - tmp2 = NULL; - for (pass = 0; pass < 2; pass++) { - neon_load_reg64(cpu_V0, rm + pass); - tmp = tcg_temp_new_i32(); - gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size, - tmp, cpu_V0); - if (pass == 0) { - tmp2 = tmp; - } else { - neon_store_reg(rd, 0, tmp2); - neon_store_reg(rd, 1, tmp); - } - } - break; - case NEON_2RM_VSHLL: - if (q || (rd & 1)) { - return 1; - } - tmp = neon_load_reg(rm, 0); - tmp2 = neon_load_reg(rm, 1); - for (pass = 0; pass < 2; pass++) { - if (pass == 1) - tmp = tmp2; - gen_neon_widen(cpu_V0, tmp, size, 1); - tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size); - neon_store_reg64(cpu_V0, rd + pass); - } - break; - case NEON_2RM_VCVT_F16_F32: - { - TCGv_ptr fpst; - TCGv_i32 ahp; - - if (!dc_isar_feature(aa32_fp16_spconv, s) || - q || (rm & 1)) { - return 1; - } - fpst = get_fpstatus_ptr(true); - ahp = get_ahp_flag(); - tmp = neon_load_reg(rm, 0); - gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); - tmp2 = neon_load_reg(rm, 1); - gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp); - tcg_gen_shli_i32(tmp2, tmp2, 16); - tcg_gen_or_i32(tmp2, tmp2, tmp); - tcg_temp_free_i32(tmp); - tmp = neon_load_reg(rm, 2); - gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); - tmp3 = neon_load_reg(rm, 3); - neon_store_reg(rd, 0, tmp2); - gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp); - tcg_gen_shli_i32(tmp3, tmp3, 16); - tcg_gen_or_i32(tmp3, tmp3, tmp); - neon_store_reg(rd, 1, tmp3); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(ahp); - tcg_temp_free_ptr(fpst); - break; - } - case NEON_2RM_VCVT_F32_F16: - { - TCGv_ptr fpst; - TCGv_i32 ahp; - if (!dc_isar_feature(aa32_fp16_spconv, s) || - q || (rd & 1)) { - return 1; - } - fpst = get_fpstatus_ptr(true); - ahp = get_ahp_flag(); - tmp3 = tcg_temp_new_i32(); - tmp = neon_load_reg(rm, 0); - tmp2 = neon_load_reg(rm, 1); - tcg_gen_ext16u_i32(tmp3, tmp); - gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); - neon_store_reg(rd, 0, tmp3); - tcg_gen_shri_i32(tmp, tmp, 16); - gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); - neon_store_reg(rd, 1, tmp); - tmp3 = tcg_temp_new_i32(); - tcg_gen_ext16u_i32(tmp3, tmp2); - gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); - neon_store_reg(rd, 2, tmp3); - tcg_gen_shri_i32(tmp2, tmp2, 16); - gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); - neon_store_reg(rd, 3, tmp2); - tcg_temp_free_i32(ahp); - tcg_temp_free_ptr(fpst); - break; - } - case NEON_2RM_AESE: case NEON_2RM_AESMC: - if (!dc_isar_feature(aa32_aes, s) || ((rm | rd) & 1)) { - return 1; - } - /* - * Bit 6 is the lowest opcode bit; it distinguishes - * between encryption (AESE/AESMC) and decryption - * (AESD/AESIMC). - */ - if (op == NEON_2RM_AESE) { - tcg_gen_gvec_3_ool(vfp_reg_offset(true, rd), - vfp_reg_offset(true, rd), - vfp_reg_offset(true, rm), - 16, 16, extract32(insn, 6, 1), - gen_helper_crypto_aese); - } else { - tcg_gen_gvec_2_ool(vfp_reg_offset(true, rd), - vfp_reg_offset(true, rm), - 16, 16, extract32(insn, 6, 1), - gen_helper_crypto_aesmc); - } - break; - case NEON_2RM_SHA1H: - if (!dc_isar_feature(aa32_sha1, s) || ((rm | rd) & 1)) { - return 1; - } - tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0, - gen_helper_crypto_sha1h); - break; - case NEON_2RM_SHA1SU1: - if ((rm | rd) & 1) { - return 1; - } - /* bit 6 (q): set -> SHA256SU0, cleared -> SHA1SU1 */ - if (q) { - if (!dc_isar_feature(aa32_sha2, s)) { - return 1; - } - } else if (!dc_isar_feature(aa32_sha1, s)) { - return 1; - } - tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0, - q ? gen_helper_crypto_sha256su0 - : gen_helper_crypto_sha1su1); - break; - case NEON_2RM_VMVN: - tcg_gen_gvec_not(0, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VNEG: - tcg_gen_gvec_neg(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VABS: - tcg_gen_gvec_abs(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - - case NEON_2RM_VCEQ0: - gen_gvec_ceq0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCGT0: - gen_gvec_cgt0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCLE0: - gen_gvec_cle0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCGE0: - gen_gvec_cge0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCLT0: - gen_gvec_clt0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - - default: - elementwise: - for (pass = 0; pass < (q ? 4 : 2); pass++) { - tmp = neon_load_reg(rm, pass); - switch (op) { - case NEON_2RM_VREV32: - switch (size) { - case 0: tcg_gen_bswap32_i32(tmp, tmp); break; - case 1: gen_swap_half(tmp); break; - default: abort(); - } - break; - case NEON_2RM_VREV16: - gen_rev16(tmp, tmp); - break; - case NEON_2RM_VCLS: - switch (size) { - case 0: gen_helper_neon_cls_s8(tmp, tmp); break; - case 1: gen_helper_neon_cls_s16(tmp, tmp); break; - case 2: gen_helper_neon_cls_s32(tmp, tmp); break; - default: abort(); - } - break; - case NEON_2RM_VCLZ: - switch (size) { - case 0: gen_helper_neon_clz_u8(tmp, tmp); break; - case 1: gen_helper_neon_clz_u16(tmp, tmp); break; - case 2: tcg_gen_clzi_i32(tmp, tmp, 32); break; - default: abort(); - } - break; - case NEON_2RM_VCNT: - gen_helper_neon_cnt_u8(tmp, tmp); - break; - case NEON_2RM_VQABS: - switch (size) { - case 0: - gen_helper_neon_qabs_s8(tmp, cpu_env, tmp); - break; - case 1: - gen_helper_neon_qabs_s16(tmp, cpu_env, tmp); - break; - case 2: - gen_helper_neon_qabs_s32(tmp, cpu_env, tmp); - break; - default: abort(); - } - break; - case NEON_2RM_VQNEG: - switch (size) { - case 0: - gen_helper_neon_qneg_s8(tmp, cpu_env, tmp); - break; - case 1: - gen_helper_neon_qneg_s16(tmp, cpu_env, tmp); - break; - case 2: - gen_helper_neon_qneg_s32(tmp, cpu_env, tmp); - break; - default: abort(); - } - break; - case NEON_2RM_VCGT0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCGE0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCEQ0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCLE0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCLT0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VABS_F: - gen_helper_vfp_abss(tmp, tmp); - break; - case NEON_2RM_VNEG_F: - gen_helper_vfp_negs(tmp, tmp); - break; - case NEON_2RM_VSWP: - tmp2 = neon_load_reg(rd, pass); - neon_store_reg(rm, pass, tmp2); - break; - case NEON_2RM_VTRN: - tmp2 = neon_load_reg(rd, pass); - switch (size) { - case 0: gen_neon_trn_u8(tmp, tmp2); break; - case 1: gen_neon_trn_u16(tmp, tmp2); break; - default: abort(); - } - neon_store_reg(rm, pass, tmp2); - break; - case NEON_2RM_VRINTN: - case NEON_2RM_VRINTA: - case NEON_2RM_VRINTM: - case NEON_2RM_VRINTP: - case NEON_2RM_VRINTZ: - { - TCGv_i32 tcg_rmode; - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - int rmode; - - if (op == NEON_2RM_VRINTZ) { - rmode = FPROUNDING_ZERO; - } else { - rmode = fp_decode_rm[((op & 0x6) >> 1) ^ 1]; - } - - tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - gen_helper_rints(tmp, tmp, fpstatus); - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - tcg_temp_free_ptr(fpstatus); - tcg_temp_free_i32(tcg_rmode); - break; - } - case NEON_2RM_VRINTX: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_rints_exact(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCVTAU: - case NEON_2RM_VCVTAS: - case NEON_2RM_VCVTNU: - case NEON_2RM_VCVTNS: - case NEON_2RM_VCVTPU: - case NEON_2RM_VCVTPS: - case NEON_2RM_VCVTMU: - case NEON_2RM_VCVTMS: - { - bool is_signed = !extract32(insn, 7, 1); - TCGv_ptr fpst = get_fpstatus_ptr(1); - TCGv_i32 tcg_rmode, tcg_shift; - int rmode = fp_decode_rm[extract32(insn, 8, 2)]; - - tcg_shift = tcg_const_i32(0); - tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - - if (is_signed) { - gen_helper_vfp_tosls(tmp, tmp, - tcg_shift, fpst); - } else { - gen_helper_vfp_touls(tmp, tmp, - tcg_shift, fpst); - } - - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - tcg_temp_free_i32(tcg_rmode); - tcg_temp_free_i32(tcg_shift); - tcg_temp_free_ptr(fpst); - break; - } - case NEON_2RM_VRECPE: - gen_helper_recpe_u32(tmp, tmp); - break; - case NEON_2RM_VRSQRTE: - gen_helper_rsqrte_u32(tmp, tmp); - break; - case NEON_2RM_VRECPE_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_recpe_f32(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VRSQRTE_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_rsqrte_f32(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */ - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_sitos(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */ - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_uitos(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */ - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_tosizs(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */ - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_vfp_touizs(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - default: - /* Reserved op values were caught by the - * neon_2rm_sizes[] check earlier. - */ - abort(); - } - neon_store_reg(rd, pass, tmp); - } - break; - } - } else { - /* VTBL, VTBX, VDUP: handled by decodetree */ - return 1; - } - } - } - return 0; -} - static int disas_coproc_insn(DisasContext *s, uint32_t insn) { int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2; @@ -8417,7 +7378,7 @@ static bool op_smlad(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub) t1 = load_reg(s, a->rn); t2 = load_reg(s, a->rm); if (m_swap) { - gen_swap_half(t2); + gen_swap_half(t2, t2); } gen_smul_dual(t1, t2); @@ -8475,7 +7436,7 @@ static bool op_smlald(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub) t1 = load_reg(s, a->rn); t2 = load_reg(s, a->rm); if (m_swap) { - gen_swap_half(t2); + gen_swap_half(t2, t2); } gen_smul_dual(t1, t2); @@ -8824,9 +7785,6 @@ static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) gen_io_start(); } gen_helper_cpsr_write_eret(cpu_env, tmp); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } tcg_temp_free_i32(tmp); /* Must exit loop to check un-masked IRQs */ s->base.is_jmp = DISAS_EXIT; @@ -9283,13 +8241,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } /* fall back to legacy decoder */ - if (((insn >> 25) & 7) == 1) { - /* NEON Data processing. */ - if (disas_neon_data_insn(s, insn)) { - goto illegal_op; - } - return; - } if ((insn & 0x0e000f00) == 0x0c000100) { if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) { /* iWMMXt register transfer. */ @@ -9477,11 +8428,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) break; } 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)) { - goto illegal_op; - } + /* Neon DP, but failed disas_neon_dp() */ + goto illegal_op; } else if (((insn >> 8) & 0xe) == 10) { /* VFP, but failed disas_vfp. */ goto illegal_op; |