]>
git.proxmox.com Git - mirror_qemu.git/blob - target/arm/translate-vfp.inc.c
2 * ARM translation: AArch32 VFP instructions
4 * Copyright (c) 2003 Fabrice Bellard
5 * Copyright (c) 2005-2007 CodeSourcery
6 * Copyright (c) 2007 OpenedHand, Ltd.
7 * Copyright (c) 2019 Linaro, Ltd.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 * This file is intended to be included from translate.c; it uses
25 * some macros and definitions provided by that file.
26 * It might be possible to convert it to a standalone .c file eventually.
29 /* Include the generated VFP decoder */
30 #include "decode-vfp.inc.c"
31 #include "decode-vfp-uncond.inc.c"
34 * The imm8 encodes the sign bit, enough bits to represent an exponent in
35 * the range 01....1xx to 10....0xx, and the most significant 4 bits of
36 * the mantissa; see VFPExpandImm() in the v8 ARM ARM.
38 uint64_t vfp_expand_imm(int size
, uint8_t imm8
)
44 imm
= (extract32(imm8
, 7, 1) ? 0x8000 : 0) |
45 (extract32(imm8
, 6, 1) ? 0x3fc0 : 0x4000) |
46 extract32(imm8
, 0, 6);
50 imm
= (extract32(imm8
, 7, 1) ? 0x8000 : 0) |
51 (extract32(imm8
, 6, 1) ? 0x3e00 : 0x4000) |
52 (extract32(imm8
, 0, 6) << 3);
56 imm
= (extract32(imm8
, 7, 1) ? 0x8000 : 0) |
57 (extract32(imm8
, 6, 1) ? 0x3000 : 0x4000) |
58 (extract32(imm8
, 0, 6) << 6);
61 g_assert_not_reached();
67 * Return the offset of a 16-bit half of the specified VFP single-precision
68 * register. If top is true, returns the top 16 bits; otherwise the bottom
71 static inline long vfp_f16_offset(unsigned reg
, bool top
)
73 long offs
= vfp_reg_offset(false, reg
);
74 #ifdef HOST_WORDS_BIGENDIAN
87 * Check that VFP access is enabled. If it is, do the necessary
88 * M-profile lazy-FP handling and then return true.
89 * If not, emit code to generate an appropriate exception and
91 * The ignore_vfp_enabled argument specifies that we should ignore
92 * whether VFP is enabled via FPEXC[EN]: this should be true for FMXR/FMRX
93 * accesses to FPSID, FPEXC, MVFR0, MVFR1, MVFR2, and false for all other insns.
95 static bool full_vfp_access_check(DisasContext
*s
, bool ignore_vfp_enabled
)
98 if (arm_dc_feature(s
, ARM_FEATURE_M
)) {
99 gen_exception_insn(s
, s
->pc_curr
, EXCP_NOCP
, syn_uncategorized(),
102 gen_exception_insn(s
, s
->pc_curr
, EXCP_UDEF
,
103 syn_fp_access_trap(1, 0xe, false),
109 if (!s
->vfp_enabled
&& !ignore_vfp_enabled
) {
110 assert(!arm_dc_feature(s
, ARM_FEATURE_M
));
111 unallocated_encoding(s
);
115 if (arm_dc_feature(s
, ARM_FEATURE_M
)) {
116 /* Handle M-profile lazy FP state mechanics */
118 /* Trigger lazy-state preservation if necessary */
121 * Lazy state saving affects external memory and also the NVIC,
122 * so we must mark it as an IO operation for icount.
124 if (tb_cflags(s
->base
.tb
) & CF_USE_ICOUNT
) {
127 gen_helper_v7m_preserve_fp_state(cpu_env
);
128 if (tb_cflags(s
->base
.tb
) & CF_USE_ICOUNT
) {
132 * If the preserve_fp_state helper doesn't throw an exception
133 * then it will clear LSPACT; we don't need to repeat this for
134 * any further FP insns in this TB.
136 s
->v7m_lspact
= false;
139 /* Update ownership of FP context: set FPCCR.S to match current state */
140 if (s
->v8m_fpccr_s_wrong
) {
143 tmp
= load_cpu_field(v7m
.fpccr
[M_REG_S
]);
145 tcg_gen_ori_i32(tmp
, tmp
, R_V7M_FPCCR_S_MASK
);
147 tcg_gen_andi_i32(tmp
, tmp
, ~R_V7M_FPCCR_S_MASK
);
149 store_cpu_field(tmp
, v7m
.fpccr
[M_REG_S
]);
150 /* Don't need to do this for any further FP insns in this TB */
151 s
->v8m_fpccr_s_wrong
= false;
154 if (s
->v7m_new_fp_ctxt_needed
) {
156 * Create new FP context by updating CONTROL.FPCA, CONTROL.SFPA
159 TCGv_i32 control
, fpscr
;
160 uint32_t bits
= R_V7M_CONTROL_FPCA_MASK
;
162 fpscr
= load_cpu_field(v7m
.fpdscr
[s
->v8m_secure
]);
163 gen_helper_vfp_set_fpscr(cpu_env
, fpscr
);
164 tcg_temp_free_i32(fpscr
);
166 * We don't need to arrange to end the TB, because the only
167 * parts of FPSCR which we cache in the TB flags are the VECLEN
168 * and VECSTRIDE, and those don't exist for M-profile.
172 bits
|= R_V7M_CONTROL_SFPA_MASK
;
174 control
= load_cpu_field(v7m
.control
[M_REG_S
]);
175 tcg_gen_ori_i32(control
, control
, bits
);
176 store_cpu_field(control
, v7m
.control
[M_REG_S
]);
177 /* Don't need to do this for any further FP insns in this TB */
178 s
->v7m_new_fp_ctxt_needed
= false;
186 * The most usual kind of VFP access check, for everything except
187 * FMXR/FMRX to the always-available special registers.
189 static bool vfp_access_check(DisasContext
*s
)
191 return full_vfp_access_check(s
, false);
194 static bool trans_VSEL(DisasContext
*s
, arg_VSEL
*a
)
199 if (!dc_isar_feature(aa32_vsel
, s
)) {
203 /* UNDEF accesses to D16-D31 if they don't exist */
204 if (dp
&& !dc_isar_feature(aa32_fp_d32
, s
) &&
205 ((a
->vm
| a
->vn
| a
->vd
) & 0x10)) {
209 if (dp
&& !dc_isar_feature(aa32_fpdp
, s
)) {
217 if (!vfp_access_check(s
)) {
222 TCGv_i64 frn
, frm
, dest
;
223 TCGv_i64 tmp
, zero
, zf
, nf
, vf
;
225 zero
= tcg_const_i64(0);
227 frn
= tcg_temp_new_i64();
228 frm
= tcg_temp_new_i64();
229 dest
= tcg_temp_new_i64();
231 zf
= tcg_temp_new_i64();
232 nf
= tcg_temp_new_i64();
233 vf
= tcg_temp_new_i64();
235 tcg_gen_extu_i32_i64(zf
, cpu_ZF
);
236 tcg_gen_ext_i32_i64(nf
, cpu_NF
);
237 tcg_gen_ext_i32_i64(vf
, cpu_VF
);
239 neon_load_reg64(frn
, rn
);
240 neon_load_reg64(frm
, rm
);
243 tcg_gen_movcond_i64(TCG_COND_EQ
, dest
, zf
, zero
,
247 tcg_gen_movcond_i64(TCG_COND_LT
, dest
, vf
, zero
,
250 case 2: /* ge: N == V -> N ^ V == 0 */
251 tmp
= tcg_temp_new_i64();
252 tcg_gen_xor_i64(tmp
, vf
, nf
);
253 tcg_gen_movcond_i64(TCG_COND_GE
, dest
, tmp
, zero
,
255 tcg_temp_free_i64(tmp
);
257 case 3: /* gt: !Z && N == V */
258 tcg_gen_movcond_i64(TCG_COND_NE
, dest
, zf
, zero
,
260 tmp
= tcg_temp_new_i64();
261 tcg_gen_xor_i64(tmp
, vf
, nf
);
262 tcg_gen_movcond_i64(TCG_COND_GE
, dest
, tmp
, zero
,
264 tcg_temp_free_i64(tmp
);
267 neon_store_reg64(dest
, rd
);
268 tcg_temp_free_i64(frn
);
269 tcg_temp_free_i64(frm
);
270 tcg_temp_free_i64(dest
);
272 tcg_temp_free_i64(zf
);
273 tcg_temp_free_i64(nf
);
274 tcg_temp_free_i64(vf
);
276 tcg_temp_free_i64(zero
);
278 TCGv_i32 frn
, frm
, dest
;
281 zero
= tcg_const_i32(0);
283 frn
= tcg_temp_new_i32();
284 frm
= tcg_temp_new_i32();
285 dest
= tcg_temp_new_i32();
286 neon_load_reg32(frn
, rn
);
287 neon_load_reg32(frm
, rm
);
290 tcg_gen_movcond_i32(TCG_COND_EQ
, dest
, cpu_ZF
, zero
,
294 tcg_gen_movcond_i32(TCG_COND_LT
, dest
, cpu_VF
, zero
,
297 case 2: /* ge: N == V -> N ^ V == 0 */
298 tmp
= tcg_temp_new_i32();
299 tcg_gen_xor_i32(tmp
, cpu_VF
, cpu_NF
);
300 tcg_gen_movcond_i32(TCG_COND_GE
, dest
, tmp
, zero
,
302 tcg_temp_free_i32(tmp
);
304 case 3: /* gt: !Z && N == V */
305 tcg_gen_movcond_i32(TCG_COND_NE
, dest
, cpu_ZF
, zero
,
307 tmp
= tcg_temp_new_i32();
308 tcg_gen_xor_i32(tmp
, cpu_VF
, cpu_NF
);
309 tcg_gen_movcond_i32(TCG_COND_GE
, dest
, tmp
, zero
,
311 tcg_temp_free_i32(tmp
);
314 neon_store_reg32(dest
, rd
);
315 tcg_temp_free_i32(frn
);
316 tcg_temp_free_i32(frm
);
317 tcg_temp_free_i32(dest
);
319 tcg_temp_free_i32(zero
);
325 static bool trans_VMINMAXNM(DisasContext
*s
, arg_VMINMAXNM
*a
)
332 if (!dc_isar_feature(aa32_vminmaxnm
, s
)) {
336 /* UNDEF accesses to D16-D31 if they don't exist */
337 if (dp
&& !dc_isar_feature(aa32_fp_d32
, s
) &&
338 ((a
->vm
| a
->vn
| a
->vd
) & 0x10)) {
342 if (dp
&& !dc_isar_feature(aa32_fpdp
, s
)) {
350 if (!vfp_access_check(s
)) {
354 fpst
= get_fpstatus_ptr(0);
357 TCGv_i64 frn
, frm
, dest
;
359 frn
= tcg_temp_new_i64();
360 frm
= tcg_temp_new_i64();
361 dest
= tcg_temp_new_i64();
363 neon_load_reg64(frn
, rn
);
364 neon_load_reg64(frm
, rm
);
366 gen_helper_vfp_minnumd(dest
, frn
, frm
, fpst
);
368 gen_helper_vfp_maxnumd(dest
, frn
, frm
, fpst
);
370 neon_store_reg64(dest
, rd
);
371 tcg_temp_free_i64(frn
);
372 tcg_temp_free_i64(frm
);
373 tcg_temp_free_i64(dest
);
375 TCGv_i32 frn
, frm
, dest
;
377 frn
= tcg_temp_new_i32();
378 frm
= tcg_temp_new_i32();
379 dest
= tcg_temp_new_i32();
381 neon_load_reg32(frn
, rn
);
382 neon_load_reg32(frm
, rm
);
384 gen_helper_vfp_minnums(dest
, frn
, frm
, fpst
);
386 gen_helper_vfp_maxnums(dest
, frn
, frm
, fpst
);
388 neon_store_reg32(dest
, rd
);
389 tcg_temp_free_i32(frn
);
390 tcg_temp_free_i32(frm
);
391 tcg_temp_free_i32(dest
);
394 tcg_temp_free_ptr(fpst
);
399 * Table for converting the most common AArch32 encoding of
400 * rounding mode to arm_fprounding order (which matches the
401 * common AArch64 order); see ARM ARM pseudocode FPDecodeRM().
403 static const uint8_t fp_decode_rm
[] = {
410 static bool trans_VRINT(DisasContext
*s
, arg_VRINT
*a
)
416 int rounding
= fp_decode_rm
[a
->rm
];
418 if (!dc_isar_feature(aa32_vrint
, s
)) {
422 /* UNDEF accesses to D16-D31 if they don't exist */
423 if (dp
&& !dc_isar_feature(aa32_fp_d32
, s
) &&
424 ((a
->vm
| a
->vd
) & 0x10)) {
428 if (dp
&& !dc_isar_feature(aa32_fpdp
, s
)) {
435 if (!vfp_access_check(s
)) {
439 fpst
= get_fpstatus_ptr(0);
441 tcg_rmode
= tcg_const_i32(arm_rmode_to_sf(rounding
));
442 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
447 tcg_op
= tcg_temp_new_i64();
448 tcg_res
= tcg_temp_new_i64();
449 neon_load_reg64(tcg_op
, rm
);
450 gen_helper_rintd(tcg_res
, tcg_op
, fpst
);
451 neon_store_reg64(tcg_res
, rd
);
452 tcg_temp_free_i64(tcg_op
);
453 tcg_temp_free_i64(tcg_res
);
457 tcg_op
= tcg_temp_new_i32();
458 tcg_res
= tcg_temp_new_i32();
459 neon_load_reg32(tcg_op
, rm
);
460 gen_helper_rints(tcg_res
, tcg_op
, fpst
);
461 neon_store_reg32(tcg_res
, rd
);
462 tcg_temp_free_i32(tcg_op
);
463 tcg_temp_free_i32(tcg_res
);
466 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
467 tcg_temp_free_i32(tcg_rmode
);
469 tcg_temp_free_ptr(fpst
);
473 static bool trans_VCVT(DisasContext
*s
, arg_VCVT
*a
)
478 TCGv_i32 tcg_rmode
, tcg_shift
;
479 int rounding
= fp_decode_rm
[a
->rm
];
480 bool is_signed
= a
->op
;
482 if (!dc_isar_feature(aa32_vcvt_dr
, s
)) {
486 /* UNDEF accesses to D16-D31 if they don't exist */
487 if (dp
&& !dc_isar_feature(aa32_fp_d32
, s
) && (a
->vm
& 0x10)) {
491 if (dp
&& !dc_isar_feature(aa32_fpdp
, s
)) {
498 if (!vfp_access_check(s
)) {
502 fpst
= get_fpstatus_ptr(0);
504 tcg_shift
= tcg_const_i32(0);
506 tcg_rmode
= tcg_const_i32(arm_rmode_to_sf(rounding
));
507 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
510 TCGv_i64 tcg_double
, tcg_res
;
512 tcg_double
= tcg_temp_new_i64();
513 tcg_res
= tcg_temp_new_i64();
514 tcg_tmp
= tcg_temp_new_i32();
515 neon_load_reg64(tcg_double
, rm
);
517 gen_helper_vfp_tosld(tcg_res
, tcg_double
, tcg_shift
, fpst
);
519 gen_helper_vfp_tould(tcg_res
, tcg_double
, tcg_shift
, fpst
);
521 tcg_gen_extrl_i64_i32(tcg_tmp
, tcg_res
);
522 neon_store_reg32(tcg_tmp
, rd
);
523 tcg_temp_free_i32(tcg_tmp
);
524 tcg_temp_free_i64(tcg_res
);
525 tcg_temp_free_i64(tcg_double
);
527 TCGv_i32 tcg_single
, tcg_res
;
528 tcg_single
= tcg_temp_new_i32();
529 tcg_res
= tcg_temp_new_i32();
530 neon_load_reg32(tcg_single
, rm
);
532 gen_helper_vfp_tosls(tcg_res
, tcg_single
, tcg_shift
, fpst
);
534 gen_helper_vfp_touls(tcg_res
, tcg_single
, tcg_shift
, fpst
);
536 neon_store_reg32(tcg_res
, rd
);
537 tcg_temp_free_i32(tcg_res
);
538 tcg_temp_free_i32(tcg_single
);
541 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
542 tcg_temp_free_i32(tcg_rmode
);
544 tcg_temp_free_i32(tcg_shift
);
546 tcg_temp_free_ptr(fpst
);
551 static bool trans_VMOV_to_gp(DisasContext
*s
, arg_VMOV_to_gp
*a
)
553 /* VMOV scalar to general purpose register */
558 /* UNDEF accesses to D16-D31 if they don't exist */
559 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vn
& 0x10)) {
563 offset
= a
->index
<< a
->size
;
564 pass
= extract32(offset
, 2, 1);
565 offset
= extract32(offset
, 0, 2) * 8;
567 if (a
->size
!= 2 && !arm_dc_feature(s
, ARM_FEATURE_NEON
)) {
571 if (!vfp_access_check(s
)) {
575 tmp
= neon_load_reg(a
->vn
, pass
);
579 tcg_gen_shri_i32(tmp
, tmp
, offset
);
590 tcg_gen_shri_i32(tmp
, tmp
, 16);
596 tcg_gen_sari_i32(tmp
, tmp
, 16);
605 store_reg(s
, a
->rt
, tmp
);
610 static bool trans_VMOV_from_gp(DisasContext
*s
, arg_VMOV_from_gp
*a
)
612 /* VMOV general purpose register to scalar */
617 /* UNDEF accesses to D16-D31 if they don't exist */
618 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vn
& 0x10)) {
622 offset
= a
->index
<< a
->size
;
623 pass
= extract32(offset
, 2, 1);
624 offset
= extract32(offset
, 0, 2) * 8;
626 if (a
->size
!= 2 && !arm_dc_feature(s
, ARM_FEATURE_NEON
)) {
630 if (!vfp_access_check(s
)) {
634 tmp
= load_reg(s
, a
->rt
);
637 tmp2
= neon_load_reg(a
->vn
, pass
);
638 tcg_gen_deposit_i32(tmp
, tmp2
, tmp
, offset
, 8);
639 tcg_temp_free_i32(tmp2
);
642 tmp2
= neon_load_reg(a
->vn
, pass
);
643 tcg_gen_deposit_i32(tmp
, tmp2
, tmp
, offset
, 16);
644 tcg_temp_free_i32(tmp2
);
649 neon_store_reg(a
->vn
, pass
, tmp
);
654 static bool trans_VDUP(DisasContext
*s
, arg_VDUP
*a
)
656 /* VDUP (general purpose register) */
660 if (!arm_dc_feature(s
, ARM_FEATURE_NEON
)) {
664 /* UNDEF accesses to D16-D31 if they don't exist */
665 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vn
& 0x10)) {
673 if (a
->q
&& (a
->vn
& 1)) {
677 vec_size
= a
->q
? 16 : 8;
686 if (!vfp_access_check(s
)) {
690 tmp
= load_reg(s
, a
->rt
);
691 tcg_gen_gvec_dup_i32(size
, neon_reg_offset(a
->vn
, 0),
692 vec_size
, vec_size
, tmp
);
693 tcg_temp_free_i32(tmp
);
698 static bool trans_VMSR_VMRS(DisasContext
*s
, arg_VMSR_VMRS
*a
)
701 bool ignore_vfp_enabled
= false;
703 if (arm_dc_feature(s
, ARM_FEATURE_M
)) {
705 * The only M-profile VFP vmrs/vmsr sysreg is FPSCR.
706 * Writes to R15 are UNPREDICTABLE; we choose to undef.
708 if (a
->rt
== 15 || a
->reg
!= ARM_VFP_FPSCR
) {
716 * VFPv2 allows access to FPSID from userspace; VFPv3 restricts
717 * all ID registers to privileged access only.
719 if (IS_USER(s
) && arm_dc_feature(s
, ARM_FEATURE_VFP3
)) {
722 ignore_vfp_enabled
= true;
726 if (IS_USER(s
) || !arm_dc_feature(s
, ARM_FEATURE_MVFR
)) {
729 ignore_vfp_enabled
= true;
732 if (IS_USER(s
) || !arm_dc_feature(s
, ARM_FEATURE_V8
)) {
735 ignore_vfp_enabled
= true;
743 ignore_vfp_enabled
= true;
746 case ARM_VFP_FPINST2
:
747 /* Not present in VFPv3 */
748 if (IS_USER(s
) || arm_dc_feature(s
, ARM_FEATURE_VFP3
)) {
756 if (!full_vfp_access_check(s
, ignore_vfp_enabled
)) {
761 /* VMRS, move VFP special register to gp register */
766 case ARM_VFP_FPINST2
:
770 tmp
= load_cpu_field(vfp
.xregs
[a
->reg
]);
774 tmp
= load_cpu_field(vfp
.xregs
[ARM_VFP_FPSCR
]);
775 tcg_gen_andi_i32(tmp
, tmp
, 0xf0000000);
777 tmp
= tcg_temp_new_i32();
778 gen_helper_vfp_get_fpscr(tmp
, cpu_env
);
782 g_assert_not_reached();
786 /* Set the 4 flag bits in the CPSR. */
788 tcg_temp_free_i32(tmp
);
790 store_reg(s
, a
->rt
, tmp
);
793 /* VMSR, move gp register to VFP special register */
799 /* Writes are ignored. */
802 tmp
= load_reg(s
, a
->rt
);
803 gen_helper_vfp_set_fpscr(cpu_env
, tmp
);
804 tcg_temp_free_i32(tmp
);
809 * TODO: VFP subarchitecture support.
810 * For now, keep the EN bit only
812 tmp
= load_reg(s
, a
->rt
);
813 tcg_gen_andi_i32(tmp
, tmp
, 1 << 30);
814 store_cpu_field(tmp
, vfp
.xregs
[a
->reg
]);
818 case ARM_VFP_FPINST2
:
819 tmp
= load_reg(s
, a
->rt
);
820 store_cpu_field(tmp
, vfp
.xregs
[a
->reg
]);
823 g_assert_not_reached();
830 static bool trans_VMOV_single(DisasContext
*s
, arg_VMOV_single
*a
)
834 if (!vfp_access_check(s
)) {
839 /* VFP to general purpose register */
840 tmp
= tcg_temp_new_i32();
841 neon_load_reg32(tmp
, a
->vn
);
843 /* Set the 4 flag bits in the CPSR. */
845 tcg_temp_free_i32(tmp
);
847 store_reg(s
, a
->rt
, tmp
);
850 /* general purpose register to VFP */
851 tmp
= load_reg(s
, a
->rt
);
852 neon_store_reg32(tmp
, a
->vn
);
853 tcg_temp_free_i32(tmp
);
859 static bool trans_VMOV_64_sp(DisasContext
*s
, arg_VMOV_64_sp
*a
)
864 * VMOV between two general-purpose registers and two single precision
865 * floating point registers
867 if (!vfp_access_check(s
)) {
873 tmp
= tcg_temp_new_i32();
874 neon_load_reg32(tmp
, a
->vm
);
875 store_reg(s
, a
->rt
, tmp
);
876 tmp
= tcg_temp_new_i32();
877 neon_load_reg32(tmp
, a
->vm
+ 1);
878 store_reg(s
, a
->rt2
, tmp
);
881 tmp
= load_reg(s
, a
->rt
);
882 neon_store_reg32(tmp
, a
->vm
);
883 tcg_temp_free_i32(tmp
);
884 tmp
= load_reg(s
, a
->rt2
);
885 neon_store_reg32(tmp
, a
->vm
+ 1);
886 tcg_temp_free_i32(tmp
);
892 static bool trans_VMOV_64_dp(DisasContext
*s
, arg_VMOV_64_dp
*a
)
897 * VMOV between two general-purpose registers and one double precision
898 * floating point register
901 /* UNDEF accesses to D16-D31 if they don't exist */
902 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vm
& 0x10)) {
906 if (!vfp_access_check(s
)) {
912 tmp
= tcg_temp_new_i32();
913 neon_load_reg32(tmp
, a
->vm
* 2);
914 store_reg(s
, a
->rt
, tmp
);
915 tmp
= tcg_temp_new_i32();
916 neon_load_reg32(tmp
, a
->vm
* 2 + 1);
917 store_reg(s
, a
->rt2
, tmp
);
920 tmp
= load_reg(s
, a
->rt
);
921 neon_store_reg32(tmp
, a
->vm
* 2);
922 tcg_temp_free_i32(tmp
);
923 tmp
= load_reg(s
, a
->rt2
);
924 neon_store_reg32(tmp
, a
->vm
* 2 + 1);
925 tcg_temp_free_i32(tmp
);
931 static bool trans_VLDR_VSTR_sp(DisasContext
*s
, arg_VLDR_VSTR_sp
*a
)
936 if (!vfp_access_check(s
)) {
940 offset
= a
->imm
<< 2;
945 /* For thumb, use of PC is UNPREDICTABLE. */
946 addr
= add_reg_for_lit(s
, a
->rn
, offset
);
947 tmp
= tcg_temp_new_i32();
949 gen_aa32_ld32u(s
, tmp
, addr
, get_mem_index(s
));
950 neon_store_reg32(tmp
, a
->vd
);
952 neon_load_reg32(tmp
, a
->vd
);
953 gen_aa32_st32(s
, tmp
, addr
, get_mem_index(s
));
955 tcg_temp_free_i32(tmp
);
956 tcg_temp_free_i32(addr
);
961 static bool trans_VLDR_VSTR_dp(DisasContext
*s
, arg_VLDR_VSTR_dp
*a
)
967 /* UNDEF accesses to D16-D31 if they don't exist */
968 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vd
& 0x10)) {
972 if (!vfp_access_check(s
)) {
976 offset
= a
->imm
<< 2;
981 /* For thumb, use of PC is UNPREDICTABLE. */
982 addr
= add_reg_for_lit(s
, a
->rn
, offset
);
983 tmp
= tcg_temp_new_i64();
985 gen_aa32_ld64(s
, tmp
, addr
, get_mem_index(s
));
986 neon_store_reg64(tmp
, a
->vd
);
988 neon_load_reg64(tmp
, a
->vd
);
989 gen_aa32_st64(s
, tmp
, addr
, get_mem_index(s
));
991 tcg_temp_free_i64(tmp
);
992 tcg_temp_free_i32(addr
);
997 static bool trans_VLDM_VSTM_sp(DisasContext
*s
, arg_VLDM_VSTM_sp
*a
)
1005 if (n
== 0 || (a
->vd
+ n
) > 32) {
1007 * UNPREDICTABLE cases for bad immediates: we choose to
1008 * UNDEF to avoid generating huge numbers of TCG ops
1012 if (a
->rn
== 15 && a
->w
) {
1013 /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1017 if (!vfp_access_check(s
)) {
1021 /* For thumb, use of PC is UNPREDICTABLE. */
1022 addr
= add_reg_for_lit(s
, a
->rn
, 0);
1025 tcg_gen_addi_i32(addr
, addr
, -(a
->imm
<< 2));
1028 if (s
->v8m_stackcheck
&& a
->rn
== 13 && a
->w
) {
1030 * Here 'addr' is the lowest address we will store to,
1031 * and is either the old SP (if post-increment) or
1032 * the new SP (if pre-decrement). For post-increment
1033 * where the old value is below the limit and the new
1034 * value is above, it is UNKNOWN whether the limit check
1035 * triggers; we choose to trigger.
1037 gen_helper_v8m_stackcheck(cpu_env
, addr
);
1041 tmp
= tcg_temp_new_i32();
1042 for (i
= 0; i
< n
; i
++) {
1045 gen_aa32_ld32u(s
, tmp
, addr
, get_mem_index(s
));
1046 neon_store_reg32(tmp
, a
->vd
+ i
);
1049 neon_load_reg32(tmp
, a
->vd
+ i
);
1050 gen_aa32_st32(s
, tmp
, addr
, get_mem_index(s
));
1052 tcg_gen_addi_i32(addr
, addr
, offset
);
1054 tcg_temp_free_i32(tmp
);
1058 offset
= -offset
* n
;
1059 tcg_gen_addi_i32(addr
, addr
, offset
);
1061 store_reg(s
, a
->rn
, addr
);
1063 tcg_temp_free_i32(addr
);
1069 static bool trans_VLDM_VSTM_dp(DisasContext
*s
, arg_VLDM_VSTM_dp
*a
)
1078 if (n
== 0 || (a
->vd
+ n
) > 32 || n
> 16) {
1080 * UNPREDICTABLE cases for bad immediates: we choose to
1081 * UNDEF to avoid generating huge numbers of TCG ops
1085 if (a
->rn
== 15 && a
->w
) {
1086 /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1090 /* UNDEF accesses to D16-D31 if they don't exist */
1091 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vd
+ n
) > 16) {
1095 if (!vfp_access_check(s
)) {
1099 /* For thumb, use of PC is UNPREDICTABLE. */
1100 addr
= add_reg_for_lit(s
, a
->rn
, 0);
1103 tcg_gen_addi_i32(addr
, addr
, -(a
->imm
<< 2));
1106 if (s
->v8m_stackcheck
&& a
->rn
== 13 && a
->w
) {
1108 * Here 'addr' is the lowest address we will store to,
1109 * and is either the old SP (if post-increment) or
1110 * the new SP (if pre-decrement). For post-increment
1111 * where the old value is below the limit and the new
1112 * value is above, it is UNKNOWN whether the limit check
1113 * triggers; we choose to trigger.
1115 gen_helper_v8m_stackcheck(cpu_env
, addr
);
1119 tmp
= tcg_temp_new_i64();
1120 for (i
= 0; i
< n
; i
++) {
1123 gen_aa32_ld64(s
, tmp
, addr
, get_mem_index(s
));
1124 neon_store_reg64(tmp
, a
->vd
+ i
);
1127 neon_load_reg64(tmp
, a
->vd
+ i
);
1128 gen_aa32_st64(s
, tmp
, addr
, get_mem_index(s
));
1130 tcg_gen_addi_i32(addr
, addr
, offset
);
1132 tcg_temp_free_i64(tmp
);
1136 offset
= -offset
* n
;
1137 } else if (a
->imm
& 1) {
1144 tcg_gen_addi_i32(addr
, addr
, offset
);
1146 store_reg(s
, a
->rn
, addr
);
1148 tcg_temp_free_i32(addr
);
1155 * Types for callbacks for do_vfp_3op_sp() and do_vfp_3op_dp().
1156 * The callback should emit code to write a value to vd. If
1157 * do_vfp_3op_{sp,dp}() was passed reads_vd then the TCGv vd
1158 * will contain the old value of the relevant VFP register;
1159 * otherwise it must be written to only.
1161 typedef void VFPGen3OpSPFn(TCGv_i32 vd
,
1162 TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
);
1163 typedef void VFPGen3OpDPFn(TCGv_i64 vd
,
1164 TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
);
1167 * Types for callbacks for do_vfp_2op_sp() and do_vfp_2op_dp().
1168 * The callback should emit code to write a value to vd (which
1169 * should be written to only).
1171 typedef void VFPGen2OpSPFn(TCGv_i32 vd
, TCGv_i32 vm
);
1172 typedef void VFPGen2OpDPFn(TCGv_i64 vd
, TCGv_i64 vm
);
1175 * Return true if the specified S reg is in a scalar bank
1176 * (ie if it is s0..s7)
1178 static inline bool vfp_sreg_is_scalar(int reg
)
1180 return (reg
& 0x18) == 0;
1184 * Return true if the specified D reg is in a scalar bank
1185 * (ie if it is d0..d3 or d16..d19)
1187 static inline bool vfp_dreg_is_scalar(int reg
)
1189 return (reg
& 0xc) == 0;
1193 * Advance the S reg number forwards by delta within its bank
1194 * (ie increment the low 3 bits but leave the rest the same)
1196 static inline int vfp_advance_sreg(int reg
, int delta
)
1198 return ((reg
+ delta
) & 0x7) | (reg
& ~0x7);
1202 * Advance the D reg number forwards by delta within its bank
1203 * (ie increment the low 2 bits but leave the rest the same)
1205 static inline int vfp_advance_dreg(int reg
, int delta
)
1207 return ((reg
+ delta
) & 0x3) | (reg
& ~0x3);
1211 * Perform a 3-operand VFP data processing instruction. fn is the
1212 * callback to do the actual operation; this function deals with the
1213 * code to handle looping around for VFP vector processing.
1215 static bool do_vfp_3op_sp(DisasContext
*s
, VFPGen3OpSPFn
*fn
,
1216 int vd
, int vn
, int vm
, bool reads_vd
)
1218 uint32_t delta_m
= 0;
1219 uint32_t delta_d
= 0;
1220 int veclen
= s
->vec_len
;
1221 TCGv_i32 f0
, f1
, fd
;
1224 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
1225 (veclen
!= 0 || s
->vec_stride
!= 0)) {
1229 if (!vfp_access_check(s
)) {
1234 /* Figure out what type of vector operation this is. */
1235 if (vfp_sreg_is_scalar(vd
)) {
1239 delta_d
= s
->vec_stride
+ 1;
1241 if (vfp_sreg_is_scalar(vm
)) {
1242 /* mixed scalar/vector */
1251 f0
= tcg_temp_new_i32();
1252 f1
= tcg_temp_new_i32();
1253 fd
= tcg_temp_new_i32();
1254 fpst
= get_fpstatus_ptr(0);
1256 neon_load_reg32(f0
, vn
);
1257 neon_load_reg32(f1
, vm
);
1261 neon_load_reg32(fd
, vd
);
1263 fn(fd
, f0
, f1
, fpst
);
1264 neon_store_reg32(fd
, vd
);
1270 /* Set up the operands for the next iteration */
1272 vd
= vfp_advance_sreg(vd
, delta_d
);
1273 vn
= vfp_advance_sreg(vn
, delta_d
);
1274 neon_load_reg32(f0
, vn
);
1276 vm
= vfp_advance_sreg(vm
, delta_m
);
1277 neon_load_reg32(f1
, vm
);
1281 tcg_temp_free_i32(f0
);
1282 tcg_temp_free_i32(f1
);
1283 tcg_temp_free_i32(fd
);
1284 tcg_temp_free_ptr(fpst
);
1289 static bool do_vfp_3op_dp(DisasContext
*s
, VFPGen3OpDPFn
*fn
,
1290 int vd
, int vn
, int vm
, bool reads_vd
)
1292 uint32_t delta_m
= 0;
1293 uint32_t delta_d
= 0;
1294 int veclen
= s
->vec_len
;
1295 TCGv_i64 f0
, f1
, fd
;
1298 /* UNDEF accesses to D16-D31 if they don't exist */
1299 if (!dc_isar_feature(aa32_fp_d32
, s
) && ((vd
| vn
| vm
) & 0x10)) {
1303 if (!dc_isar_feature(aa32_fpdp
, s
)) {
1307 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
1308 (veclen
!= 0 || s
->vec_stride
!= 0)) {
1312 if (!vfp_access_check(s
)) {
1317 /* Figure out what type of vector operation this is. */
1318 if (vfp_dreg_is_scalar(vd
)) {
1322 delta_d
= (s
->vec_stride
>> 1) + 1;
1324 if (vfp_dreg_is_scalar(vm
)) {
1325 /* mixed scalar/vector */
1334 f0
= tcg_temp_new_i64();
1335 f1
= tcg_temp_new_i64();
1336 fd
= tcg_temp_new_i64();
1337 fpst
= get_fpstatus_ptr(0);
1339 neon_load_reg64(f0
, vn
);
1340 neon_load_reg64(f1
, vm
);
1344 neon_load_reg64(fd
, vd
);
1346 fn(fd
, f0
, f1
, fpst
);
1347 neon_store_reg64(fd
, vd
);
1352 /* Set up the operands for the next iteration */
1354 vd
= vfp_advance_dreg(vd
, delta_d
);
1355 vn
= vfp_advance_dreg(vn
, delta_d
);
1356 neon_load_reg64(f0
, vn
);
1358 vm
= vfp_advance_dreg(vm
, delta_m
);
1359 neon_load_reg64(f1
, vm
);
1363 tcg_temp_free_i64(f0
);
1364 tcg_temp_free_i64(f1
);
1365 tcg_temp_free_i64(fd
);
1366 tcg_temp_free_ptr(fpst
);
1371 static bool do_vfp_2op_sp(DisasContext
*s
, VFPGen2OpSPFn
*fn
, int vd
, int vm
)
1373 uint32_t delta_m
= 0;
1374 uint32_t delta_d
= 0;
1375 int veclen
= s
->vec_len
;
1378 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
1379 (veclen
!= 0 || s
->vec_stride
!= 0)) {
1383 if (!vfp_access_check(s
)) {
1388 /* Figure out what type of vector operation this is. */
1389 if (vfp_sreg_is_scalar(vd
)) {
1393 delta_d
= s
->vec_stride
+ 1;
1395 if (vfp_sreg_is_scalar(vm
)) {
1396 /* mixed scalar/vector */
1405 f0
= tcg_temp_new_i32();
1406 fd
= tcg_temp_new_i32();
1408 neon_load_reg32(f0
, vm
);
1412 neon_store_reg32(fd
, vd
);
1419 /* single source one-many */
1421 vd
= vfp_advance_sreg(vd
, delta_d
);
1422 neon_store_reg32(fd
, vd
);
1427 /* Set up the operands for the next iteration */
1429 vd
= vfp_advance_sreg(vd
, delta_d
);
1430 vm
= vfp_advance_sreg(vm
, delta_m
);
1431 neon_load_reg32(f0
, vm
);
1434 tcg_temp_free_i32(f0
);
1435 tcg_temp_free_i32(fd
);
1440 static bool do_vfp_2op_dp(DisasContext
*s
, VFPGen2OpDPFn
*fn
, int vd
, int vm
)
1442 uint32_t delta_m
= 0;
1443 uint32_t delta_d
= 0;
1444 int veclen
= s
->vec_len
;
1447 /* UNDEF accesses to D16-D31 if they don't exist */
1448 if (!dc_isar_feature(aa32_fp_d32
, s
) && ((vd
| vm
) & 0x10)) {
1452 if (!dc_isar_feature(aa32_fpdp
, s
)) {
1456 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
1457 (veclen
!= 0 || s
->vec_stride
!= 0)) {
1461 if (!vfp_access_check(s
)) {
1466 /* Figure out what type of vector operation this is. */
1467 if (vfp_dreg_is_scalar(vd
)) {
1471 delta_d
= (s
->vec_stride
>> 1) + 1;
1473 if (vfp_dreg_is_scalar(vm
)) {
1474 /* mixed scalar/vector */
1483 f0
= tcg_temp_new_i64();
1484 fd
= tcg_temp_new_i64();
1486 neon_load_reg64(f0
, vm
);
1490 neon_store_reg64(fd
, vd
);
1497 /* single source one-many */
1499 vd
= vfp_advance_dreg(vd
, delta_d
);
1500 neon_store_reg64(fd
, vd
);
1505 /* Set up the operands for the next iteration */
1507 vd
= vfp_advance_dreg(vd
, delta_d
);
1508 vd
= vfp_advance_dreg(vm
, delta_m
);
1509 neon_load_reg64(f0
, vm
);
1512 tcg_temp_free_i64(f0
);
1513 tcg_temp_free_i64(fd
);
1518 static void gen_VMLA_sp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1520 /* Note that order of inputs to the add matters for NaNs */
1521 TCGv_i32 tmp
= tcg_temp_new_i32();
1523 gen_helper_vfp_muls(tmp
, vn
, vm
, fpst
);
1524 gen_helper_vfp_adds(vd
, vd
, tmp
, fpst
);
1525 tcg_temp_free_i32(tmp
);
1528 static bool trans_VMLA_sp(DisasContext
*s
, arg_VMLA_sp
*a
)
1530 return do_vfp_3op_sp(s
, gen_VMLA_sp
, a
->vd
, a
->vn
, a
->vm
, true);
1533 static void gen_VMLA_dp(TCGv_i64 vd
, TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
)
1535 /* Note that order of inputs to the add matters for NaNs */
1536 TCGv_i64 tmp
= tcg_temp_new_i64();
1538 gen_helper_vfp_muld(tmp
, vn
, vm
, fpst
);
1539 gen_helper_vfp_addd(vd
, vd
, tmp
, fpst
);
1540 tcg_temp_free_i64(tmp
);
1543 static bool trans_VMLA_dp(DisasContext
*s
, arg_VMLA_dp
*a
)
1545 return do_vfp_3op_dp(s
, gen_VMLA_dp
, a
->vd
, a
->vn
, a
->vm
, true);
1548 static void gen_VMLS_sp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1551 * VMLS: vd = vd + -(vn * vm)
1552 * Note that order of inputs to the add matters for NaNs.
1554 TCGv_i32 tmp
= tcg_temp_new_i32();
1556 gen_helper_vfp_muls(tmp
, vn
, vm
, fpst
);
1557 gen_helper_vfp_negs(tmp
, tmp
);
1558 gen_helper_vfp_adds(vd
, vd
, tmp
, fpst
);
1559 tcg_temp_free_i32(tmp
);
1562 static bool trans_VMLS_sp(DisasContext
*s
, arg_VMLS_sp
*a
)
1564 return do_vfp_3op_sp(s
, gen_VMLS_sp
, a
->vd
, a
->vn
, a
->vm
, true);
1567 static void gen_VMLS_dp(TCGv_i64 vd
, TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
)
1570 * VMLS: vd = vd + -(vn * vm)
1571 * Note that order of inputs to the add matters for NaNs.
1573 TCGv_i64 tmp
= tcg_temp_new_i64();
1575 gen_helper_vfp_muld(tmp
, vn
, vm
, fpst
);
1576 gen_helper_vfp_negd(tmp
, tmp
);
1577 gen_helper_vfp_addd(vd
, vd
, tmp
, fpst
);
1578 tcg_temp_free_i64(tmp
);
1581 static bool trans_VMLS_dp(DisasContext
*s
, arg_VMLS_dp
*a
)
1583 return do_vfp_3op_dp(s
, gen_VMLS_dp
, a
->vd
, a
->vn
, a
->vm
, true);
1586 static void gen_VNMLS_sp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1589 * VNMLS: -fd + (fn * fm)
1590 * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1591 * plausible looking simplifications because this will give wrong results
1594 TCGv_i32 tmp
= tcg_temp_new_i32();
1596 gen_helper_vfp_muls(tmp
, vn
, vm
, fpst
);
1597 gen_helper_vfp_negs(vd
, vd
);
1598 gen_helper_vfp_adds(vd
, vd
, tmp
, fpst
);
1599 tcg_temp_free_i32(tmp
);
1602 static bool trans_VNMLS_sp(DisasContext
*s
, arg_VNMLS_sp
*a
)
1604 return do_vfp_3op_sp(s
, gen_VNMLS_sp
, a
->vd
, a
->vn
, a
->vm
, true);
1607 static void gen_VNMLS_dp(TCGv_i64 vd
, TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
)
1610 * VNMLS: -fd + (fn * fm)
1611 * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1612 * plausible looking simplifications because this will give wrong results
1615 TCGv_i64 tmp
= tcg_temp_new_i64();
1617 gen_helper_vfp_muld(tmp
, vn
, vm
, fpst
);
1618 gen_helper_vfp_negd(vd
, vd
);
1619 gen_helper_vfp_addd(vd
, vd
, tmp
, fpst
);
1620 tcg_temp_free_i64(tmp
);
1623 static bool trans_VNMLS_dp(DisasContext
*s
, arg_VNMLS_dp
*a
)
1625 return do_vfp_3op_dp(s
, gen_VNMLS_dp
, a
->vd
, a
->vn
, a
->vm
, true);
1628 static void gen_VNMLA_sp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1630 /* VNMLA: -fd + -(fn * fm) */
1631 TCGv_i32 tmp
= tcg_temp_new_i32();
1633 gen_helper_vfp_muls(tmp
, vn
, vm
, fpst
);
1634 gen_helper_vfp_negs(tmp
, tmp
);
1635 gen_helper_vfp_negs(vd
, vd
);
1636 gen_helper_vfp_adds(vd
, vd
, tmp
, fpst
);
1637 tcg_temp_free_i32(tmp
);
1640 static bool trans_VNMLA_sp(DisasContext
*s
, arg_VNMLA_sp
*a
)
1642 return do_vfp_3op_sp(s
, gen_VNMLA_sp
, a
->vd
, a
->vn
, a
->vm
, true);
1645 static void gen_VNMLA_dp(TCGv_i64 vd
, TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
)
1647 /* VNMLA: -fd + (fn * fm) */
1648 TCGv_i64 tmp
= tcg_temp_new_i64();
1650 gen_helper_vfp_muld(tmp
, vn
, vm
, fpst
);
1651 gen_helper_vfp_negd(tmp
, tmp
);
1652 gen_helper_vfp_negd(vd
, vd
);
1653 gen_helper_vfp_addd(vd
, vd
, tmp
, fpst
);
1654 tcg_temp_free_i64(tmp
);
1657 static bool trans_VNMLA_dp(DisasContext
*s
, arg_VNMLA_dp
*a
)
1659 return do_vfp_3op_dp(s
, gen_VNMLA_dp
, a
->vd
, a
->vn
, a
->vm
, true);
1662 static bool trans_VMUL_sp(DisasContext
*s
, arg_VMUL_sp
*a
)
1664 return do_vfp_3op_sp(s
, gen_helper_vfp_muls
, a
->vd
, a
->vn
, a
->vm
, false);
1667 static bool trans_VMUL_dp(DisasContext
*s
, arg_VMUL_dp
*a
)
1669 return do_vfp_3op_dp(s
, gen_helper_vfp_muld
, a
->vd
, a
->vn
, a
->vm
, false);
1672 static void gen_VNMUL_sp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1674 /* VNMUL: -(fn * fm) */
1675 gen_helper_vfp_muls(vd
, vn
, vm
, fpst
);
1676 gen_helper_vfp_negs(vd
, vd
);
1679 static bool trans_VNMUL_sp(DisasContext
*s
, arg_VNMUL_sp
*a
)
1681 return do_vfp_3op_sp(s
, gen_VNMUL_sp
, a
->vd
, a
->vn
, a
->vm
, false);
1684 static void gen_VNMUL_dp(TCGv_i64 vd
, TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
)
1686 /* VNMUL: -(fn * fm) */
1687 gen_helper_vfp_muld(vd
, vn
, vm
, fpst
);
1688 gen_helper_vfp_negd(vd
, vd
);
1691 static bool trans_VNMUL_dp(DisasContext
*s
, arg_VNMUL_dp
*a
)
1693 return do_vfp_3op_dp(s
, gen_VNMUL_dp
, a
->vd
, a
->vn
, a
->vm
, false);
1696 static bool trans_VADD_sp(DisasContext
*s
, arg_VADD_sp
*a
)
1698 return do_vfp_3op_sp(s
, gen_helper_vfp_adds
, a
->vd
, a
->vn
, a
->vm
, false);
1701 static bool trans_VADD_dp(DisasContext
*s
, arg_VADD_dp
*a
)
1703 return do_vfp_3op_dp(s
, gen_helper_vfp_addd
, a
->vd
, a
->vn
, a
->vm
, false);
1706 static bool trans_VSUB_sp(DisasContext
*s
, arg_VSUB_sp
*a
)
1708 return do_vfp_3op_sp(s
, gen_helper_vfp_subs
, a
->vd
, a
->vn
, a
->vm
, false);
1711 static bool trans_VSUB_dp(DisasContext
*s
, arg_VSUB_dp
*a
)
1713 return do_vfp_3op_dp(s
, gen_helper_vfp_subd
, a
->vd
, a
->vn
, a
->vm
, false);
1716 static bool trans_VDIV_sp(DisasContext
*s
, arg_VDIV_sp
*a
)
1718 return do_vfp_3op_sp(s
, gen_helper_vfp_divs
, a
->vd
, a
->vn
, a
->vm
, false);
1721 static bool trans_VDIV_dp(DisasContext
*s
, arg_VDIV_dp
*a
)
1723 return do_vfp_3op_dp(s
, gen_helper_vfp_divd
, a
->vd
, a
->vn
, a
->vm
, false);
1726 static bool trans_VFM_sp(DisasContext
*s
, arg_VFM_sp
*a
)
1729 * VFNMA : fd = muladd(-fd, fn, fm)
1730 * VFNMS : fd = muladd(-fd, -fn, fm)
1731 * VFMA : fd = muladd( fd, fn, fm)
1732 * VFMS : fd = muladd( fd, -fn, fm)
1734 * These are fused multiply-add, and must be done as one floating
1735 * point operation with no rounding between the multiplication and
1736 * addition steps. NB that doing the negations here as separate
1737 * steps is correct : an input NaN should come out with its sign
1738 * bit flipped if it is a negated-input.
1741 TCGv_i32 vn
, vm
, vd
;
1744 * Present in VFPv4 only.
1745 * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
1746 * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
1748 if (!arm_dc_feature(s
, ARM_FEATURE_VFP4
) ||
1749 (s
->vec_len
!= 0 || s
->vec_stride
!= 0)) {
1753 if (!vfp_access_check(s
)) {
1757 vn
= tcg_temp_new_i32();
1758 vm
= tcg_temp_new_i32();
1759 vd
= tcg_temp_new_i32();
1761 neon_load_reg32(vn
, a
->vn
);
1762 neon_load_reg32(vm
, a
->vm
);
1765 gen_helper_vfp_negs(vn
, vn
);
1767 neon_load_reg32(vd
, a
->vd
);
1770 gen_helper_vfp_negs(vd
, vd
);
1772 fpst
= get_fpstatus_ptr(0);
1773 gen_helper_vfp_muladds(vd
, vn
, vm
, vd
, fpst
);
1774 neon_store_reg32(vd
, a
->vd
);
1776 tcg_temp_free_ptr(fpst
);
1777 tcg_temp_free_i32(vn
);
1778 tcg_temp_free_i32(vm
);
1779 tcg_temp_free_i32(vd
);
1784 static bool trans_VFM_dp(DisasContext
*s
, arg_VFM_dp
*a
)
1787 * VFNMA : fd = muladd(-fd, fn, fm)
1788 * VFNMS : fd = muladd(-fd, -fn, fm)
1789 * VFMA : fd = muladd( fd, fn, fm)
1790 * VFMS : fd = muladd( fd, -fn, fm)
1792 * These are fused multiply-add, and must be done as one floating
1793 * point operation with no rounding between the multiplication and
1794 * addition steps. NB that doing the negations here as separate
1795 * steps is correct : an input NaN should come out with its sign
1796 * bit flipped if it is a negated-input.
1799 TCGv_i64 vn
, vm
, vd
;
1802 * Present in VFPv4 only.
1803 * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
1804 * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
1806 if (!arm_dc_feature(s
, ARM_FEATURE_VFP4
) ||
1807 (s
->vec_len
!= 0 || s
->vec_stride
!= 0)) {
1811 /* UNDEF accesses to D16-D31 if they don't exist. */
1812 if (!dc_isar_feature(aa32_fp_d32
, s
) && ((a
->vd
| a
->vn
| a
->vm
) & 0x10)) {
1816 if (!dc_isar_feature(aa32_fpdp
, s
)) {
1820 if (!vfp_access_check(s
)) {
1824 vn
= tcg_temp_new_i64();
1825 vm
= tcg_temp_new_i64();
1826 vd
= tcg_temp_new_i64();
1828 neon_load_reg64(vn
, a
->vn
);
1829 neon_load_reg64(vm
, a
->vm
);
1832 gen_helper_vfp_negd(vn
, vn
);
1834 neon_load_reg64(vd
, a
->vd
);
1837 gen_helper_vfp_negd(vd
, vd
);
1839 fpst
= get_fpstatus_ptr(0);
1840 gen_helper_vfp_muladdd(vd
, vn
, vm
, vd
, fpst
);
1841 neon_store_reg64(vd
, a
->vd
);
1843 tcg_temp_free_ptr(fpst
);
1844 tcg_temp_free_i64(vn
);
1845 tcg_temp_free_i64(vm
);
1846 tcg_temp_free_i64(vd
);
1851 static bool trans_VMOV_imm_sp(DisasContext
*s
, arg_VMOV_imm_sp
*a
)
1853 uint32_t delta_d
= 0;
1854 int veclen
= s
->vec_len
;
1860 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
1861 (veclen
!= 0 || s
->vec_stride
!= 0)) {
1865 if (!arm_dc_feature(s
, ARM_FEATURE_VFP3
)) {
1869 if (!vfp_access_check(s
)) {
1874 /* Figure out what type of vector operation this is. */
1875 if (vfp_sreg_is_scalar(vd
)) {
1879 delta_d
= s
->vec_stride
+ 1;
1883 fd
= tcg_const_i32(vfp_expand_imm(MO_32
, a
->imm
));
1886 neon_store_reg32(fd
, vd
);
1892 /* Set up the operands for the next iteration */
1894 vd
= vfp_advance_sreg(vd
, delta_d
);
1897 tcg_temp_free_i32(fd
);
1901 static bool trans_VMOV_imm_dp(DisasContext
*s
, arg_VMOV_imm_dp
*a
)
1903 uint32_t delta_d
= 0;
1904 int veclen
= s
->vec_len
;
1910 /* UNDEF accesses to D16-D31 if they don't exist. */
1911 if (!dc_isar_feature(aa32_fp_d32
, s
) && (vd
& 0x10)) {
1915 if (!dc_isar_feature(aa32_fpdp
, s
)) {
1919 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
1920 (veclen
!= 0 || s
->vec_stride
!= 0)) {
1924 if (!arm_dc_feature(s
, ARM_FEATURE_VFP3
)) {
1928 if (!vfp_access_check(s
)) {
1933 /* Figure out what type of vector operation this is. */
1934 if (vfp_dreg_is_scalar(vd
)) {
1938 delta_d
= (s
->vec_stride
>> 1) + 1;
1942 fd
= tcg_const_i64(vfp_expand_imm(MO_64
, a
->imm
));
1945 neon_store_reg64(fd
, vd
);
1951 /* Set up the operands for the next iteration */
1953 vd
= vfp_advance_dreg(vd
, delta_d
);
1956 tcg_temp_free_i64(fd
);
1960 static bool trans_VMOV_reg_sp(DisasContext
*s
, arg_VMOV_reg_sp
*a
)
1962 return do_vfp_2op_sp(s
, tcg_gen_mov_i32
, a
->vd
, a
->vm
);
1965 static bool trans_VMOV_reg_dp(DisasContext
*s
, arg_VMOV_reg_dp
*a
)
1967 return do_vfp_2op_dp(s
, tcg_gen_mov_i64
, a
->vd
, a
->vm
);
1970 static bool trans_VABS_sp(DisasContext
*s
, arg_VABS_sp
*a
)
1972 return do_vfp_2op_sp(s
, gen_helper_vfp_abss
, a
->vd
, a
->vm
);
1975 static bool trans_VABS_dp(DisasContext
*s
, arg_VABS_dp
*a
)
1977 return do_vfp_2op_dp(s
, gen_helper_vfp_absd
, a
->vd
, a
->vm
);
1980 static bool trans_VNEG_sp(DisasContext
*s
, arg_VNEG_sp
*a
)
1982 return do_vfp_2op_sp(s
, gen_helper_vfp_negs
, a
->vd
, a
->vm
);
1985 static bool trans_VNEG_dp(DisasContext
*s
, arg_VNEG_dp
*a
)
1987 return do_vfp_2op_dp(s
, gen_helper_vfp_negd
, a
->vd
, a
->vm
);
1990 static void gen_VSQRT_sp(TCGv_i32 vd
, TCGv_i32 vm
)
1992 gen_helper_vfp_sqrts(vd
, vm
, cpu_env
);
1995 static bool trans_VSQRT_sp(DisasContext
*s
, arg_VSQRT_sp
*a
)
1997 return do_vfp_2op_sp(s
, gen_VSQRT_sp
, a
->vd
, a
->vm
);
2000 static void gen_VSQRT_dp(TCGv_i64 vd
, TCGv_i64 vm
)
2002 gen_helper_vfp_sqrtd(vd
, vm
, cpu_env
);
2005 static bool trans_VSQRT_dp(DisasContext
*s
, arg_VSQRT_dp
*a
)
2007 return do_vfp_2op_dp(s
, gen_VSQRT_dp
, a
->vd
, a
->vm
);
2010 static bool trans_VCMP_sp(DisasContext
*s
, arg_VCMP_sp
*a
)
2014 /* Vm/M bits must be zero for the Z variant */
2015 if (a
->z
&& a
->vm
!= 0) {
2019 if (!vfp_access_check(s
)) {
2023 vd
= tcg_temp_new_i32();
2024 vm
= tcg_temp_new_i32();
2026 neon_load_reg32(vd
, a
->vd
);
2028 tcg_gen_movi_i32(vm
, 0);
2030 neon_load_reg32(vm
, a
->vm
);
2034 gen_helper_vfp_cmpes(vd
, vm
, cpu_env
);
2036 gen_helper_vfp_cmps(vd
, vm
, cpu_env
);
2039 tcg_temp_free_i32(vd
);
2040 tcg_temp_free_i32(vm
);
2045 static bool trans_VCMP_dp(DisasContext
*s
, arg_VCMP_dp
*a
)
2049 /* Vm/M bits must be zero for the Z variant */
2050 if (a
->z
&& a
->vm
!= 0) {
2054 /* UNDEF accesses to D16-D31 if they don't exist. */
2055 if (!dc_isar_feature(aa32_fp_d32
, s
) && ((a
->vd
| a
->vm
) & 0x10)) {
2059 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2063 if (!vfp_access_check(s
)) {
2067 vd
= tcg_temp_new_i64();
2068 vm
= tcg_temp_new_i64();
2070 neon_load_reg64(vd
, a
->vd
);
2072 tcg_gen_movi_i64(vm
, 0);
2074 neon_load_reg64(vm
, a
->vm
);
2078 gen_helper_vfp_cmped(vd
, vm
, cpu_env
);
2080 gen_helper_vfp_cmpd(vd
, vm
, cpu_env
);
2083 tcg_temp_free_i64(vd
);
2084 tcg_temp_free_i64(vm
);
2089 static bool trans_VCVT_f32_f16(DisasContext
*s
, arg_VCVT_f32_f16
*a
)
2095 if (!dc_isar_feature(aa32_fp16_spconv
, s
)) {
2099 if (!vfp_access_check(s
)) {
2103 fpst
= get_fpstatus_ptr(false);
2104 ahp_mode
= get_ahp_flag();
2105 tmp
= tcg_temp_new_i32();
2106 /* The T bit tells us if we want the low or high 16 bits of Vm */
2107 tcg_gen_ld16u_i32(tmp
, cpu_env
, vfp_f16_offset(a
->vm
, a
->t
));
2108 gen_helper_vfp_fcvt_f16_to_f32(tmp
, tmp
, fpst
, ahp_mode
);
2109 neon_store_reg32(tmp
, a
->vd
);
2110 tcg_temp_free_i32(ahp_mode
);
2111 tcg_temp_free_ptr(fpst
);
2112 tcg_temp_free_i32(tmp
);
2116 static bool trans_VCVT_f64_f16(DisasContext
*s
, arg_VCVT_f64_f16
*a
)
2123 if (!dc_isar_feature(aa32_fp16_dpconv
, s
)) {
2127 /* UNDEF accesses to D16-D31 if they don't exist. */
2128 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vd
& 0x10)) {
2132 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2136 if (!vfp_access_check(s
)) {
2140 fpst
= get_fpstatus_ptr(false);
2141 ahp_mode
= get_ahp_flag();
2142 tmp
= tcg_temp_new_i32();
2143 /* The T bit tells us if we want the low or high 16 bits of Vm */
2144 tcg_gen_ld16u_i32(tmp
, cpu_env
, vfp_f16_offset(a
->vm
, a
->t
));
2145 vd
= tcg_temp_new_i64();
2146 gen_helper_vfp_fcvt_f16_to_f64(vd
, tmp
, fpst
, ahp_mode
);
2147 neon_store_reg64(vd
, a
->vd
);
2148 tcg_temp_free_i32(ahp_mode
);
2149 tcg_temp_free_ptr(fpst
);
2150 tcg_temp_free_i32(tmp
);
2151 tcg_temp_free_i64(vd
);
2155 static bool trans_VCVT_f16_f32(DisasContext
*s
, arg_VCVT_f16_f32
*a
)
2161 if (!dc_isar_feature(aa32_fp16_spconv
, s
)) {
2165 if (!vfp_access_check(s
)) {
2169 fpst
= get_fpstatus_ptr(false);
2170 ahp_mode
= get_ahp_flag();
2171 tmp
= tcg_temp_new_i32();
2173 neon_load_reg32(tmp
, a
->vm
);
2174 gen_helper_vfp_fcvt_f32_to_f16(tmp
, tmp
, fpst
, ahp_mode
);
2175 tcg_gen_st16_i32(tmp
, cpu_env
, vfp_f16_offset(a
->vd
, a
->t
));
2176 tcg_temp_free_i32(ahp_mode
);
2177 tcg_temp_free_ptr(fpst
);
2178 tcg_temp_free_i32(tmp
);
2182 static bool trans_VCVT_f16_f64(DisasContext
*s
, arg_VCVT_f16_f64
*a
)
2189 if (!dc_isar_feature(aa32_fp16_dpconv
, s
)) {
2193 /* UNDEF accesses to D16-D31 if they don't exist. */
2194 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vm
& 0x10)) {
2198 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2202 if (!vfp_access_check(s
)) {
2206 fpst
= get_fpstatus_ptr(false);
2207 ahp_mode
= get_ahp_flag();
2208 tmp
= tcg_temp_new_i32();
2209 vm
= tcg_temp_new_i64();
2211 neon_load_reg64(vm
, a
->vm
);
2212 gen_helper_vfp_fcvt_f64_to_f16(tmp
, vm
, fpst
, ahp_mode
);
2213 tcg_temp_free_i64(vm
);
2214 tcg_gen_st16_i32(tmp
, cpu_env
, vfp_f16_offset(a
->vd
, a
->t
));
2215 tcg_temp_free_i32(ahp_mode
);
2216 tcg_temp_free_ptr(fpst
);
2217 tcg_temp_free_i32(tmp
);
2221 static bool trans_VRINTR_sp(DisasContext
*s
, arg_VRINTR_sp
*a
)
2226 if (!dc_isar_feature(aa32_vrint
, s
)) {
2230 if (!vfp_access_check(s
)) {
2234 tmp
= tcg_temp_new_i32();
2235 neon_load_reg32(tmp
, a
->vm
);
2236 fpst
= get_fpstatus_ptr(false);
2237 gen_helper_rints(tmp
, tmp
, fpst
);
2238 neon_store_reg32(tmp
, a
->vd
);
2239 tcg_temp_free_ptr(fpst
);
2240 tcg_temp_free_i32(tmp
);
2244 static bool trans_VRINTR_dp(DisasContext
*s
, arg_VRINTR_dp
*a
)
2249 if (!dc_isar_feature(aa32_vrint
, s
)) {
2253 /* UNDEF accesses to D16-D31 if they don't exist. */
2254 if (!dc_isar_feature(aa32_fp_d32
, s
) && ((a
->vd
| a
->vm
) & 0x10)) {
2258 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2262 if (!vfp_access_check(s
)) {
2266 tmp
= tcg_temp_new_i64();
2267 neon_load_reg64(tmp
, a
->vm
);
2268 fpst
= get_fpstatus_ptr(false);
2269 gen_helper_rintd(tmp
, tmp
, fpst
);
2270 neon_store_reg64(tmp
, a
->vd
);
2271 tcg_temp_free_ptr(fpst
);
2272 tcg_temp_free_i64(tmp
);
2276 static bool trans_VRINTZ_sp(DisasContext
*s
, arg_VRINTZ_sp
*a
)
2282 if (!dc_isar_feature(aa32_vrint
, s
)) {
2286 if (!vfp_access_check(s
)) {
2290 tmp
= tcg_temp_new_i32();
2291 neon_load_reg32(tmp
, a
->vm
);
2292 fpst
= get_fpstatus_ptr(false);
2293 tcg_rmode
= tcg_const_i32(float_round_to_zero
);
2294 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
2295 gen_helper_rints(tmp
, tmp
, fpst
);
2296 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
2297 neon_store_reg32(tmp
, a
->vd
);
2298 tcg_temp_free_ptr(fpst
);
2299 tcg_temp_free_i32(tcg_rmode
);
2300 tcg_temp_free_i32(tmp
);
2304 static bool trans_VRINTZ_dp(DisasContext
*s
, arg_VRINTZ_dp
*a
)
2310 if (!dc_isar_feature(aa32_vrint
, s
)) {
2314 /* UNDEF accesses to D16-D31 if they don't exist. */
2315 if (!dc_isar_feature(aa32_fp_d32
, s
) && ((a
->vd
| a
->vm
) & 0x10)) {
2319 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2323 if (!vfp_access_check(s
)) {
2327 tmp
= tcg_temp_new_i64();
2328 neon_load_reg64(tmp
, a
->vm
);
2329 fpst
= get_fpstatus_ptr(false);
2330 tcg_rmode
= tcg_const_i32(float_round_to_zero
);
2331 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
2332 gen_helper_rintd(tmp
, tmp
, fpst
);
2333 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
2334 neon_store_reg64(tmp
, a
->vd
);
2335 tcg_temp_free_ptr(fpst
);
2336 tcg_temp_free_i64(tmp
);
2337 tcg_temp_free_i32(tcg_rmode
);
2341 static bool trans_VRINTX_sp(DisasContext
*s
, arg_VRINTX_sp
*a
)
2346 if (!dc_isar_feature(aa32_vrint
, s
)) {
2350 if (!vfp_access_check(s
)) {
2354 tmp
= tcg_temp_new_i32();
2355 neon_load_reg32(tmp
, a
->vm
);
2356 fpst
= get_fpstatus_ptr(false);
2357 gen_helper_rints_exact(tmp
, tmp
, fpst
);
2358 neon_store_reg32(tmp
, a
->vd
);
2359 tcg_temp_free_ptr(fpst
);
2360 tcg_temp_free_i32(tmp
);
2364 static bool trans_VRINTX_dp(DisasContext
*s
, arg_VRINTX_dp
*a
)
2369 if (!dc_isar_feature(aa32_vrint
, s
)) {
2373 /* UNDEF accesses to D16-D31 if they don't exist. */
2374 if (!dc_isar_feature(aa32_fp_d32
, s
) && ((a
->vd
| a
->vm
) & 0x10)) {
2378 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2382 if (!vfp_access_check(s
)) {
2386 tmp
= tcg_temp_new_i64();
2387 neon_load_reg64(tmp
, a
->vm
);
2388 fpst
= get_fpstatus_ptr(false);
2389 gen_helper_rintd_exact(tmp
, tmp
, fpst
);
2390 neon_store_reg64(tmp
, a
->vd
);
2391 tcg_temp_free_ptr(fpst
);
2392 tcg_temp_free_i64(tmp
);
2396 static bool trans_VCVT_sp(DisasContext
*s
, arg_VCVT_sp
*a
)
2401 /* UNDEF accesses to D16-D31 if they don't exist. */
2402 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vd
& 0x10)) {
2406 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2410 if (!vfp_access_check(s
)) {
2414 vm
= tcg_temp_new_i32();
2415 vd
= tcg_temp_new_i64();
2416 neon_load_reg32(vm
, a
->vm
);
2417 gen_helper_vfp_fcvtds(vd
, vm
, cpu_env
);
2418 neon_store_reg64(vd
, a
->vd
);
2419 tcg_temp_free_i32(vm
);
2420 tcg_temp_free_i64(vd
);
2424 static bool trans_VCVT_dp(DisasContext
*s
, arg_VCVT_dp
*a
)
2429 /* UNDEF accesses to D16-D31 if they don't exist. */
2430 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vm
& 0x10)) {
2434 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2438 if (!vfp_access_check(s
)) {
2442 vd
= tcg_temp_new_i32();
2443 vm
= tcg_temp_new_i64();
2444 neon_load_reg64(vm
, a
->vm
);
2445 gen_helper_vfp_fcvtsd(vd
, vm
, cpu_env
);
2446 neon_store_reg32(vd
, a
->vd
);
2447 tcg_temp_free_i32(vd
);
2448 tcg_temp_free_i64(vm
);
2452 static bool trans_VCVT_int_sp(DisasContext
*s
, arg_VCVT_int_sp
*a
)
2457 if (!vfp_access_check(s
)) {
2461 vm
= tcg_temp_new_i32();
2462 neon_load_reg32(vm
, a
->vm
);
2463 fpst
= get_fpstatus_ptr(false);
2466 gen_helper_vfp_sitos(vm
, vm
, fpst
);
2469 gen_helper_vfp_uitos(vm
, vm
, fpst
);
2471 neon_store_reg32(vm
, a
->vd
);
2472 tcg_temp_free_i32(vm
);
2473 tcg_temp_free_ptr(fpst
);
2477 static bool trans_VCVT_int_dp(DisasContext
*s
, arg_VCVT_int_dp
*a
)
2483 /* UNDEF accesses to D16-D31 if they don't exist. */
2484 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vd
& 0x10)) {
2488 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2492 if (!vfp_access_check(s
)) {
2496 vm
= tcg_temp_new_i32();
2497 vd
= tcg_temp_new_i64();
2498 neon_load_reg32(vm
, a
->vm
);
2499 fpst
= get_fpstatus_ptr(false);
2502 gen_helper_vfp_sitod(vd
, vm
, fpst
);
2505 gen_helper_vfp_uitod(vd
, vm
, fpst
);
2507 neon_store_reg64(vd
, a
->vd
);
2508 tcg_temp_free_i32(vm
);
2509 tcg_temp_free_i64(vd
);
2510 tcg_temp_free_ptr(fpst
);
2514 static bool trans_VJCVT(DisasContext
*s
, arg_VJCVT
*a
)
2519 if (!dc_isar_feature(aa32_jscvt
, s
)) {
2523 /* UNDEF accesses to D16-D31 if they don't exist. */
2524 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vm
& 0x10)) {
2528 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2532 if (!vfp_access_check(s
)) {
2536 vm
= tcg_temp_new_i64();
2537 vd
= tcg_temp_new_i32();
2538 neon_load_reg64(vm
, a
->vm
);
2539 gen_helper_vjcvt(vd
, vm
, cpu_env
);
2540 neon_store_reg32(vd
, a
->vd
);
2541 tcg_temp_free_i64(vm
);
2542 tcg_temp_free_i32(vd
);
2546 static bool trans_VCVT_fix_sp(DisasContext
*s
, arg_VCVT_fix_sp
*a
)
2552 if (!arm_dc_feature(s
, ARM_FEATURE_VFP3
)) {
2556 if (!vfp_access_check(s
)) {
2560 frac_bits
= (a
->opc
& 1) ? (32 - a
->imm
) : (16 - a
->imm
);
2562 vd
= tcg_temp_new_i32();
2563 neon_load_reg32(vd
, a
->vd
);
2565 fpst
= get_fpstatus_ptr(false);
2566 shift
= tcg_const_i32(frac_bits
);
2568 /* Switch on op:U:sx bits */
2571 gen_helper_vfp_shtos(vd
, vd
, shift
, fpst
);
2574 gen_helper_vfp_sltos(vd
, vd
, shift
, fpst
);
2577 gen_helper_vfp_uhtos(vd
, vd
, shift
, fpst
);
2580 gen_helper_vfp_ultos(vd
, vd
, shift
, fpst
);
2583 gen_helper_vfp_toshs_round_to_zero(vd
, vd
, shift
, fpst
);
2586 gen_helper_vfp_tosls_round_to_zero(vd
, vd
, shift
, fpst
);
2589 gen_helper_vfp_touhs_round_to_zero(vd
, vd
, shift
, fpst
);
2592 gen_helper_vfp_touls_round_to_zero(vd
, vd
, shift
, fpst
);
2595 g_assert_not_reached();
2598 neon_store_reg32(vd
, a
->vd
);
2599 tcg_temp_free_i32(vd
);
2600 tcg_temp_free_i32(shift
);
2601 tcg_temp_free_ptr(fpst
);
2605 static bool trans_VCVT_fix_dp(DisasContext
*s
, arg_VCVT_fix_dp
*a
)
2612 if (!arm_dc_feature(s
, ARM_FEATURE_VFP3
)) {
2616 /* UNDEF accesses to D16-D31 if they don't exist. */
2617 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vd
& 0x10)) {
2621 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2625 if (!vfp_access_check(s
)) {
2629 frac_bits
= (a
->opc
& 1) ? (32 - a
->imm
) : (16 - a
->imm
);
2631 vd
= tcg_temp_new_i64();
2632 neon_load_reg64(vd
, a
->vd
);
2634 fpst
= get_fpstatus_ptr(false);
2635 shift
= tcg_const_i32(frac_bits
);
2637 /* Switch on op:U:sx bits */
2640 gen_helper_vfp_shtod(vd
, vd
, shift
, fpst
);
2643 gen_helper_vfp_sltod(vd
, vd
, shift
, fpst
);
2646 gen_helper_vfp_uhtod(vd
, vd
, shift
, fpst
);
2649 gen_helper_vfp_ultod(vd
, vd
, shift
, fpst
);
2652 gen_helper_vfp_toshd_round_to_zero(vd
, vd
, shift
, fpst
);
2655 gen_helper_vfp_tosld_round_to_zero(vd
, vd
, shift
, fpst
);
2658 gen_helper_vfp_touhd_round_to_zero(vd
, vd
, shift
, fpst
);
2661 gen_helper_vfp_tould_round_to_zero(vd
, vd
, shift
, fpst
);
2664 g_assert_not_reached();
2667 neon_store_reg64(vd
, a
->vd
);
2668 tcg_temp_free_i64(vd
);
2669 tcg_temp_free_i32(shift
);
2670 tcg_temp_free_ptr(fpst
);
2674 static bool trans_VCVT_sp_int(DisasContext
*s
, arg_VCVT_sp_int
*a
)
2679 if (!vfp_access_check(s
)) {
2683 fpst
= get_fpstatus_ptr(false);
2684 vm
= tcg_temp_new_i32();
2685 neon_load_reg32(vm
, a
->vm
);
2689 gen_helper_vfp_tosizs(vm
, vm
, fpst
);
2691 gen_helper_vfp_tosis(vm
, vm
, fpst
);
2695 gen_helper_vfp_touizs(vm
, vm
, fpst
);
2697 gen_helper_vfp_touis(vm
, vm
, fpst
);
2700 neon_store_reg32(vm
, a
->vd
);
2701 tcg_temp_free_i32(vm
);
2702 tcg_temp_free_ptr(fpst
);
2706 static bool trans_VCVT_dp_int(DisasContext
*s
, arg_VCVT_dp_int
*a
)
2712 /* UNDEF accesses to D16-D31 if they don't exist. */
2713 if (!dc_isar_feature(aa32_fp_d32
, s
) && (a
->vm
& 0x10)) {
2717 if (!dc_isar_feature(aa32_fpdp
, s
)) {
2721 if (!vfp_access_check(s
)) {
2725 fpst
= get_fpstatus_ptr(false);
2726 vm
= tcg_temp_new_i64();
2727 vd
= tcg_temp_new_i32();
2728 neon_load_reg64(vm
, a
->vm
);
2732 gen_helper_vfp_tosizd(vd
, vm
, fpst
);
2734 gen_helper_vfp_tosid(vd
, vm
, fpst
);
2738 gen_helper_vfp_touizd(vd
, vm
, fpst
);
2740 gen_helper_vfp_touid(vd
, vm
, fpst
);
2743 neon_store_reg32(vd
, a
->vd
);
2744 tcg_temp_free_i32(vd
);
2745 tcg_temp_free_i64(vm
);
2746 tcg_temp_free_ptr(fpst
);