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.1 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/>.
23 #include "qemu/osdep.h"
24 #include "tcg/tcg-op.h"
25 #include "tcg/tcg-op-gvec.h"
26 #include "exec/exec-all.h"
27 #include "exec/gen-icount.h"
28 #include "translate.h"
29 #include "translate-a32.h"
31 /* Include the generated VFP decoder */
32 #include "decode-vfp.c.inc"
33 #include "decode-vfp-uncond.c.inc"
35 static inline void vfp_load_reg64(TCGv_i64 var
, int reg
)
37 tcg_gen_ld_i64(var
, cpu_env
, vfp_reg_offset(true, reg
));
40 static inline void vfp_store_reg64(TCGv_i64 var
, int reg
)
42 tcg_gen_st_i64(var
, cpu_env
, vfp_reg_offset(true, reg
));
45 static inline void vfp_load_reg32(TCGv_i32 var
, int reg
)
47 tcg_gen_ld_i32(var
, cpu_env
, vfp_reg_offset(false, reg
));
50 static inline void vfp_store_reg32(TCGv_i32 var
, int reg
)
52 tcg_gen_st_i32(var
, cpu_env
, vfp_reg_offset(false, reg
));
56 * The imm8 encodes the sign bit, enough bits to represent an exponent in
57 * the range 01....1xx to 10....0xx, and the most significant 4 bits of
58 * the mantissa; see VFPExpandImm() in the v8 ARM ARM.
60 uint64_t vfp_expand_imm(int size
, uint8_t imm8
)
66 imm
= (extract32(imm8
, 7, 1) ? 0x8000 : 0) |
67 (extract32(imm8
, 6, 1) ? 0x3fc0 : 0x4000) |
68 extract32(imm8
, 0, 6);
72 imm
= (extract32(imm8
, 7, 1) ? 0x8000 : 0) |
73 (extract32(imm8
, 6, 1) ? 0x3e00 : 0x4000) |
74 (extract32(imm8
, 0, 6) << 3);
78 imm
= (extract32(imm8
, 7, 1) ? 0x8000 : 0) |
79 (extract32(imm8
, 6, 1) ? 0x3000 : 0x4000) |
80 (extract32(imm8
, 0, 6) << 6);
83 g_assert_not_reached();
89 * Return the offset of a 16-bit half of the specified VFP single-precision
90 * register. If top is true, returns the top 16 bits; otherwise the bottom
93 static inline long vfp_f16_offset(unsigned reg
, bool top
)
95 long offs
= vfp_reg_offset(false, reg
);
109 * Generate code for M-profile lazy FP state preservation if needed;
110 * this corresponds to the pseudocode PreserveFPState() function.
112 static void gen_preserve_fp_state(DisasContext
*s
, bool skip_context_update
)
116 * Lazy state saving affects external memory and also the NVIC,
117 * so we must mark it as an IO operation for icount (and cause
118 * this to be the last insn in the TB).
120 if (tb_cflags(s
->base
.tb
) & CF_USE_ICOUNT
) {
121 s
->base
.is_jmp
= DISAS_UPDATE_EXIT
;
124 gen_helper_v7m_preserve_fp_state(cpu_env
);
126 * If the preserve_fp_state helper doesn't throw an exception
127 * then it will clear LSPACT; we don't need to repeat this for
128 * any further FP insns in this TB.
130 s
->v7m_lspact
= false;
132 * The helper might have zeroed VPR, so we do not know the
133 * correct value for the MVE_NO_PRED TB flag any more.
134 * If we're about to create a new fp context then that
135 * will precisely determine the MVE_NO_PRED value (see
136 * gen_update_fp_context()). Otherwise, we must:
137 * - set s->mve_no_pred to false, so this instruction
138 * is generated to use helper functions
139 * - end the TB now, without chaining to the next TB
141 if (skip_context_update
|| !s
->v7m_new_fp_ctxt_needed
) {
142 s
->mve_no_pred
= false;
143 s
->base
.is_jmp
= DISAS_UPDATE_NOCHAIN
;
149 * Generate code for M-profile FP context handling: update the
150 * ownership of the FP context, and create a new context if
151 * necessary. This corresponds to the parts of the pseudocode
152 * ExecuteFPCheck() after the inital PreserveFPState() call.
154 static void gen_update_fp_context(DisasContext
*s
)
156 /* Update ownership of FP context: set FPCCR.S to match current state */
157 if (s
->v8m_fpccr_s_wrong
) {
160 tmp
= load_cpu_field(v7m
.fpccr
[M_REG_S
]);
162 tcg_gen_ori_i32(tmp
, tmp
, R_V7M_FPCCR_S_MASK
);
164 tcg_gen_andi_i32(tmp
, tmp
, ~R_V7M_FPCCR_S_MASK
);
166 store_cpu_field(tmp
, v7m
.fpccr
[M_REG_S
]);
167 /* Don't need to do this for any further FP insns in this TB */
168 s
->v8m_fpccr_s_wrong
= false;
171 if (s
->v7m_new_fp_ctxt_needed
) {
173 * Create new FP context by updating CONTROL.FPCA, CONTROL.SFPA,
174 * the FPSCR, and VPR.
176 TCGv_i32 control
, fpscr
;
177 uint32_t bits
= R_V7M_CONTROL_FPCA_MASK
;
179 fpscr
= load_cpu_field(v7m
.fpdscr
[s
->v8m_secure
]);
180 gen_helper_vfp_set_fpscr(cpu_env
, fpscr
);
181 tcg_temp_free_i32(fpscr
);
182 if (dc_isar_feature(aa32_mve
, s
)) {
183 store_cpu_field(tcg_constant_i32(0), v7m
.vpr
);
186 * We just updated the FPSCR and VPR. Some of this state is cached
187 * in the MVE_NO_PRED TB flag. We want to avoid having to end the
188 * TB here, which means we need the new value of the MVE_NO_PRED
189 * flag to be exactly known here and the same for all executions.
190 * Luckily FPDSCR.LTPSIZE is always constant 4 and the VPR is
191 * always set to 0, so the new MVE_NO_PRED flag is always 1
192 * if and only if we have MVE.
194 * (The other FPSCR state cached in TB flags is VECLEN and VECSTRIDE,
195 * but those do not exist for M-profile, so are not relevant here.)
197 s
->mve_no_pred
= dc_isar_feature(aa32_mve
, s
);
200 bits
|= R_V7M_CONTROL_SFPA_MASK
;
202 control
= load_cpu_field(v7m
.control
[M_REG_S
]);
203 tcg_gen_ori_i32(control
, control
, bits
);
204 store_cpu_field(control
, v7m
.control
[M_REG_S
]);
205 /* Don't need to do this for any further FP insns in this TB */
206 s
->v7m_new_fp_ctxt_needed
= false;
211 * Check that VFP access is enabled, A-profile specific version.
213 * If VFP is enabled, return true. If not, emit code to generate an
214 * appropriate exception and return false.
215 * The ignore_vfp_enabled argument specifies that we should ignore
216 * whether VFP is enabled via FPEXC.EN: this should be true for FMXR/FMRX
217 * accesses to FPSID, FPEXC, MVFR0, MVFR1, MVFR2, and false for all other insns.
219 static bool vfp_access_check_a(DisasContext
*s
, bool ignore_vfp_enabled
)
222 gen_exception_insn(s
, s
->pc_curr
, EXCP_UDEF
,
223 syn_fp_access_trap(1, 0xe, false), s
->fp_excp_el
);
227 if (!s
->vfp_enabled
&& !ignore_vfp_enabled
) {
228 assert(!arm_dc_feature(s
, ARM_FEATURE_M
));
229 unallocated_encoding(s
);
236 * Check that VFP access is enabled, M-profile specific version.
238 * If VFP is enabled, do the necessary M-profile lazy-FP handling and then
239 * return true. If not, emit code to generate an appropriate exception and
241 * skip_context_update is true to skip the "update FP context" part of this.
243 bool vfp_access_check_m(DisasContext
*s
, bool skip_context_update
)
247 * M-profile mostly catches the "FPU disabled" case early, in
248 * disas_m_nocp(), but a few insns (eg LCTP, WLSTP, DLSTP)
249 * which do coprocessor-checks are outside the large ranges of
250 * the encoding space handled by the patterns in m-nocp.decode,
251 * and for them we may need to raise NOCP here.
253 gen_exception_insn(s
, s
->pc_curr
, EXCP_NOCP
,
254 syn_uncategorized(), s
->fp_excp_el
);
258 /* Handle M-profile lazy FP state mechanics */
260 /* Trigger lazy-state preservation if necessary */
261 gen_preserve_fp_state(s
, skip_context_update
);
263 if (!skip_context_update
) {
264 /* Update ownership of FP context and create new FP context if needed */
265 gen_update_fp_context(s
);
272 * The most usual kind of VFP access check, for everything except
273 * FMXR/FMRX to the always-available special registers.
275 bool vfp_access_check(DisasContext
*s
)
277 if (arm_dc_feature(s
, ARM_FEATURE_M
)) {
278 return vfp_access_check_m(s
, false);
280 return vfp_access_check_a(s
, false);
284 static bool trans_VSEL(DisasContext
*s
, arg_VSEL
*a
)
289 if (!dc_isar_feature(aa32_vsel
, s
)) {
293 if (sz
== 3 && !dc_isar_feature(aa32_fpdp_v2
, s
)) {
297 if (sz
== 1 && !dc_isar_feature(aa32_fp16_arith
, s
)) {
301 /* UNDEF accesses to D16-D31 if they don't exist */
302 if (sz
== 3 && !dc_isar_feature(aa32_simd_r32
, s
) &&
303 ((a
->vm
| a
->vn
| a
->vd
) & 0x10)) {
311 if (!vfp_access_check(s
)) {
316 TCGv_i64 frn
, frm
, dest
;
317 TCGv_i64 tmp
, zero
, zf
, nf
, vf
;
319 zero
= tcg_constant_i64(0);
321 frn
= tcg_temp_new_i64();
322 frm
= tcg_temp_new_i64();
323 dest
= tcg_temp_new_i64();
325 zf
= tcg_temp_new_i64();
326 nf
= tcg_temp_new_i64();
327 vf
= tcg_temp_new_i64();
329 tcg_gen_extu_i32_i64(zf
, cpu_ZF
);
330 tcg_gen_ext_i32_i64(nf
, cpu_NF
);
331 tcg_gen_ext_i32_i64(vf
, cpu_VF
);
333 vfp_load_reg64(frn
, rn
);
334 vfp_load_reg64(frm
, rm
);
337 tcg_gen_movcond_i64(TCG_COND_EQ
, dest
, zf
, zero
, frn
, frm
);
340 tcg_gen_movcond_i64(TCG_COND_LT
, dest
, vf
, zero
, frn
, frm
);
342 case 2: /* ge: N == V -> N ^ V == 0 */
343 tmp
= tcg_temp_new_i64();
344 tcg_gen_xor_i64(tmp
, vf
, nf
);
345 tcg_gen_movcond_i64(TCG_COND_GE
, dest
, tmp
, zero
, frn
, frm
);
346 tcg_temp_free_i64(tmp
);
348 case 3: /* gt: !Z && N == V */
349 tcg_gen_movcond_i64(TCG_COND_NE
, dest
, zf
, zero
, frn
, frm
);
350 tmp
= tcg_temp_new_i64();
351 tcg_gen_xor_i64(tmp
, vf
, nf
);
352 tcg_gen_movcond_i64(TCG_COND_GE
, dest
, tmp
, zero
, dest
, frm
);
353 tcg_temp_free_i64(tmp
);
356 vfp_store_reg64(dest
, rd
);
357 tcg_temp_free_i64(frn
);
358 tcg_temp_free_i64(frm
);
359 tcg_temp_free_i64(dest
);
361 tcg_temp_free_i64(zf
);
362 tcg_temp_free_i64(nf
);
363 tcg_temp_free_i64(vf
);
365 TCGv_i32 frn
, frm
, dest
;
368 zero
= tcg_constant_i32(0);
370 frn
= tcg_temp_new_i32();
371 frm
= tcg_temp_new_i32();
372 dest
= tcg_temp_new_i32();
373 vfp_load_reg32(frn
, rn
);
374 vfp_load_reg32(frm
, rm
);
377 tcg_gen_movcond_i32(TCG_COND_EQ
, dest
, cpu_ZF
, zero
, frn
, frm
);
380 tcg_gen_movcond_i32(TCG_COND_LT
, dest
, cpu_VF
, zero
, frn
, frm
);
382 case 2: /* ge: N == V -> N ^ V == 0 */
383 tmp
= tcg_temp_new_i32();
384 tcg_gen_xor_i32(tmp
, cpu_VF
, cpu_NF
);
385 tcg_gen_movcond_i32(TCG_COND_GE
, dest
, tmp
, zero
, frn
, frm
);
386 tcg_temp_free_i32(tmp
);
388 case 3: /* gt: !Z && N == V */
389 tcg_gen_movcond_i32(TCG_COND_NE
, dest
, cpu_ZF
, zero
, frn
, frm
);
390 tmp
= tcg_temp_new_i32();
391 tcg_gen_xor_i32(tmp
, cpu_VF
, cpu_NF
);
392 tcg_gen_movcond_i32(TCG_COND_GE
, dest
, tmp
, zero
, dest
, frm
);
393 tcg_temp_free_i32(tmp
);
396 /* For fp16 the top half is always zeroes */
398 tcg_gen_andi_i32(dest
, dest
, 0xffff);
400 vfp_store_reg32(dest
, rd
);
401 tcg_temp_free_i32(frn
);
402 tcg_temp_free_i32(frm
);
403 tcg_temp_free_i32(dest
);
410 * Table for converting the most common AArch32 encoding of
411 * rounding mode to arm_fprounding order (which matches the
412 * common AArch64 order); see ARM ARM pseudocode FPDecodeRM().
414 static const uint8_t fp_decode_rm
[] = {
421 static bool trans_VRINT(DisasContext
*s
, arg_VRINT
*a
)
427 int rounding
= fp_decode_rm
[a
->rm
];
429 if (!dc_isar_feature(aa32_vrint
, s
)) {
433 if (sz
== 3 && !dc_isar_feature(aa32_fpdp_v2
, s
)) {
437 if (sz
== 1 && !dc_isar_feature(aa32_fp16_arith
, s
)) {
441 /* UNDEF accesses to D16-D31 if they don't exist */
442 if (sz
== 3 && !dc_isar_feature(aa32_simd_r32
, s
) &&
443 ((a
->vm
| a
->vd
) & 0x10)) {
450 if (!vfp_access_check(s
)) {
455 fpst
= fpstatus_ptr(FPST_FPCR_F16
);
457 fpst
= fpstatus_ptr(FPST_FPCR
);
460 tcg_rmode
= tcg_const_i32(arm_rmode_to_sf(rounding
));
461 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
466 tcg_op
= tcg_temp_new_i64();
467 tcg_res
= tcg_temp_new_i64();
468 vfp_load_reg64(tcg_op
, rm
);
469 gen_helper_rintd(tcg_res
, tcg_op
, fpst
);
470 vfp_store_reg64(tcg_res
, rd
);
471 tcg_temp_free_i64(tcg_op
);
472 tcg_temp_free_i64(tcg_res
);
476 tcg_op
= tcg_temp_new_i32();
477 tcg_res
= tcg_temp_new_i32();
478 vfp_load_reg32(tcg_op
, rm
);
480 gen_helper_rinth(tcg_res
, tcg_op
, fpst
);
482 gen_helper_rints(tcg_res
, tcg_op
, fpst
);
484 vfp_store_reg32(tcg_res
, rd
);
485 tcg_temp_free_i32(tcg_op
);
486 tcg_temp_free_i32(tcg_res
);
489 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
490 tcg_temp_free_i32(tcg_rmode
);
492 tcg_temp_free_ptr(fpst
);
496 static bool trans_VCVT(DisasContext
*s
, arg_VCVT
*a
)
501 TCGv_i32 tcg_rmode
, tcg_shift
;
502 int rounding
= fp_decode_rm
[a
->rm
];
503 bool is_signed
= a
->op
;
505 if (!dc_isar_feature(aa32_vcvt_dr
, s
)) {
509 if (sz
== 3 && !dc_isar_feature(aa32_fpdp_v2
, s
)) {
513 if (sz
== 1 && !dc_isar_feature(aa32_fp16_arith
, s
)) {
517 /* UNDEF accesses to D16-D31 if they don't exist */
518 if (sz
== 3 && !dc_isar_feature(aa32_simd_r32
, s
) && (a
->vm
& 0x10)) {
525 if (!vfp_access_check(s
)) {
530 fpst
= fpstatus_ptr(FPST_FPCR_F16
);
532 fpst
= fpstatus_ptr(FPST_FPCR
);
535 tcg_shift
= tcg_constant_i32(0);
537 tcg_rmode
= tcg_const_i32(arm_rmode_to_sf(rounding
));
538 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
541 TCGv_i64 tcg_double
, tcg_res
;
543 tcg_double
= tcg_temp_new_i64();
544 tcg_res
= tcg_temp_new_i64();
545 tcg_tmp
= tcg_temp_new_i32();
546 vfp_load_reg64(tcg_double
, rm
);
548 gen_helper_vfp_tosld(tcg_res
, tcg_double
, tcg_shift
, fpst
);
550 gen_helper_vfp_tould(tcg_res
, tcg_double
, tcg_shift
, fpst
);
552 tcg_gen_extrl_i64_i32(tcg_tmp
, tcg_res
);
553 vfp_store_reg32(tcg_tmp
, rd
);
554 tcg_temp_free_i32(tcg_tmp
);
555 tcg_temp_free_i64(tcg_res
);
556 tcg_temp_free_i64(tcg_double
);
558 TCGv_i32 tcg_single
, tcg_res
;
559 tcg_single
= tcg_temp_new_i32();
560 tcg_res
= tcg_temp_new_i32();
561 vfp_load_reg32(tcg_single
, rm
);
564 gen_helper_vfp_toslh(tcg_res
, tcg_single
, tcg_shift
, fpst
);
566 gen_helper_vfp_toulh(tcg_res
, tcg_single
, tcg_shift
, fpst
);
570 gen_helper_vfp_tosls(tcg_res
, tcg_single
, tcg_shift
, fpst
);
572 gen_helper_vfp_touls(tcg_res
, tcg_single
, tcg_shift
, fpst
);
575 vfp_store_reg32(tcg_res
, rd
);
576 tcg_temp_free_i32(tcg_res
);
577 tcg_temp_free_i32(tcg_single
);
580 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
581 tcg_temp_free_i32(tcg_rmode
);
583 tcg_temp_free_ptr(fpst
);
588 bool mve_skip_vmov(DisasContext
*s
, int vn
, int index
, int size
)
591 * In a CPU with MVE, the VMOV (vector lane to general-purpose register)
592 * and VMOV (general-purpose register to vector lane) insns are not
593 * predicated, but they are subject to beatwise execution if they are
594 * not in an IT block.
596 * Since our implementation always executes all 4 beats in one tick,
597 * this means only that if PSR.ECI says we should not be executing
598 * the beat corresponding to the lane of the vector register being
599 * accessed then we should skip performing the move, and that we need
600 * to do the usual check for bad ECI state and advance of ECI state.
602 * Note that if PSR.ECI is non-zero then we cannot be in an IT block.
604 * Return true if this VMOV scalar <-> gpreg should be skipped because
605 * the MVE PSR.ECI state says we skip the beat where the store happens.
608 /* Calculate the byte offset into Qn which we're going to access */
609 int ofs
= (index
<< size
) + ((vn
& 1) * 8);
611 if (!dc_isar_feature(aa32_mve
, s
)) {
626 g_assert_not_reached();
630 static bool trans_VMOV_to_gp(DisasContext
*s
, arg_VMOV_to_gp
*a
)
632 /* VMOV scalar to general purpose register */
636 * SIZE == MO_32 is a VFP instruction; otherwise NEON. MVE has
637 * all sizes, whether the CPU has fp or not.
639 if (!dc_isar_feature(aa32_mve
, s
)) {
641 ? !dc_isar_feature(aa32_fpsp_v2
, s
)
642 : !arm_dc_feature(s
, ARM_FEATURE_NEON
)) {
647 /* UNDEF accesses to D16-D31 if they don't exist */
648 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vn
& 0x10)) {
652 if (dc_isar_feature(aa32_mve
, s
)) {
653 if (!mve_eci_check(s
)) {
658 if (!vfp_access_check(s
)) {
662 if (!mve_skip_vmov(s
, a
->vn
, a
->index
, a
->size
)) {
663 tmp
= tcg_temp_new_i32();
664 read_neon_element32(tmp
, a
->vn
, a
->index
,
665 a
->size
| (a
->u
? 0 : MO_SIGN
));
666 store_reg(s
, a
->rt
, tmp
);
669 if (dc_isar_feature(aa32_mve
, s
)) {
670 mve_update_and_store_eci(s
);
675 static bool trans_VMOV_from_gp(DisasContext
*s
, arg_VMOV_from_gp
*a
)
677 /* VMOV general purpose register to scalar */
681 * SIZE == MO_32 is a VFP instruction; otherwise NEON. MVE has
682 * all sizes, whether the CPU has fp or not.
684 if (!dc_isar_feature(aa32_mve
, s
)) {
686 ? !dc_isar_feature(aa32_fpsp_v2
, s
)
687 : !arm_dc_feature(s
, ARM_FEATURE_NEON
)) {
692 /* UNDEF accesses to D16-D31 if they don't exist */
693 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vn
& 0x10)) {
697 if (dc_isar_feature(aa32_mve
, s
)) {
698 if (!mve_eci_check(s
)) {
703 if (!vfp_access_check(s
)) {
707 if (!mve_skip_vmov(s
, a
->vn
, a
->index
, a
->size
)) {
708 tmp
= load_reg(s
, a
->rt
);
709 write_neon_element32(tmp
, a
->vn
, a
->index
, a
->size
);
710 tcg_temp_free_i32(tmp
);
713 if (dc_isar_feature(aa32_mve
, s
)) {
714 mve_update_and_store_eci(s
);
719 static bool trans_VDUP(DisasContext
*s
, arg_VDUP
*a
)
721 /* VDUP (general purpose register) */
725 if (!arm_dc_feature(s
, ARM_FEATURE_NEON
)) {
729 /* UNDEF accesses to D16-D31 if they don't exist */
730 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vn
& 0x10)) {
738 if (a
->q
&& (a
->vn
& 1)) {
742 vec_size
= a
->q
? 16 : 8;
751 if (!vfp_access_check(s
)) {
755 tmp
= load_reg(s
, a
->rt
);
756 tcg_gen_gvec_dup_i32(size
, neon_full_reg_offset(a
->vn
),
757 vec_size
, vec_size
, tmp
);
758 tcg_temp_free_i32(tmp
);
763 static bool trans_VMSR_VMRS(DisasContext
*s
, arg_VMSR_VMRS
*a
)
766 bool ignore_vfp_enabled
= false;
768 if (arm_dc_feature(s
, ARM_FEATURE_M
)) {
769 /* M profile version was already handled in m-nocp.decode */
773 if (!dc_isar_feature(aa32_fpsp_v2
, s
)) {
780 * VFPv2 allows access to FPSID from userspace; VFPv3 restricts
781 * all ID registers to privileged access only.
783 if (IS_USER(s
) && dc_isar_feature(aa32_fpsp_v3
, s
)) {
786 ignore_vfp_enabled
= true;
790 if (IS_USER(s
) || !arm_dc_feature(s
, ARM_FEATURE_MVFR
)) {
793 ignore_vfp_enabled
= true;
796 if (IS_USER(s
) || !arm_dc_feature(s
, ARM_FEATURE_V8
)) {
799 ignore_vfp_enabled
= true;
807 ignore_vfp_enabled
= true;
810 case ARM_VFP_FPINST2
:
811 /* Not present in VFPv3 */
812 if (IS_USER(s
) || dc_isar_feature(aa32_fpsp_v3
, s
)) {
821 * Call vfp_access_check_a() directly, because we need to tell
822 * it to ignore FPEXC.EN for some register accesses.
824 if (!vfp_access_check_a(s
, ignore_vfp_enabled
)) {
829 /* VMRS, move VFP special register to gp register */
835 if (s
->current_el
== 1) {
837 gen_set_pc_im(s
, s
->pc_curr
);
838 gen_helper_check_hcr_el2_trap(cpu_env
,
839 tcg_constant_i32(a
->rt
),
840 tcg_constant_i32(a
->reg
));
845 case ARM_VFP_FPINST2
:
846 tmp
= load_cpu_field(vfp
.xregs
[a
->reg
]);
850 tmp
= load_cpu_field(vfp
.xregs
[ARM_VFP_FPSCR
]);
851 tcg_gen_andi_i32(tmp
, tmp
, FPCR_NZCV_MASK
);
853 tmp
= tcg_temp_new_i32();
854 gen_helper_vfp_get_fpscr(tmp
, cpu_env
);
858 g_assert_not_reached();
862 /* Set the 4 flag bits in the CPSR. */
864 tcg_temp_free_i32(tmp
);
866 store_reg(s
, a
->rt
, tmp
);
869 /* VMSR, move gp register to VFP special register */
875 /* Writes are ignored. */
878 tmp
= load_reg(s
, a
->rt
);
879 gen_helper_vfp_set_fpscr(cpu_env
, tmp
);
880 tcg_temp_free_i32(tmp
);
885 * TODO: VFP subarchitecture support.
886 * For now, keep the EN bit only
888 tmp
= load_reg(s
, a
->rt
);
889 tcg_gen_andi_i32(tmp
, tmp
, 1 << 30);
890 store_cpu_field(tmp
, vfp
.xregs
[a
->reg
]);
894 case ARM_VFP_FPINST2
:
895 tmp
= load_reg(s
, a
->rt
);
896 store_cpu_field(tmp
, vfp
.xregs
[a
->reg
]);
899 g_assert_not_reached();
907 static bool trans_VMOV_half(DisasContext
*s
, arg_VMOV_single
*a
)
911 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
916 /* UNPREDICTABLE; we choose to UNDEF */
920 if (!vfp_access_check(s
)) {
925 /* VFP to general purpose register */
926 tmp
= tcg_temp_new_i32();
927 vfp_load_reg32(tmp
, a
->vn
);
928 tcg_gen_andi_i32(tmp
, tmp
, 0xffff);
929 store_reg(s
, a
->rt
, tmp
);
931 /* general purpose register to VFP */
932 tmp
= load_reg(s
, a
->rt
);
933 tcg_gen_andi_i32(tmp
, tmp
, 0xffff);
934 vfp_store_reg32(tmp
, a
->vn
);
935 tcg_temp_free_i32(tmp
);
941 static bool trans_VMOV_single(DisasContext
*s
, arg_VMOV_single
*a
)
945 if (!dc_isar_feature(aa32_fpsp_v2
, s
) && !dc_isar_feature(aa32_mve
, s
)) {
949 if (!vfp_access_check(s
)) {
954 /* VFP to general purpose register */
955 tmp
= tcg_temp_new_i32();
956 vfp_load_reg32(tmp
, a
->vn
);
958 /* Set the 4 flag bits in the CPSR. */
960 tcg_temp_free_i32(tmp
);
962 store_reg(s
, a
->rt
, tmp
);
965 /* general purpose register to VFP */
966 tmp
= load_reg(s
, a
->rt
);
967 vfp_store_reg32(tmp
, a
->vn
);
968 tcg_temp_free_i32(tmp
);
974 static bool trans_VMOV_64_sp(DisasContext
*s
, arg_VMOV_64_sp
*a
)
978 if (!dc_isar_feature(aa32_fpsp_v2
, s
) && !dc_isar_feature(aa32_mve
, s
)) {
983 * VMOV between two general-purpose registers and two single precision
984 * floating point registers
986 if (!vfp_access_check(s
)) {
992 tmp
= tcg_temp_new_i32();
993 vfp_load_reg32(tmp
, a
->vm
);
994 store_reg(s
, a
->rt
, tmp
);
995 tmp
= tcg_temp_new_i32();
996 vfp_load_reg32(tmp
, a
->vm
+ 1);
997 store_reg(s
, a
->rt2
, tmp
);
1000 tmp
= load_reg(s
, a
->rt
);
1001 vfp_store_reg32(tmp
, a
->vm
);
1002 tcg_temp_free_i32(tmp
);
1003 tmp
= load_reg(s
, a
->rt2
);
1004 vfp_store_reg32(tmp
, a
->vm
+ 1);
1005 tcg_temp_free_i32(tmp
);
1011 static bool trans_VMOV_64_dp(DisasContext
*s
, arg_VMOV_64_dp
*a
)
1016 * VMOV between two general-purpose registers and one double precision
1017 * floating point register. Note that this does not require support
1018 * for double precision arithmetic.
1020 if (!dc_isar_feature(aa32_fpsp_v2
, s
) && !dc_isar_feature(aa32_mve
, s
)) {
1024 /* UNDEF accesses to D16-D31 if they don't exist */
1025 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vm
& 0x10)) {
1029 if (!vfp_access_check(s
)) {
1034 /* fpreg to gpreg */
1035 tmp
= tcg_temp_new_i32();
1036 vfp_load_reg32(tmp
, a
->vm
* 2);
1037 store_reg(s
, a
->rt
, tmp
);
1038 tmp
= tcg_temp_new_i32();
1039 vfp_load_reg32(tmp
, a
->vm
* 2 + 1);
1040 store_reg(s
, a
->rt2
, tmp
);
1042 /* gpreg to fpreg */
1043 tmp
= load_reg(s
, a
->rt
);
1044 vfp_store_reg32(tmp
, a
->vm
* 2);
1045 tcg_temp_free_i32(tmp
);
1046 tmp
= load_reg(s
, a
->rt2
);
1047 vfp_store_reg32(tmp
, a
->vm
* 2 + 1);
1048 tcg_temp_free_i32(tmp
);
1054 static bool trans_VLDR_VSTR_hp(DisasContext
*s
, arg_VLDR_VSTR_sp
*a
)
1059 if (!dc_isar_feature(aa32_fpsp_v2
, s
) && !dc_isar_feature(aa32_mve
, s
)) {
1063 if (!vfp_access_check(s
)) {
1067 /* imm8 field is offset/2 for fp16, unlike fp32 and fp64 */
1068 offset
= a
->imm
<< 1;
1073 /* For thumb, use of PC is UNPREDICTABLE. */
1074 addr
= add_reg_for_lit(s
, a
->rn
, offset
);
1075 tmp
= tcg_temp_new_i32();
1077 gen_aa32_ld_i32(s
, tmp
, addr
, get_mem_index(s
), MO_UW
| MO_ALIGN
);
1078 vfp_store_reg32(tmp
, a
->vd
);
1080 vfp_load_reg32(tmp
, a
->vd
);
1081 gen_aa32_st_i32(s
, tmp
, addr
, get_mem_index(s
), MO_UW
| MO_ALIGN
);
1083 tcg_temp_free_i32(tmp
);
1084 tcg_temp_free_i32(addr
);
1089 static bool trans_VLDR_VSTR_sp(DisasContext
*s
, arg_VLDR_VSTR_sp
*a
)
1094 if (!dc_isar_feature(aa32_fpsp_v2
, s
) && !dc_isar_feature(aa32_mve
, s
)) {
1098 if (!vfp_access_check(s
)) {
1102 offset
= a
->imm
<< 2;
1107 /* For thumb, use of PC is UNPREDICTABLE. */
1108 addr
= add_reg_for_lit(s
, a
->rn
, offset
);
1109 tmp
= tcg_temp_new_i32();
1111 gen_aa32_ld_i32(s
, tmp
, addr
, get_mem_index(s
), MO_UL
| MO_ALIGN
);
1112 vfp_store_reg32(tmp
, a
->vd
);
1114 vfp_load_reg32(tmp
, a
->vd
);
1115 gen_aa32_st_i32(s
, tmp
, addr
, get_mem_index(s
), MO_UL
| MO_ALIGN
);
1117 tcg_temp_free_i32(tmp
);
1118 tcg_temp_free_i32(addr
);
1123 static bool trans_VLDR_VSTR_dp(DisasContext
*s
, arg_VLDR_VSTR_dp
*a
)
1129 /* Note that this does not require support for double arithmetic. */
1130 if (!dc_isar_feature(aa32_fpsp_v2
, s
) && !dc_isar_feature(aa32_mve
, s
)) {
1134 /* UNDEF accesses to D16-D31 if they don't exist */
1135 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vd
& 0x10)) {
1139 if (!vfp_access_check(s
)) {
1143 offset
= a
->imm
<< 2;
1148 /* For thumb, use of PC is UNPREDICTABLE. */
1149 addr
= add_reg_for_lit(s
, a
->rn
, offset
);
1150 tmp
= tcg_temp_new_i64();
1152 gen_aa32_ld_i64(s
, tmp
, addr
, get_mem_index(s
), MO_UQ
| MO_ALIGN_4
);
1153 vfp_store_reg64(tmp
, a
->vd
);
1155 vfp_load_reg64(tmp
, a
->vd
);
1156 gen_aa32_st_i64(s
, tmp
, addr
, get_mem_index(s
), MO_UQ
| MO_ALIGN_4
);
1158 tcg_temp_free_i64(tmp
);
1159 tcg_temp_free_i32(addr
);
1164 static bool trans_VLDM_VSTM_sp(DisasContext
*s
, arg_VLDM_VSTM_sp
*a
)
1170 if (!dc_isar_feature(aa32_fpsp_v2
, s
) && !dc_isar_feature(aa32_mve
, s
)) {
1176 if (n
== 0 || (a
->vd
+ n
) > 32) {
1178 * UNPREDICTABLE cases for bad immediates: we choose to
1179 * UNDEF to avoid generating huge numbers of TCG ops
1183 if (a
->rn
== 15 && a
->w
) {
1184 /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1188 s
->eci_handled
= true;
1190 if (!vfp_access_check(s
)) {
1194 /* For thumb, use of PC is UNPREDICTABLE. */
1195 addr
= add_reg_for_lit(s
, a
->rn
, 0);
1198 tcg_gen_addi_i32(addr
, addr
, -(a
->imm
<< 2));
1201 if (s
->v8m_stackcheck
&& a
->rn
== 13 && a
->w
) {
1203 * Here 'addr' is the lowest address we will store to,
1204 * and is either the old SP (if post-increment) or
1205 * the new SP (if pre-decrement). For post-increment
1206 * where the old value is below the limit and the new
1207 * value is above, it is UNKNOWN whether the limit check
1208 * triggers; we choose to trigger.
1210 gen_helper_v8m_stackcheck(cpu_env
, addr
);
1214 tmp
= tcg_temp_new_i32();
1215 for (i
= 0; i
< n
; i
++) {
1218 gen_aa32_ld_i32(s
, tmp
, addr
, get_mem_index(s
), MO_UL
| MO_ALIGN
);
1219 vfp_store_reg32(tmp
, a
->vd
+ i
);
1222 vfp_load_reg32(tmp
, a
->vd
+ i
);
1223 gen_aa32_st_i32(s
, tmp
, addr
, get_mem_index(s
), MO_UL
| MO_ALIGN
);
1225 tcg_gen_addi_i32(addr
, addr
, offset
);
1227 tcg_temp_free_i32(tmp
);
1231 offset
= -offset
* n
;
1232 tcg_gen_addi_i32(addr
, addr
, offset
);
1234 store_reg(s
, a
->rn
, addr
);
1236 tcg_temp_free_i32(addr
);
1243 static bool trans_VLDM_VSTM_dp(DisasContext
*s
, arg_VLDM_VSTM_dp
*a
)
1250 /* Note that this does not require support for double arithmetic. */
1251 if (!dc_isar_feature(aa32_fpsp_v2
, s
) && !dc_isar_feature(aa32_mve
, s
)) {
1257 if (n
== 0 || (a
->vd
+ n
) > 32 || n
> 16) {
1259 * UNPREDICTABLE cases for bad immediates: we choose to
1260 * UNDEF to avoid generating huge numbers of TCG ops
1264 if (a
->rn
== 15 && a
->w
) {
1265 /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1269 /* UNDEF accesses to D16-D31 if they don't exist */
1270 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vd
+ n
) > 16) {
1274 s
->eci_handled
= true;
1276 if (!vfp_access_check(s
)) {
1280 /* For thumb, use of PC is UNPREDICTABLE. */
1281 addr
= add_reg_for_lit(s
, a
->rn
, 0);
1284 tcg_gen_addi_i32(addr
, addr
, -(a
->imm
<< 2));
1287 if (s
->v8m_stackcheck
&& a
->rn
== 13 && a
->w
) {
1289 * Here 'addr' is the lowest address we will store to,
1290 * and is either the old SP (if post-increment) or
1291 * the new SP (if pre-decrement). For post-increment
1292 * where the old value is below the limit and the new
1293 * value is above, it is UNKNOWN whether the limit check
1294 * triggers; we choose to trigger.
1296 gen_helper_v8m_stackcheck(cpu_env
, addr
);
1300 tmp
= tcg_temp_new_i64();
1301 for (i
= 0; i
< n
; i
++) {
1304 gen_aa32_ld_i64(s
, tmp
, addr
, get_mem_index(s
), MO_UQ
| MO_ALIGN_4
);
1305 vfp_store_reg64(tmp
, a
->vd
+ i
);
1308 vfp_load_reg64(tmp
, a
->vd
+ i
);
1309 gen_aa32_st_i64(s
, tmp
, addr
, get_mem_index(s
), MO_UQ
| MO_ALIGN_4
);
1311 tcg_gen_addi_i32(addr
, addr
, offset
);
1313 tcg_temp_free_i64(tmp
);
1317 offset
= -offset
* n
;
1318 } else if (a
->imm
& 1) {
1325 tcg_gen_addi_i32(addr
, addr
, offset
);
1327 store_reg(s
, a
->rn
, addr
);
1329 tcg_temp_free_i32(addr
);
1337 * Types for callbacks for do_vfp_3op_sp() and do_vfp_3op_dp().
1338 * The callback should emit code to write a value to vd. If
1339 * do_vfp_3op_{sp,dp}() was passed reads_vd then the TCGv vd
1340 * will contain the old value of the relevant VFP register;
1341 * otherwise it must be written to only.
1343 typedef void VFPGen3OpSPFn(TCGv_i32 vd
,
1344 TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
);
1345 typedef void VFPGen3OpDPFn(TCGv_i64 vd
,
1346 TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
);
1349 * Types for callbacks for do_vfp_2op_sp() and do_vfp_2op_dp().
1350 * The callback should emit code to write a value to vd (which
1351 * should be written to only).
1353 typedef void VFPGen2OpSPFn(TCGv_i32 vd
, TCGv_i32 vm
);
1354 typedef void VFPGen2OpDPFn(TCGv_i64 vd
, TCGv_i64 vm
);
1357 * Return true if the specified S reg is in a scalar bank
1358 * (ie if it is s0..s7)
1360 static inline bool vfp_sreg_is_scalar(int reg
)
1362 return (reg
& 0x18) == 0;
1366 * Return true if the specified D reg is in a scalar bank
1367 * (ie if it is d0..d3 or d16..d19)
1369 static inline bool vfp_dreg_is_scalar(int reg
)
1371 return (reg
& 0xc) == 0;
1375 * Advance the S reg number forwards by delta within its bank
1376 * (ie increment the low 3 bits but leave the rest the same)
1378 static inline int vfp_advance_sreg(int reg
, int delta
)
1380 return ((reg
+ delta
) & 0x7) | (reg
& ~0x7);
1384 * Advance the D reg number forwards by delta within its bank
1385 * (ie increment the low 2 bits but leave the rest the same)
1387 static inline int vfp_advance_dreg(int reg
, int delta
)
1389 return ((reg
+ delta
) & 0x3) | (reg
& ~0x3);
1393 * Perform a 3-operand VFP data processing instruction. fn is the
1394 * callback to do the actual operation; this function deals with the
1395 * code to handle looping around for VFP vector processing.
1397 static bool do_vfp_3op_sp(DisasContext
*s
, VFPGen3OpSPFn
*fn
,
1398 int vd
, int vn
, int vm
, bool reads_vd
)
1400 uint32_t delta_m
= 0;
1401 uint32_t delta_d
= 0;
1402 int veclen
= s
->vec_len
;
1403 TCGv_i32 f0
, f1
, fd
;
1406 if (!dc_isar_feature(aa32_fpsp_v2
, s
)) {
1410 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
1411 (veclen
!= 0 || s
->vec_stride
!= 0)) {
1415 if (!vfp_access_check(s
)) {
1420 /* Figure out what type of vector operation this is. */
1421 if (vfp_sreg_is_scalar(vd
)) {
1425 delta_d
= s
->vec_stride
+ 1;
1427 if (vfp_sreg_is_scalar(vm
)) {
1428 /* mixed scalar/vector */
1437 f0
= tcg_temp_new_i32();
1438 f1
= tcg_temp_new_i32();
1439 fd
= tcg_temp_new_i32();
1440 fpst
= fpstatus_ptr(FPST_FPCR
);
1442 vfp_load_reg32(f0
, vn
);
1443 vfp_load_reg32(f1
, vm
);
1447 vfp_load_reg32(fd
, vd
);
1449 fn(fd
, f0
, f1
, fpst
);
1450 vfp_store_reg32(fd
, vd
);
1456 /* Set up the operands for the next iteration */
1458 vd
= vfp_advance_sreg(vd
, delta_d
);
1459 vn
= vfp_advance_sreg(vn
, delta_d
);
1460 vfp_load_reg32(f0
, vn
);
1462 vm
= vfp_advance_sreg(vm
, delta_m
);
1463 vfp_load_reg32(f1
, vm
);
1467 tcg_temp_free_i32(f0
);
1468 tcg_temp_free_i32(f1
);
1469 tcg_temp_free_i32(fd
);
1470 tcg_temp_free_ptr(fpst
);
1475 static bool do_vfp_3op_hp(DisasContext
*s
, VFPGen3OpSPFn
*fn
,
1476 int vd
, int vn
, int vm
, bool reads_vd
)
1479 * Do a half-precision operation. Functionally this is
1480 * the same as do_vfp_3op_sp(), except:
1481 * - it uses the FPST_FPCR_F16
1482 * - it doesn't need the VFP vector handling (fp16 is a
1483 * v8 feature, and in v8 VFP vectors don't exist)
1484 * - it does the aa32_fp16_arith feature test
1486 TCGv_i32 f0
, f1
, fd
;
1489 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
1493 if (s
->vec_len
!= 0 || s
->vec_stride
!= 0) {
1497 if (!vfp_access_check(s
)) {
1501 f0
= tcg_temp_new_i32();
1502 f1
= tcg_temp_new_i32();
1503 fd
= tcg_temp_new_i32();
1504 fpst
= fpstatus_ptr(FPST_FPCR_F16
);
1506 vfp_load_reg32(f0
, vn
);
1507 vfp_load_reg32(f1
, vm
);
1510 vfp_load_reg32(fd
, vd
);
1512 fn(fd
, f0
, f1
, fpst
);
1513 vfp_store_reg32(fd
, vd
);
1515 tcg_temp_free_i32(f0
);
1516 tcg_temp_free_i32(f1
);
1517 tcg_temp_free_i32(fd
);
1518 tcg_temp_free_ptr(fpst
);
1523 static bool do_vfp_3op_dp(DisasContext
*s
, VFPGen3OpDPFn
*fn
,
1524 int vd
, int vn
, int vm
, bool reads_vd
)
1526 uint32_t delta_m
= 0;
1527 uint32_t delta_d
= 0;
1528 int veclen
= s
->vec_len
;
1529 TCGv_i64 f0
, f1
, fd
;
1532 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
1536 /* UNDEF accesses to D16-D31 if they don't exist */
1537 if (!dc_isar_feature(aa32_simd_r32
, s
) && ((vd
| vn
| vm
) & 0x10)) {
1541 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
1542 (veclen
!= 0 || s
->vec_stride
!= 0)) {
1546 if (!vfp_access_check(s
)) {
1551 /* Figure out what type of vector operation this is. */
1552 if (vfp_dreg_is_scalar(vd
)) {
1556 delta_d
= (s
->vec_stride
>> 1) + 1;
1558 if (vfp_dreg_is_scalar(vm
)) {
1559 /* mixed scalar/vector */
1568 f0
= tcg_temp_new_i64();
1569 f1
= tcg_temp_new_i64();
1570 fd
= tcg_temp_new_i64();
1571 fpst
= fpstatus_ptr(FPST_FPCR
);
1573 vfp_load_reg64(f0
, vn
);
1574 vfp_load_reg64(f1
, vm
);
1578 vfp_load_reg64(fd
, vd
);
1580 fn(fd
, f0
, f1
, fpst
);
1581 vfp_store_reg64(fd
, vd
);
1586 /* Set up the operands for the next iteration */
1588 vd
= vfp_advance_dreg(vd
, delta_d
);
1589 vn
= vfp_advance_dreg(vn
, delta_d
);
1590 vfp_load_reg64(f0
, vn
);
1592 vm
= vfp_advance_dreg(vm
, delta_m
);
1593 vfp_load_reg64(f1
, vm
);
1597 tcg_temp_free_i64(f0
);
1598 tcg_temp_free_i64(f1
);
1599 tcg_temp_free_i64(fd
);
1600 tcg_temp_free_ptr(fpst
);
1605 static bool do_vfp_2op_sp(DisasContext
*s
, VFPGen2OpSPFn
*fn
, int vd
, int vm
)
1607 uint32_t delta_m
= 0;
1608 uint32_t delta_d
= 0;
1609 int veclen
= s
->vec_len
;
1612 /* Note that the caller must check the aa32_fpsp_v2 feature. */
1614 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
1615 (veclen
!= 0 || s
->vec_stride
!= 0)) {
1619 if (!vfp_access_check(s
)) {
1624 /* Figure out what type of vector operation this is. */
1625 if (vfp_sreg_is_scalar(vd
)) {
1629 delta_d
= s
->vec_stride
+ 1;
1631 if (vfp_sreg_is_scalar(vm
)) {
1632 /* mixed scalar/vector */
1641 f0
= tcg_temp_new_i32();
1642 fd
= tcg_temp_new_i32();
1644 vfp_load_reg32(f0
, vm
);
1648 vfp_store_reg32(fd
, vd
);
1655 /* single source one-many */
1657 vd
= vfp_advance_sreg(vd
, delta_d
);
1658 vfp_store_reg32(fd
, vd
);
1663 /* Set up the operands for the next iteration */
1665 vd
= vfp_advance_sreg(vd
, delta_d
);
1666 vm
= vfp_advance_sreg(vm
, delta_m
);
1667 vfp_load_reg32(f0
, vm
);
1670 tcg_temp_free_i32(f0
);
1671 tcg_temp_free_i32(fd
);
1676 static bool do_vfp_2op_hp(DisasContext
*s
, VFPGen2OpSPFn
*fn
, int vd
, int vm
)
1679 * Do a half-precision operation. Functionally this is
1680 * the same as do_vfp_2op_sp(), except:
1681 * - it doesn't need the VFP vector handling (fp16 is a
1682 * v8 feature, and in v8 VFP vectors don't exist)
1683 * - it does the aa32_fp16_arith feature test
1687 /* Note that the caller must check the aa32_fp16_arith feature */
1689 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
1693 if (s
->vec_len
!= 0 || s
->vec_stride
!= 0) {
1697 if (!vfp_access_check(s
)) {
1701 f0
= tcg_temp_new_i32();
1702 vfp_load_reg32(f0
, vm
);
1704 vfp_store_reg32(f0
, vd
);
1705 tcg_temp_free_i32(f0
);
1710 static bool do_vfp_2op_dp(DisasContext
*s
, VFPGen2OpDPFn
*fn
, int vd
, int vm
)
1712 uint32_t delta_m
= 0;
1713 uint32_t delta_d
= 0;
1714 int veclen
= s
->vec_len
;
1717 /* Note that the caller must check the aa32_fpdp_v2 feature. */
1719 /* UNDEF accesses to D16-D31 if they don't exist */
1720 if (!dc_isar_feature(aa32_simd_r32
, s
) && ((vd
| vm
) & 0x10)) {
1724 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
1725 (veclen
!= 0 || s
->vec_stride
!= 0)) {
1729 if (!vfp_access_check(s
)) {
1734 /* Figure out what type of vector operation this is. */
1735 if (vfp_dreg_is_scalar(vd
)) {
1739 delta_d
= (s
->vec_stride
>> 1) + 1;
1741 if (vfp_dreg_is_scalar(vm
)) {
1742 /* mixed scalar/vector */
1751 f0
= tcg_temp_new_i64();
1752 fd
= tcg_temp_new_i64();
1754 vfp_load_reg64(f0
, vm
);
1758 vfp_store_reg64(fd
, vd
);
1765 /* single source one-many */
1767 vd
= vfp_advance_dreg(vd
, delta_d
);
1768 vfp_store_reg64(fd
, vd
);
1773 /* Set up the operands for the next iteration */
1775 vd
= vfp_advance_dreg(vd
, delta_d
);
1776 vd
= vfp_advance_dreg(vm
, delta_m
);
1777 vfp_load_reg64(f0
, vm
);
1780 tcg_temp_free_i64(f0
);
1781 tcg_temp_free_i64(fd
);
1786 static void gen_VMLA_hp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1788 /* Note that order of inputs to the add matters for NaNs */
1789 TCGv_i32 tmp
= tcg_temp_new_i32();
1791 gen_helper_vfp_mulh(tmp
, vn
, vm
, fpst
);
1792 gen_helper_vfp_addh(vd
, vd
, tmp
, fpst
);
1793 tcg_temp_free_i32(tmp
);
1796 static bool trans_VMLA_hp(DisasContext
*s
, arg_VMLA_sp
*a
)
1798 return do_vfp_3op_hp(s
, gen_VMLA_hp
, a
->vd
, a
->vn
, a
->vm
, true);
1801 static void gen_VMLA_sp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1803 /* Note that order of inputs to the add matters for NaNs */
1804 TCGv_i32 tmp
= tcg_temp_new_i32();
1806 gen_helper_vfp_muls(tmp
, vn
, vm
, fpst
);
1807 gen_helper_vfp_adds(vd
, vd
, tmp
, fpst
);
1808 tcg_temp_free_i32(tmp
);
1811 static bool trans_VMLA_sp(DisasContext
*s
, arg_VMLA_sp
*a
)
1813 return do_vfp_3op_sp(s
, gen_VMLA_sp
, a
->vd
, a
->vn
, a
->vm
, true);
1816 static void gen_VMLA_dp(TCGv_i64 vd
, TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
)
1818 /* Note that order of inputs to the add matters for NaNs */
1819 TCGv_i64 tmp
= tcg_temp_new_i64();
1821 gen_helper_vfp_muld(tmp
, vn
, vm
, fpst
);
1822 gen_helper_vfp_addd(vd
, vd
, tmp
, fpst
);
1823 tcg_temp_free_i64(tmp
);
1826 static bool trans_VMLA_dp(DisasContext
*s
, arg_VMLA_dp
*a
)
1828 return do_vfp_3op_dp(s
, gen_VMLA_dp
, a
->vd
, a
->vn
, a
->vm
, true);
1831 static void gen_VMLS_hp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1834 * VMLS: vd = vd + -(vn * vm)
1835 * Note that order of inputs to the add matters for NaNs.
1837 TCGv_i32 tmp
= tcg_temp_new_i32();
1839 gen_helper_vfp_mulh(tmp
, vn
, vm
, fpst
);
1840 gen_helper_vfp_negh(tmp
, tmp
);
1841 gen_helper_vfp_addh(vd
, vd
, tmp
, fpst
);
1842 tcg_temp_free_i32(tmp
);
1845 static bool trans_VMLS_hp(DisasContext
*s
, arg_VMLS_sp
*a
)
1847 return do_vfp_3op_hp(s
, gen_VMLS_hp
, a
->vd
, a
->vn
, a
->vm
, true);
1850 static void gen_VMLS_sp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1853 * VMLS: vd = vd + -(vn * vm)
1854 * Note that order of inputs to the add matters for NaNs.
1856 TCGv_i32 tmp
= tcg_temp_new_i32();
1858 gen_helper_vfp_muls(tmp
, vn
, vm
, fpst
);
1859 gen_helper_vfp_negs(tmp
, tmp
);
1860 gen_helper_vfp_adds(vd
, vd
, tmp
, fpst
);
1861 tcg_temp_free_i32(tmp
);
1864 static bool trans_VMLS_sp(DisasContext
*s
, arg_VMLS_sp
*a
)
1866 return do_vfp_3op_sp(s
, gen_VMLS_sp
, a
->vd
, a
->vn
, a
->vm
, true);
1869 static void gen_VMLS_dp(TCGv_i64 vd
, TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
)
1872 * VMLS: vd = vd + -(vn * vm)
1873 * Note that order of inputs to the add matters for NaNs.
1875 TCGv_i64 tmp
= tcg_temp_new_i64();
1877 gen_helper_vfp_muld(tmp
, vn
, vm
, fpst
);
1878 gen_helper_vfp_negd(tmp
, tmp
);
1879 gen_helper_vfp_addd(vd
, vd
, tmp
, fpst
);
1880 tcg_temp_free_i64(tmp
);
1883 static bool trans_VMLS_dp(DisasContext
*s
, arg_VMLS_dp
*a
)
1885 return do_vfp_3op_dp(s
, gen_VMLS_dp
, a
->vd
, a
->vn
, a
->vm
, true);
1888 static void gen_VNMLS_hp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1891 * VNMLS: -fd + (fn * fm)
1892 * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1893 * plausible looking simplifications because this will give wrong results
1896 TCGv_i32 tmp
= tcg_temp_new_i32();
1898 gen_helper_vfp_mulh(tmp
, vn
, vm
, fpst
);
1899 gen_helper_vfp_negh(vd
, vd
);
1900 gen_helper_vfp_addh(vd
, vd
, tmp
, fpst
);
1901 tcg_temp_free_i32(tmp
);
1904 static bool trans_VNMLS_hp(DisasContext
*s
, arg_VNMLS_sp
*a
)
1906 return do_vfp_3op_hp(s
, gen_VNMLS_hp
, a
->vd
, a
->vn
, a
->vm
, true);
1909 static void gen_VNMLS_sp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1912 * VNMLS: -fd + (fn * fm)
1913 * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1914 * plausible looking simplifications because this will give wrong results
1917 TCGv_i32 tmp
= tcg_temp_new_i32();
1919 gen_helper_vfp_muls(tmp
, vn
, vm
, fpst
);
1920 gen_helper_vfp_negs(vd
, vd
);
1921 gen_helper_vfp_adds(vd
, vd
, tmp
, fpst
);
1922 tcg_temp_free_i32(tmp
);
1925 static bool trans_VNMLS_sp(DisasContext
*s
, arg_VNMLS_sp
*a
)
1927 return do_vfp_3op_sp(s
, gen_VNMLS_sp
, a
->vd
, a
->vn
, a
->vm
, true);
1930 static void gen_VNMLS_dp(TCGv_i64 vd
, TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
)
1933 * VNMLS: -fd + (fn * fm)
1934 * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1935 * plausible looking simplifications because this will give wrong results
1938 TCGv_i64 tmp
= tcg_temp_new_i64();
1940 gen_helper_vfp_muld(tmp
, vn
, vm
, fpst
);
1941 gen_helper_vfp_negd(vd
, vd
);
1942 gen_helper_vfp_addd(vd
, vd
, tmp
, fpst
);
1943 tcg_temp_free_i64(tmp
);
1946 static bool trans_VNMLS_dp(DisasContext
*s
, arg_VNMLS_dp
*a
)
1948 return do_vfp_3op_dp(s
, gen_VNMLS_dp
, a
->vd
, a
->vn
, a
->vm
, true);
1951 static void gen_VNMLA_hp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1953 /* VNMLA: -fd + -(fn * fm) */
1954 TCGv_i32 tmp
= tcg_temp_new_i32();
1956 gen_helper_vfp_mulh(tmp
, vn
, vm
, fpst
);
1957 gen_helper_vfp_negh(tmp
, tmp
);
1958 gen_helper_vfp_negh(vd
, vd
);
1959 gen_helper_vfp_addh(vd
, vd
, tmp
, fpst
);
1960 tcg_temp_free_i32(tmp
);
1963 static bool trans_VNMLA_hp(DisasContext
*s
, arg_VNMLA_sp
*a
)
1965 return do_vfp_3op_hp(s
, gen_VNMLA_hp
, a
->vd
, a
->vn
, a
->vm
, true);
1968 static void gen_VNMLA_sp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
1970 /* VNMLA: -fd + -(fn * fm) */
1971 TCGv_i32 tmp
= tcg_temp_new_i32();
1973 gen_helper_vfp_muls(tmp
, vn
, vm
, fpst
);
1974 gen_helper_vfp_negs(tmp
, tmp
);
1975 gen_helper_vfp_negs(vd
, vd
);
1976 gen_helper_vfp_adds(vd
, vd
, tmp
, fpst
);
1977 tcg_temp_free_i32(tmp
);
1980 static bool trans_VNMLA_sp(DisasContext
*s
, arg_VNMLA_sp
*a
)
1982 return do_vfp_3op_sp(s
, gen_VNMLA_sp
, a
->vd
, a
->vn
, a
->vm
, true);
1985 static void gen_VNMLA_dp(TCGv_i64 vd
, TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
)
1987 /* VNMLA: -fd + (fn * fm) */
1988 TCGv_i64 tmp
= tcg_temp_new_i64();
1990 gen_helper_vfp_muld(tmp
, vn
, vm
, fpst
);
1991 gen_helper_vfp_negd(tmp
, tmp
);
1992 gen_helper_vfp_negd(vd
, vd
);
1993 gen_helper_vfp_addd(vd
, vd
, tmp
, fpst
);
1994 tcg_temp_free_i64(tmp
);
1997 static bool trans_VNMLA_dp(DisasContext
*s
, arg_VNMLA_dp
*a
)
1999 return do_vfp_3op_dp(s
, gen_VNMLA_dp
, a
->vd
, a
->vn
, a
->vm
, true);
2002 static bool trans_VMUL_hp(DisasContext
*s
, arg_VMUL_sp
*a
)
2004 return do_vfp_3op_hp(s
, gen_helper_vfp_mulh
, a
->vd
, a
->vn
, a
->vm
, false);
2007 static bool trans_VMUL_sp(DisasContext
*s
, arg_VMUL_sp
*a
)
2009 return do_vfp_3op_sp(s
, gen_helper_vfp_muls
, a
->vd
, a
->vn
, a
->vm
, false);
2012 static bool trans_VMUL_dp(DisasContext
*s
, arg_VMUL_dp
*a
)
2014 return do_vfp_3op_dp(s
, gen_helper_vfp_muld
, a
->vd
, a
->vn
, a
->vm
, false);
2017 static void gen_VNMUL_hp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
2019 /* VNMUL: -(fn * fm) */
2020 gen_helper_vfp_mulh(vd
, vn
, vm
, fpst
);
2021 gen_helper_vfp_negh(vd
, vd
);
2024 static bool trans_VNMUL_hp(DisasContext
*s
, arg_VNMUL_sp
*a
)
2026 return do_vfp_3op_hp(s
, gen_VNMUL_hp
, a
->vd
, a
->vn
, a
->vm
, false);
2029 static void gen_VNMUL_sp(TCGv_i32 vd
, TCGv_i32 vn
, TCGv_i32 vm
, TCGv_ptr fpst
)
2031 /* VNMUL: -(fn * fm) */
2032 gen_helper_vfp_muls(vd
, vn
, vm
, fpst
);
2033 gen_helper_vfp_negs(vd
, vd
);
2036 static bool trans_VNMUL_sp(DisasContext
*s
, arg_VNMUL_sp
*a
)
2038 return do_vfp_3op_sp(s
, gen_VNMUL_sp
, a
->vd
, a
->vn
, a
->vm
, false);
2041 static void gen_VNMUL_dp(TCGv_i64 vd
, TCGv_i64 vn
, TCGv_i64 vm
, TCGv_ptr fpst
)
2043 /* VNMUL: -(fn * fm) */
2044 gen_helper_vfp_muld(vd
, vn
, vm
, fpst
);
2045 gen_helper_vfp_negd(vd
, vd
);
2048 static bool trans_VNMUL_dp(DisasContext
*s
, arg_VNMUL_dp
*a
)
2050 return do_vfp_3op_dp(s
, gen_VNMUL_dp
, a
->vd
, a
->vn
, a
->vm
, false);
2053 static bool trans_VADD_hp(DisasContext
*s
, arg_VADD_sp
*a
)
2055 return do_vfp_3op_hp(s
, gen_helper_vfp_addh
, a
->vd
, a
->vn
, a
->vm
, false);
2058 static bool trans_VADD_sp(DisasContext
*s
, arg_VADD_sp
*a
)
2060 return do_vfp_3op_sp(s
, gen_helper_vfp_adds
, a
->vd
, a
->vn
, a
->vm
, false);
2063 static bool trans_VADD_dp(DisasContext
*s
, arg_VADD_dp
*a
)
2065 return do_vfp_3op_dp(s
, gen_helper_vfp_addd
, a
->vd
, a
->vn
, a
->vm
, false);
2068 static bool trans_VSUB_hp(DisasContext
*s
, arg_VSUB_sp
*a
)
2070 return do_vfp_3op_hp(s
, gen_helper_vfp_subh
, a
->vd
, a
->vn
, a
->vm
, false);
2073 static bool trans_VSUB_sp(DisasContext
*s
, arg_VSUB_sp
*a
)
2075 return do_vfp_3op_sp(s
, gen_helper_vfp_subs
, a
->vd
, a
->vn
, a
->vm
, false);
2078 static bool trans_VSUB_dp(DisasContext
*s
, arg_VSUB_dp
*a
)
2080 return do_vfp_3op_dp(s
, gen_helper_vfp_subd
, a
->vd
, a
->vn
, a
->vm
, false);
2083 static bool trans_VDIV_hp(DisasContext
*s
, arg_VDIV_sp
*a
)
2085 return do_vfp_3op_hp(s
, gen_helper_vfp_divh
, a
->vd
, a
->vn
, a
->vm
, false);
2088 static bool trans_VDIV_sp(DisasContext
*s
, arg_VDIV_sp
*a
)
2090 return do_vfp_3op_sp(s
, gen_helper_vfp_divs
, a
->vd
, a
->vn
, a
->vm
, false);
2093 static bool trans_VDIV_dp(DisasContext
*s
, arg_VDIV_dp
*a
)
2095 return do_vfp_3op_dp(s
, gen_helper_vfp_divd
, a
->vd
, a
->vn
, a
->vm
, false);
2098 static bool trans_VMINNM_hp(DisasContext
*s
, arg_VMINNM_sp
*a
)
2100 if (!dc_isar_feature(aa32_vminmaxnm
, s
)) {
2103 return do_vfp_3op_hp(s
, gen_helper_vfp_minnumh
,
2104 a
->vd
, a
->vn
, a
->vm
, false);
2107 static bool trans_VMAXNM_hp(DisasContext
*s
, arg_VMAXNM_sp
*a
)
2109 if (!dc_isar_feature(aa32_vminmaxnm
, s
)) {
2112 return do_vfp_3op_hp(s
, gen_helper_vfp_maxnumh
,
2113 a
->vd
, a
->vn
, a
->vm
, false);
2116 static bool trans_VMINNM_sp(DisasContext
*s
, arg_VMINNM_sp
*a
)
2118 if (!dc_isar_feature(aa32_vminmaxnm
, s
)) {
2121 return do_vfp_3op_sp(s
, gen_helper_vfp_minnums
,
2122 a
->vd
, a
->vn
, a
->vm
, false);
2125 static bool trans_VMAXNM_sp(DisasContext
*s
, arg_VMAXNM_sp
*a
)
2127 if (!dc_isar_feature(aa32_vminmaxnm
, s
)) {
2130 return do_vfp_3op_sp(s
, gen_helper_vfp_maxnums
,
2131 a
->vd
, a
->vn
, a
->vm
, false);
2134 static bool trans_VMINNM_dp(DisasContext
*s
, arg_VMINNM_dp
*a
)
2136 if (!dc_isar_feature(aa32_vminmaxnm
, s
)) {
2139 return do_vfp_3op_dp(s
, gen_helper_vfp_minnumd
,
2140 a
->vd
, a
->vn
, a
->vm
, false);
2143 static bool trans_VMAXNM_dp(DisasContext
*s
, arg_VMAXNM_dp
*a
)
2145 if (!dc_isar_feature(aa32_vminmaxnm
, s
)) {
2148 return do_vfp_3op_dp(s
, gen_helper_vfp_maxnumd
,
2149 a
->vd
, a
->vn
, a
->vm
, false);
2152 static bool do_vfm_hp(DisasContext
*s
, arg_VFMA_sp
*a
, bool neg_n
, bool neg_d
)
2155 * VFNMA : fd = muladd(-fd, fn, fm)
2156 * VFNMS : fd = muladd(-fd, -fn, fm)
2157 * VFMA : fd = muladd( fd, fn, fm)
2158 * VFMS : fd = muladd( fd, -fn, fm)
2160 * These are fused multiply-add, and must be done as one floating
2161 * point operation with no rounding between the multiplication and
2162 * addition steps. NB that doing the negations here as separate
2163 * steps is correct : an input NaN should come out with its sign
2164 * bit flipped if it is a negated-input.
2167 TCGv_i32 vn
, vm
, vd
;
2170 * Present in VFPv4 only, and only with the FP16 extension.
2171 * Note that we can't rely on the SIMDFMAC check alone, because
2172 * in a Neon-no-VFP core that ID register field will be non-zero.
2174 if (!dc_isar_feature(aa32_fp16_arith
, s
) ||
2175 !dc_isar_feature(aa32_simdfmac
, s
) ||
2176 !dc_isar_feature(aa32_fpsp_v2
, s
)) {
2180 if (s
->vec_len
!= 0 || s
->vec_stride
!= 0) {
2184 if (!vfp_access_check(s
)) {
2188 vn
= tcg_temp_new_i32();
2189 vm
= tcg_temp_new_i32();
2190 vd
= tcg_temp_new_i32();
2192 vfp_load_reg32(vn
, a
->vn
);
2193 vfp_load_reg32(vm
, a
->vm
);
2196 gen_helper_vfp_negh(vn
, vn
);
2198 vfp_load_reg32(vd
, a
->vd
);
2201 gen_helper_vfp_negh(vd
, vd
);
2203 fpst
= fpstatus_ptr(FPST_FPCR_F16
);
2204 gen_helper_vfp_muladdh(vd
, vn
, vm
, vd
, fpst
);
2205 vfp_store_reg32(vd
, a
->vd
);
2207 tcg_temp_free_ptr(fpst
);
2208 tcg_temp_free_i32(vn
);
2209 tcg_temp_free_i32(vm
);
2210 tcg_temp_free_i32(vd
);
2215 static bool do_vfm_sp(DisasContext
*s
, arg_VFMA_sp
*a
, bool neg_n
, bool neg_d
)
2218 * VFNMA : fd = muladd(-fd, fn, fm)
2219 * VFNMS : fd = muladd(-fd, -fn, fm)
2220 * VFMA : fd = muladd( fd, fn, fm)
2221 * VFMS : fd = muladd( fd, -fn, fm)
2223 * These are fused multiply-add, and must be done as one floating
2224 * point operation with no rounding between the multiplication and
2225 * addition steps. NB that doing the negations here as separate
2226 * steps is correct : an input NaN should come out with its sign
2227 * bit flipped if it is a negated-input.
2230 TCGv_i32 vn
, vm
, vd
;
2233 * Present in VFPv4 only.
2234 * Note that we can't rely on the SIMDFMAC check alone, because
2235 * in a Neon-no-VFP core that ID register field will be non-zero.
2237 if (!dc_isar_feature(aa32_simdfmac
, s
) ||
2238 !dc_isar_feature(aa32_fpsp_v2
, s
)) {
2242 * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
2243 * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
2245 if (s
->vec_len
!= 0 || s
->vec_stride
!= 0) {
2249 if (!vfp_access_check(s
)) {
2253 vn
= tcg_temp_new_i32();
2254 vm
= tcg_temp_new_i32();
2255 vd
= tcg_temp_new_i32();
2257 vfp_load_reg32(vn
, a
->vn
);
2258 vfp_load_reg32(vm
, a
->vm
);
2261 gen_helper_vfp_negs(vn
, vn
);
2263 vfp_load_reg32(vd
, a
->vd
);
2266 gen_helper_vfp_negs(vd
, vd
);
2268 fpst
= fpstatus_ptr(FPST_FPCR
);
2269 gen_helper_vfp_muladds(vd
, vn
, vm
, vd
, fpst
);
2270 vfp_store_reg32(vd
, a
->vd
);
2272 tcg_temp_free_ptr(fpst
);
2273 tcg_temp_free_i32(vn
);
2274 tcg_temp_free_i32(vm
);
2275 tcg_temp_free_i32(vd
);
2280 static bool do_vfm_dp(DisasContext
*s
, arg_VFMA_dp
*a
, bool neg_n
, bool neg_d
)
2283 * VFNMA : fd = muladd(-fd, fn, fm)
2284 * VFNMS : fd = muladd(-fd, -fn, fm)
2285 * VFMA : fd = muladd( fd, fn, fm)
2286 * VFMS : fd = muladd( fd, -fn, fm)
2288 * These are fused multiply-add, and must be done as one floating
2289 * point operation with no rounding between the multiplication and
2290 * addition steps. NB that doing the negations here as separate
2291 * steps is correct : an input NaN should come out with its sign
2292 * bit flipped if it is a negated-input.
2295 TCGv_i64 vn
, vm
, vd
;
2298 * Present in VFPv4 only.
2299 * Note that we can't rely on the SIMDFMAC check alone, because
2300 * in a Neon-no-VFP core that ID register field will be non-zero.
2302 if (!dc_isar_feature(aa32_simdfmac
, s
) ||
2303 !dc_isar_feature(aa32_fpdp_v2
, s
)) {
2307 * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
2308 * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
2310 if (s
->vec_len
!= 0 || s
->vec_stride
!= 0) {
2314 /* UNDEF accesses to D16-D31 if they don't exist. */
2315 if (!dc_isar_feature(aa32_simd_r32
, s
) &&
2316 ((a
->vd
| a
->vn
| a
->vm
) & 0x10)) {
2320 if (!vfp_access_check(s
)) {
2324 vn
= tcg_temp_new_i64();
2325 vm
= tcg_temp_new_i64();
2326 vd
= tcg_temp_new_i64();
2328 vfp_load_reg64(vn
, a
->vn
);
2329 vfp_load_reg64(vm
, a
->vm
);
2332 gen_helper_vfp_negd(vn
, vn
);
2334 vfp_load_reg64(vd
, a
->vd
);
2337 gen_helper_vfp_negd(vd
, vd
);
2339 fpst
= fpstatus_ptr(FPST_FPCR
);
2340 gen_helper_vfp_muladdd(vd
, vn
, vm
, vd
, fpst
);
2341 vfp_store_reg64(vd
, a
->vd
);
2343 tcg_temp_free_ptr(fpst
);
2344 tcg_temp_free_i64(vn
);
2345 tcg_temp_free_i64(vm
);
2346 tcg_temp_free_i64(vd
);
2351 #define MAKE_ONE_VFM_TRANS_FN(INSN, PREC, NEGN, NEGD) \
2352 static bool trans_##INSN##_##PREC(DisasContext *s, \
2353 arg_##INSN##_##PREC *a) \
2355 return do_vfm_##PREC(s, a, NEGN, NEGD); \
2358 #define MAKE_VFM_TRANS_FNS(PREC) \
2359 MAKE_ONE_VFM_TRANS_FN(VFMA, PREC, false, false) \
2360 MAKE_ONE_VFM_TRANS_FN(VFMS, PREC, true, false) \
2361 MAKE_ONE_VFM_TRANS_FN(VFNMA, PREC, false, true) \
2362 MAKE_ONE_VFM_TRANS_FN(VFNMS, PREC, true, true)
2364 MAKE_VFM_TRANS_FNS(hp
)
2365 MAKE_VFM_TRANS_FNS(sp
)
2366 MAKE_VFM_TRANS_FNS(dp
)
2368 static bool trans_VMOV_imm_hp(DisasContext
*s
, arg_VMOV_imm_sp
*a
)
2370 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
2374 if (s
->vec_len
!= 0 || s
->vec_stride
!= 0) {
2378 if (!vfp_access_check(s
)) {
2382 vfp_store_reg32(tcg_constant_i32(vfp_expand_imm(MO_16
, a
->imm
)), a
->vd
);
2386 static bool trans_VMOV_imm_sp(DisasContext
*s
, arg_VMOV_imm_sp
*a
)
2388 uint32_t delta_d
= 0;
2389 int veclen
= s
->vec_len
;
2395 if (!dc_isar_feature(aa32_fpsp_v3
, s
)) {
2399 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
2400 (veclen
!= 0 || s
->vec_stride
!= 0)) {
2404 if (!vfp_access_check(s
)) {
2409 /* Figure out what type of vector operation this is. */
2410 if (vfp_sreg_is_scalar(vd
)) {
2414 delta_d
= s
->vec_stride
+ 1;
2418 fd
= tcg_constant_i32(vfp_expand_imm(MO_32
, a
->imm
));
2421 vfp_store_reg32(fd
, vd
);
2427 /* Set up the operands for the next iteration */
2429 vd
= vfp_advance_sreg(vd
, delta_d
);
2435 static bool trans_VMOV_imm_dp(DisasContext
*s
, arg_VMOV_imm_dp
*a
)
2437 uint32_t delta_d
= 0;
2438 int veclen
= s
->vec_len
;
2444 if (!dc_isar_feature(aa32_fpdp_v3
, s
)) {
2448 /* UNDEF accesses to D16-D31 if they don't exist. */
2449 if (!dc_isar_feature(aa32_simd_r32
, s
) && (vd
& 0x10)) {
2453 if (!dc_isar_feature(aa32_fpshvec
, s
) &&
2454 (veclen
!= 0 || s
->vec_stride
!= 0)) {
2458 if (!vfp_access_check(s
)) {
2463 /* Figure out what type of vector operation this is. */
2464 if (vfp_dreg_is_scalar(vd
)) {
2468 delta_d
= (s
->vec_stride
>> 1) + 1;
2472 fd
= tcg_constant_i64(vfp_expand_imm(MO_64
, a
->imm
));
2475 vfp_store_reg64(fd
, vd
);
2481 /* Set up the operands for the next iteration */
2483 vd
= vfp_advance_dreg(vd
, delta_d
);
2489 #define DO_VFP_2OP(INSN, PREC, FN, CHECK) \
2490 static bool trans_##INSN##_##PREC(DisasContext *s, \
2491 arg_##INSN##_##PREC *a) \
2493 if (!dc_isar_feature(CHECK, s)) { \
2496 return do_vfp_2op_##PREC(s, FN, a->vd, a->vm); \
2499 #define DO_VFP_VMOV(INSN, PREC, FN) \
2500 static bool trans_##INSN##_##PREC(DisasContext *s, \
2501 arg_##INSN##_##PREC *a) \
2503 if (!dc_isar_feature(aa32_fp##PREC##_v2, s) && \
2504 !dc_isar_feature(aa32_mve, s)) { \
2507 return do_vfp_2op_##PREC(s, FN, a->vd, a->vm); \
2510 DO_VFP_VMOV(VMOV_reg
, sp
, tcg_gen_mov_i32
)
2511 DO_VFP_VMOV(VMOV_reg
, dp
, tcg_gen_mov_i64
)
2513 DO_VFP_2OP(VABS
, hp
, gen_helper_vfp_absh
, aa32_fp16_arith
)
2514 DO_VFP_2OP(VABS
, sp
, gen_helper_vfp_abss
, aa32_fpsp_v2
)
2515 DO_VFP_2OP(VABS
, dp
, gen_helper_vfp_absd
, aa32_fpdp_v2
)
2517 DO_VFP_2OP(VNEG
, hp
, gen_helper_vfp_negh
, aa32_fp16_arith
)
2518 DO_VFP_2OP(VNEG
, sp
, gen_helper_vfp_negs
, aa32_fpsp_v2
)
2519 DO_VFP_2OP(VNEG
, dp
, gen_helper_vfp_negd
, aa32_fpdp_v2
)
2521 static void gen_VSQRT_hp(TCGv_i32 vd
, TCGv_i32 vm
)
2523 gen_helper_vfp_sqrth(vd
, vm
, cpu_env
);
2526 static void gen_VSQRT_sp(TCGv_i32 vd
, TCGv_i32 vm
)
2528 gen_helper_vfp_sqrts(vd
, vm
, cpu_env
);
2531 static void gen_VSQRT_dp(TCGv_i64 vd
, TCGv_i64 vm
)
2533 gen_helper_vfp_sqrtd(vd
, vm
, cpu_env
);
2536 DO_VFP_2OP(VSQRT
, hp
, gen_VSQRT_hp
, aa32_fp16_arith
)
2537 DO_VFP_2OP(VSQRT
, sp
, gen_VSQRT_sp
, aa32_fpsp_v2
)
2538 DO_VFP_2OP(VSQRT
, dp
, gen_VSQRT_dp
, aa32_fpdp_v2
)
2540 static bool trans_VCMP_hp(DisasContext
*s
, arg_VCMP_sp
*a
)
2544 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
2548 /* Vm/M bits must be zero for the Z variant */
2549 if (a
->z
&& a
->vm
!= 0) {
2553 if (!vfp_access_check(s
)) {
2557 vd
= tcg_temp_new_i32();
2558 vm
= tcg_temp_new_i32();
2560 vfp_load_reg32(vd
, a
->vd
);
2562 tcg_gen_movi_i32(vm
, 0);
2564 vfp_load_reg32(vm
, a
->vm
);
2568 gen_helper_vfp_cmpeh(vd
, vm
, cpu_env
);
2570 gen_helper_vfp_cmph(vd
, vm
, cpu_env
);
2573 tcg_temp_free_i32(vd
);
2574 tcg_temp_free_i32(vm
);
2579 static bool trans_VCMP_sp(DisasContext
*s
, arg_VCMP_sp
*a
)
2583 if (!dc_isar_feature(aa32_fpsp_v2
, s
)) {
2587 /* Vm/M bits must be zero for the Z variant */
2588 if (a
->z
&& a
->vm
!= 0) {
2592 if (!vfp_access_check(s
)) {
2596 vd
= tcg_temp_new_i32();
2597 vm
= tcg_temp_new_i32();
2599 vfp_load_reg32(vd
, a
->vd
);
2601 tcg_gen_movi_i32(vm
, 0);
2603 vfp_load_reg32(vm
, a
->vm
);
2607 gen_helper_vfp_cmpes(vd
, vm
, cpu_env
);
2609 gen_helper_vfp_cmps(vd
, vm
, cpu_env
);
2612 tcg_temp_free_i32(vd
);
2613 tcg_temp_free_i32(vm
);
2618 static bool trans_VCMP_dp(DisasContext
*s
, arg_VCMP_dp
*a
)
2622 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
2626 /* Vm/M bits must be zero for the Z variant */
2627 if (a
->z
&& a
->vm
!= 0) {
2631 /* UNDEF accesses to D16-D31 if they don't exist. */
2632 if (!dc_isar_feature(aa32_simd_r32
, s
) && ((a
->vd
| a
->vm
) & 0x10)) {
2636 if (!vfp_access_check(s
)) {
2640 vd
= tcg_temp_new_i64();
2641 vm
= tcg_temp_new_i64();
2643 vfp_load_reg64(vd
, a
->vd
);
2645 tcg_gen_movi_i64(vm
, 0);
2647 vfp_load_reg64(vm
, a
->vm
);
2651 gen_helper_vfp_cmped(vd
, vm
, cpu_env
);
2653 gen_helper_vfp_cmpd(vd
, vm
, cpu_env
);
2656 tcg_temp_free_i64(vd
);
2657 tcg_temp_free_i64(vm
);
2662 static bool trans_VCVT_f32_f16(DisasContext
*s
, arg_VCVT_f32_f16
*a
)
2668 if (!dc_isar_feature(aa32_fp16_spconv
, s
)) {
2672 if (!vfp_access_check(s
)) {
2676 fpst
= fpstatus_ptr(FPST_FPCR
);
2677 ahp_mode
= get_ahp_flag();
2678 tmp
= tcg_temp_new_i32();
2679 /* The T bit tells us if we want the low or high 16 bits of Vm */
2680 tcg_gen_ld16u_i32(tmp
, cpu_env
, vfp_f16_offset(a
->vm
, a
->t
));
2681 gen_helper_vfp_fcvt_f16_to_f32(tmp
, tmp
, fpst
, ahp_mode
);
2682 vfp_store_reg32(tmp
, a
->vd
);
2683 tcg_temp_free_i32(ahp_mode
);
2684 tcg_temp_free_ptr(fpst
);
2685 tcg_temp_free_i32(tmp
);
2689 static bool trans_VCVT_f64_f16(DisasContext
*s
, arg_VCVT_f64_f16
*a
)
2696 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
2700 if (!dc_isar_feature(aa32_fp16_dpconv
, s
)) {
2704 /* UNDEF accesses to D16-D31 if they don't exist. */
2705 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vd
& 0x10)) {
2709 if (!vfp_access_check(s
)) {
2713 fpst
= fpstatus_ptr(FPST_FPCR
);
2714 ahp_mode
= get_ahp_flag();
2715 tmp
= tcg_temp_new_i32();
2716 /* The T bit tells us if we want the low or high 16 bits of Vm */
2717 tcg_gen_ld16u_i32(tmp
, cpu_env
, vfp_f16_offset(a
->vm
, a
->t
));
2718 vd
= tcg_temp_new_i64();
2719 gen_helper_vfp_fcvt_f16_to_f64(vd
, tmp
, fpst
, ahp_mode
);
2720 vfp_store_reg64(vd
, a
->vd
);
2721 tcg_temp_free_i32(ahp_mode
);
2722 tcg_temp_free_ptr(fpst
);
2723 tcg_temp_free_i32(tmp
);
2724 tcg_temp_free_i64(vd
);
2728 static bool trans_VCVT_b16_f32(DisasContext
*s
, arg_VCVT_b16_f32
*a
)
2733 if (!dc_isar_feature(aa32_bf16
, s
)) {
2737 if (!vfp_access_check(s
)) {
2741 fpst
= fpstatus_ptr(FPST_FPCR
);
2742 tmp
= tcg_temp_new_i32();
2744 vfp_load_reg32(tmp
, a
->vm
);
2745 gen_helper_bfcvt(tmp
, tmp
, fpst
);
2746 tcg_gen_st16_i32(tmp
, cpu_env
, vfp_f16_offset(a
->vd
, a
->t
));
2747 tcg_temp_free_ptr(fpst
);
2748 tcg_temp_free_i32(tmp
);
2752 static bool trans_VCVT_f16_f32(DisasContext
*s
, arg_VCVT_f16_f32
*a
)
2758 if (!dc_isar_feature(aa32_fp16_spconv
, s
)) {
2762 if (!vfp_access_check(s
)) {
2766 fpst
= fpstatus_ptr(FPST_FPCR
);
2767 ahp_mode
= get_ahp_flag();
2768 tmp
= tcg_temp_new_i32();
2770 vfp_load_reg32(tmp
, a
->vm
);
2771 gen_helper_vfp_fcvt_f32_to_f16(tmp
, tmp
, fpst
, ahp_mode
);
2772 tcg_gen_st16_i32(tmp
, cpu_env
, vfp_f16_offset(a
->vd
, a
->t
));
2773 tcg_temp_free_i32(ahp_mode
);
2774 tcg_temp_free_ptr(fpst
);
2775 tcg_temp_free_i32(tmp
);
2779 static bool trans_VCVT_f16_f64(DisasContext
*s
, arg_VCVT_f16_f64
*a
)
2786 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
2790 if (!dc_isar_feature(aa32_fp16_dpconv
, s
)) {
2794 /* UNDEF accesses to D16-D31 if they don't exist. */
2795 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vm
& 0x10)) {
2799 if (!vfp_access_check(s
)) {
2803 fpst
= fpstatus_ptr(FPST_FPCR
);
2804 ahp_mode
= get_ahp_flag();
2805 tmp
= tcg_temp_new_i32();
2806 vm
= tcg_temp_new_i64();
2808 vfp_load_reg64(vm
, a
->vm
);
2809 gen_helper_vfp_fcvt_f64_to_f16(tmp
, vm
, fpst
, ahp_mode
);
2810 tcg_temp_free_i64(vm
);
2811 tcg_gen_st16_i32(tmp
, cpu_env
, vfp_f16_offset(a
->vd
, a
->t
));
2812 tcg_temp_free_i32(ahp_mode
);
2813 tcg_temp_free_ptr(fpst
);
2814 tcg_temp_free_i32(tmp
);
2818 static bool trans_VRINTR_hp(DisasContext
*s
, arg_VRINTR_sp
*a
)
2823 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
2827 if (!vfp_access_check(s
)) {
2831 tmp
= tcg_temp_new_i32();
2832 vfp_load_reg32(tmp
, a
->vm
);
2833 fpst
= fpstatus_ptr(FPST_FPCR_F16
);
2834 gen_helper_rinth(tmp
, tmp
, fpst
);
2835 vfp_store_reg32(tmp
, a
->vd
);
2836 tcg_temp_free_ptr(fpst
);
2837 tcg_temp_free_i32(tmp
);
2841 static bool trans_VRINTR_sp(DisasContext
*s
, arg_VRINTR_sp
*a
)
2846 if (!dc_isar_feature(aa32_vrint
, s
)) {
2850 if (!vfp_access_check(s
)) {
2854 tmp
= tcg_temp_new_i32();
2855 vfp_load_reg32(tmp
, a
->vm
);
2856 fpst
= fpstatus_ptr(FPST_FPCR
);
2857 gen_helper_rints(tmp
, tmp
, fpst
);
2858 vfp_store_reg32(tmp
, a
->vd
);
2859 tcg_temp_free_ptr(fpst
);
2860 tcg_temp_free_i32(tmp
);
2864 static bool trans_VRINTR_dp(DisasContext
*s
, arg_VRINTR_dp
*a
)
2869 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
2873 if (!dc_isar_feature(aa32_vrint
, s
)) {
2877 /* UNDEF accesses to D16-D31 if they don't exist. */
2878 if (!dc_isar_feature(aa32_simd_r32
, s
) && ((a
->vd
| a
->vm
) & 0x10)) {
2882 if (!vfp_access_check(s
)) {
2886 tmp
= tcg_temp_new_i64();
2887 vfp_load_reg64(tmp
, a
->vm
);
2888 fpst
= fpstatus_ptr(FPST_FPCR
);
2889 gen_helper_rintd(tmp
, tmp
, fpst
);
2890 vfp_store_reg64(tmp
, a
->vd
);
2891 tcg_temp_free_ptr(fpst
);
2892 tcg_temp_free_i64(tmp
);
2896 static bool trans_VRINTZ_hp(DisasContext
*s
, arg_VRINTZ_sp
*a
)
2902 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
2906 if (!vfp_access_check(s
)) {
2910 tmp
= tcg_temp_new_i32();
2911 vfp_load_reg32(tmp
, a
->vm
);
2912 fpst
= fpstatus_ptr(FPST_FPCR_F16
);
2913 tcg_rmode
= tcg_const_i32(float_round_to_zero
);
2914 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
2915 gen_helper_rinth(tmp
, tmp
, fpst
);
2916 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
2917 vfp_store_reg32(tmp
, a
->vd
);
2918 tcg_temp_free_ptr(fpst
);
2919 tcg_temp_free_i32(tcg_rmode
);
2920 tcg_temp_free_i32(tmp
);
2924 static bool trans_VRINTZ_sp(DisasContext
*s
, arg_VRINTZ_sp
*a
)
2930 if (!dc_isar_feature(aa32_vrint
, s
)) {
2934 if (!vfp_access_check(s
)) {
2938 tmp
= tcg_temp_new_i32();
2939 vfp_load_reg32(tmp
, a
->vm
);
2940 fpst
= fpstatus_ptr(FPST_FPCR
);
2941 tcg_rmode
= tcg_const_i32(float_round_to_zero
);
2942 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
2943 gen_helper_rints(tmp
, tmp
, fpst
);
2944 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
2945 vfp_store_reg32(tmp
, a
->vd
);
2946 tcg_temp_free_ptr(fpst
);
2947 tcg_temp_free_i32(tcg_rmode
);
2948 tcg_temp_free_i32(tmp
);
2952 static bool trans_VRINTZ_dp(DisasContext
*s
, arg_VRINTZ_dp
*a
)
2958 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
2962 if (!dc_isar_feature(aa32_vrint
, s
)) {
2966 /* UNDEF accesses to D16-D31 if they don't exist. */
2967 if (!dc_isar_feature(aa32_simd_r32
, s
) && ((a
->vd
| a
->vm
) & 0x10)) {
2971 if (!vfp_access_check(s
)) {
2975 tmp
= tcg_temp_new_i64();
2976 vfp_load_reg64(tmp
, a
->vm
);
2977 fpst
= fpstatus_ptr(FPST_FPCR
);
2978 tcg_rmode
= tcg_const_i32(float_round_to_zero
);
2979 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
2980 gen_helper_rintd(tmp
, tmp
, fpst
);
2981 gen_helper_set_rmode(tcg_rmode
, tcg_rmode
, fpst
);
2982 vfp_store_reg64(tmp
, a
->vd
);
2983 tcg_temp_free_ptr(fpst
);
2984 tcg_temp_free_i64(tmp
);
2985 tcg_temp_free_i32(tcg_rmode
);
2989 static bool trans_VRINTX_hp(DisasContext
*s
, arg_VRINTX_sp
*a
)
2994 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
2998 if (!vfp_access_check(s
)) {
3002 tmp
= tcg_temp_new_i32();
3003 vfp_load_reg32(tmp
, a
->vm
);
3004 fpst
= fpstatus_ptr(FPST_FPCR_F16
);
3005 gen_helper_rinth_exact(tmp
, tmp
, fpst
);
3006 vfp_store_reg32(tmp
, a
->vd
);
3007 tcg_temp_free_ptr(fpst
);
3008 tcg_temp_free_i32(tmp
);
3012 static bool trans_VRINTX_sp(DisasContext
*s
, arg_VRINTX_sp
*a
)
3017 if (!dc_isar_feature(aa32_vrint
, s
)) {
3021 if (!vfp_access_check(s
)) {
3025 tmp
= tcg_temp_new_i32();
3026 vfp_load_reg32(tmp
, a
->vm
);
3027 fpst
= fpstatus_ptr(FPST_FPCR
);
3028 gen_helper_rints_exact(tmp
, tmp
, fpst
);
3029 vfp_store_reg32(tmp
, a
->vd
);
3030 tcg_temp_free_ptr(fpst
);
3031 tcg_temp_free_i32(tmp
);
3035 static bool trans_VRINTX_dp(DisasContext
*s
, arg_VRINTX_dp
*a
)
3040 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
3044 if (!dc_isar_feature(aa32_vrint
, s
)) {
3048 /* UNDEF accesses to D16-D31 if they don't exist. */
3049 if (!dc_isar_feature(aa32_simd_r32
, s
) && ((a
->vd
| a
->vm
) & 0x10)) {
3053 if (!vfp_access_check(s
)) {
3057 tmp
= tcg_temp_new_i64();
3058 vfp_load_reg64(tmp
, a
->vm
);
3059 fpst
= fpstatus_ptr(FPST_FPCR
);
3060 gen_helper_rintd_exact(tmp
, tmp
, fpst
);
3061 vfp_store_reg64(tmp
, a
->vd
);
3062 tcg_temp_free_ptr(fpst
);
3063 tcg_temp_free_i64(tmp
);
3067 static bool trans_VCVT_sp(DisasContext
*s
, arg_VCVT_sp
*a
)
3072 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
3076 /* UNDEF accesses to D16-D31 if they don't exist. */
3077 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vd
& 0x10)) {
3081 if (!vfp_access_check(s
)) {
3085 vm
= tcg_temp_new_i32();
3086 vd
= tcg_temp_new_i64();
3087 vfp_load_reg32(vm
, a
->vm
);
3088 gen_helper_vfp_fcvtds(vd
, vm
, cpu_env
);
3089 vfp_store_reg64(vd
, a
->vd
);
3090 tcg_temp_free_i32(vm
);
3091 tcg_temp_free_i64(vd
);
3095 static bool trans_VCVT_dp(DisasContext
*s
, arg_VCVT_dp
*a
)
3100 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
3104 /* UNDEF accesses to D16-D31 if they don't exist. */
3105 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vm
& 0x10)) {
3109 if (!vfp_access_check(s
)) {
3113 vd
= tcg_temp_new_i32();
3114 vm
= tcg_temp_new_i64();
3115 vfp_load_reg64(vm
, a
->vm
);
3116 gen_helper_vfp_fcvtsd(vd
, vm
, cpu_env
);
3117 vfp_store_reg32(vd
, a
->vd
);
3118 tcg_temp_free_i32(vd
);
3119 tcg_temp_free_i64(vm
);
3123 static bool trans_VCVT_int_hp(DisasContext
*s
, arg_VCVT_int_sp
*a
)
3128 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
3132 if (!vfp_access_check(s
)) {
3136 vm
= tcg_temp_new_i32();
3137 vfp_load_reg32(vm
, a
->vm
);
3138 fpst
= fpstatus_ptr(FPST_FPCR_F16
);
3141 gen_helper_vfp_sitoh(vm
, vm
, fpst
);
3144 gen_helper_vfp_uitoh(vm
, vm
, fpst
);
3146 vfp_store_reg32(vm
, a
->vd
);
3147 tcg_temp_free_i32(vm
);
3148 tcg_temp_free_ptr(fpst
);
3152 static bool trans_VCVT_int_sp(DisasContext
*s
, arg_VCVT_int_sp
*a
)
3157 if (!dc_isar_feature(aa32_fpsp_v2
, s
)) {
3161 if (!vfp_access_check(s
)) {
3165 vm
= tcg_temp_new_i32();
3166 vfp_load_reg32(vm
, a
->vm
);
3167 fpst
= fpstatus_ptr(FPST_FPCR
);
3170 gen_helper_vfp_sitos(vm
, vm
, fpst
);
3173 gen_helper_vfp_uitos(vm
, vm
, fpst
);
3175 vfp_store_reg32(vm
, a
->vd
);
3176 tcg_temp_free_i32(vm
);
3177 tcg_temp_free_ptr(fpst
);
3181 static bool trans_VCVT_int_dp(DisasContext
*s
, arg_VCVT_int_dp
*a
)
3187 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
3191 /* UNDEF accesses to D16-D31 if they don't exist. */
3192 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vd
& 0x10)) {
3196 if (!vfp_access_check(s
)) {
3200 vm
= tcg_temp_new_i32();
3201 vd
= tcg_temp_new_i64();
3202 vfp_load_reg32(vm
, a
->vm
);
3203 fpst
= fpstatus_ptr(FPST_FPCR
);
3206 gen_helper_vfp_sitod(vd
, vm
, fpst
);
3209 gen_helper_vfp_uitod(vd
, vm
, fpst
);
3211 vfp_store_reg64(vd
, a
->vd
);
3212 tcg_temp_free_i32(vm
);
3213 tcg_temp_free_i64(vd
);
3214 tcg_temp_free_ptr(fpst
);
3218 static bool trans_VJCVT(DisasContext
*s
, arg_VJCVT
*a
)
3223 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
3227 if (!dc_isar_feature(aa32_jscvt
, s
)) {
3231 /* UNDEF accesses to D16-D31 if they don't exist. */
3232 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vm
& 0x10)) {
3236 if (!vfp_access_check(s
)) {
3240 vm
= tcg_temp_new_i64();
3241 vd
= tcg_temp_new_i32();
3242 vfp_load_reg64(vm
, a
->vm
);
3243 gen_helper_vjcvt(vd
, vm
, cpu_env
);
3244 vfp_store_reg32(vd
, a
->vd
);
3245 tcg_temp_free_i64(vm
);
3246 tcg_temp_free_i32(vd
);
3250 static bool trans_VCVT_fix_hp(DisasContext
*s
, arg_VCVT_fix_sp
*a
)
3256 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
3260 if (!vfp_access_check(s
)) {
3264 frac_bits
= (a
->opc
& 1) ? (32 - a
->imm
) : (16 - a
->imm
);
3266 vd
= tcg_temp_new_i32();
3267 vfp_load_reg32(vd
, a
->vd
);
3269 fpst
= fpstatus_ptr(FPST_FPCR_F16
);
3270 shift
= tcg_constant_i32(frac_bits
);
3272 /* Switch on op:U:sx bits */
3275 gen_helper_vfp_shtoh_round_to_nearest(vd
, vd
, shift
, fpst
);
3278 gen_helper_vfp_sltoh_round_to_nearest(vd
, vd
, shift
, fpst
);
3281 gen_helper_vfp_uhtoh_round_to_nearest(vd
, vd
, shift
, fpst
);
3284 gen_helper_vfp_ultoh_round_to_nearest(vd
, vd
, shift
, fpst
);
3287 gen_helper_vfp_toshh_round_to_zero(vd
, vd
, shift
, fpst
);
3290 gen_helper_vfp_toslh_round_to_zero(vd
, vd
, shift
, fpst
);
3293 gen_helper_vfp_touhh_round_to_zero(vd
, vd
, shift
, fpst
);
3296 gen_helper_vfp_toulh_round_to_zero(vd
, vd
, shift
, fpst
);
3299 g_assert_not_reached();
3302 vfp_store_reg32(vd
, a
->vd
);
3303 tcg_temp_free_i32(vd
);
3304 tcg_temp_free_ptr(fpst
);
3308 static bool trans_VCVT_fix_sp(DisasContext
*s
, arg_VCVT_fix_sp
*a
)
3314 if (!dc_isar_feature(aa32_fpsp_v3
, s
)) {
3318 if (!vfp_access_check(s
)) {
3322 frac_bits
= (a
->opc
& 1) ? (32 - a
->imm
) : (16 - a
->imm
);
3324 vd
= tcg_temp_new_i32();
3325 vfp_load_reg32(vd
, a
->vd
);
3327 fpst
= fpstatus_ptr(FPST_FPCR
);
3328 shift
= tcg_constant_i32(frac_bits
);
3330 /* Switch on op:U:sx bits */
3333 gen_helper_vfp_shtos_round_to_nearest(vd
, vd
, shift
, fpst
);
3336 gen_helper_vfp_sltos_round_to_nearest(vd
, vd
, shift
, fpst
);
3339 gen_helper_vfp_uhtos_round_to_nearest(vd
, vd
, shift
, fpst
);
3342 gen_helper_vfp_ultos_round_to_nearest(vd
, vd
, shift
, fpst
);
3345 gen_helper_vfp_toshs_round_to_zero(vd
, vd
, shift
, fpst
);
3348 gen_helper_vfp_tosls_round_to_zero(vd
, vd
, shift
, fpst
);
3351 gen_helper_vfp_touhs_round_to_zero(vd
, vd
, shift
, fpst
);
3354 gen_helper_vfp_touls_round_to_zero(vd
, vd
, shift
, fpst
);
3357 g_assert_not_reached();
3360 vfp_store_reg32(vd
, a
->vd
);
3361 tcg_temp_free_i32(vd
);
3362 tcg_temp_free_ptr(fpst
);
3366 static bool trans_VCVT_fix_dp(DisasContext
*s
, arg_VCVT_fix_dp
*a
)
3373 if (!dc_isar_feature(aa32_fpdp_v3
, s
)) {
3377 /* UNDEF accesses to D16-D31 if they don't exist. */
3378 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vd
& 0x10)) {
3382 if (!vfp_access_check(s
)) {
3386 frac_bits
= (a
->opc
& 1) ? (32 - a
->imm
) : (16 - a
->imm
);
3388 vd
= tcg_temp_new_i64();
3389 vfp_load_reg64(vd
, a
->vd
);
3391 fpst
= fpstatus_ptr(FPST_FPCR
);
3392 shift
= tcg_constant_i32(frac_bits
);
3394 /* Switch on op:U:sx bits */
3397 gen_helper_vfp_shtod_round_to_nearest(vd
, vd
, shift
, fpst
);
3400 gen_helper_vfp_sltod_round_to_nearest(vd
, vd
, shift
, fpst
);
3403 gen_helper_vfp_uhtod_round_to_nearest(vd
, vd
, shift
, fpst
);
3406 gen_helper_vfp_ultod_round_to_nearest(vd
, vd
, shift
, fpst
);
3409 gen_helper_vfp_toshd_round_to_zero(vd
, vd
, shift
, fpst
);
3412 gen_helper_vfp_tosld_round_to_zero(vd
, vd
, shift
, fpst
);
3415 gen_helper_vfp_touhd_round_to_zero(vd
, vd
, shift
, fpst
);
3418 gen_helper_vfp_tould_round_to_zero(vd
, vd
, shift
, fpst
);
3421 g_assert_not_reached();
3424 vfp_store_reg64(vd
, a
->vd
);
3425 tcg_temp_free_i64(vd
);
3426 tcg_temp_free_ptr(fpst
);
3430 static bool trans_VCVT_hp_int(DisasContext
*s
, arg_VCVT_sp_int
*a
)
3435 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
3439 if (!vfp_access_check(s
)) {
3443 fpst
= fpstatus_ptr(FPST_FPCR_F16
);
3444 vm
= tcg_temp_new_i32();
3445 vfp_load_reg32(vm
, a
->vm
);
3449 gen_helper_vfp_tosizh(vm
, vm
, fpst
);
3451 gen_helper_vfp_tosih(vm
, vm
, fpst
);
3455 gen_helper_vfp_touizh(vm
, vm
, fpst
);
3457 gen_helper_vfp_touih(vm
, vm
, fpst
);
3460 vfp_store_reg32(vm
, a
->vd
);
3461 tcg_temp_free_i32(vm
);
3462 tcg_temp_free_ptr(fpst
);
3466 static bool trans_VCVT_sp_int(DisasContext
*s
, arg_VCVT_sp_int
*a
)
3471 if (!dc_isar_feature(aa32_fpsp_v2
, s
)) {
3475 if (!vfp_access_check(s
)) {
3479 fpst
= fpstatus_ptr(FPST_FPCR
);
3480 vm
= tcg_temp_new_i32();
3481 vfp_load_reg32(vm
, a
->vm
);
3485 gen_helper_vfp_tosizs(vm
, vm
, fpst
);
3487 gen_helper_vfp_tosis(vm
, vm
, fpst
);
3491 gen_helper_vfp_touizs(vm
, vm
, fpst
);
3493 gen_helper_vfp_touis(vm
, vm
, fpst
);
3496 vfp_store_reg32(vm
, a
->vd
);
3497 tcg_temp_free_i32(vm
);
3498 tcg_temp_free_ptr(fpst
);
3502 static bool trans_VCVT_dp_int(DisasContext
*s
, arg_VCVT_dp_int
*a
)
3508 if (!dc_isar_feature(aa32_fpdp_v2
, s
)) {
3512 /* UNDEF accesses to D16-D31 if they don't exist. */
3513 if (!dc_isar_feature(aa32_simd_r32
, s
) && (a
->vm
& 0x10)) {
3517 if (!vfp_access_check(s
)) {
3521 fpst
= fpstatus_ptr(FPST_FPCR
);
3522 vm
= tcg_temp_new_i64();
3523 vd
= tcg_temp_new_i32();
3524 vfp_load_reg64(vm
, a
->vm
);
3528 gen_helper_vfp_tosizd(vd
, vm
, fpst
);
3530 gen_helper_vfp_tosid(vd
, vm
, fpst
);
3534 gen_helper_vfp_touizd(vd
, vm
, fpst
);
3536 gen_helper_vfp_touid(vd
, vm
, fpst
);
3539 vfp_store_reg32(vd
, a
->vd
);
3540 tcg_temp_free_i32(vd
);
3541 tcg_temp_free_i64(vm
);
3542 tcg_temp_free_ptr(fpst
);
3546 static bool trans_VINS(DisasContext
*s
, arg_VINS
*a
)
3550 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
3554 if (s
->vec_len
!= 0 || s
->vec_stride
!= 0) {
3558 if (!vfp_access_check(s
)) {
3562 /* Insert low half of Vm into high half of Vd */
3563 rm
= tcg_temp_new_i32();
3564 rd
= tcg_temp_new_i32();
3565 vfp_load_reg32(rm
, a
->vm
);
3566 vfp_load_reg32(rd
, a
->vd
);
3567 tcg_gen_deposit_i32(rd
, rd
, rm
, 16, 16);
3568 vfp_store_reg32(rd
, a
->vd
);
3569 tcg_temp_free_i32(rm
);
3570 tcg_temp_free_i32(rd
);
3574 static bool trans_VMOVX(DisasContext
*s
, arg_VINS
*a
)
3578 if (!dc_isar_feature(aa32_fp16_arith
, s
)) {
3582 if (s
->vec_len
!= 0 || s
->vec_stride
!= 0) {
3586 if (!vfp_access_check(s
)) {
3590 /* Set Vd to high half of Vm */
3591 rm
= tcg_temp_new_i32();
3592 vfp_load_reg32(rm
, a
->vm
);
3593 tcg_gen_shri_i32(rm
, rm
, 16);
3594 vfp_store_reg32(rm
, a
->vd
);
3595 tcg_temp_free_i32(rm
);