x86: acpi: let the firmware handle pending "CPU remove" events in SMM
[qemu/ar7.git] / target / arm / translate-vfp.c.inc
blob96948f5a2d308ba9175fafef53190556b4ff27da
1 /*
2  *  ARM translation: AArch32 VFP instructions
3  *
4  *  Copyright (c) 2003 Fabrice Bellard
5  *  Copyright (c) 2005-2007 CodeSourcery
6  *  Copyright (c) 2007 OpenedHand, Ltd.
7  *  Copyright (c) 2019 Linaro, Ltd.
8  *
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.
13  *
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.
18  *
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/>.
21  */
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.
27  */
29 /* Include the generated VFP decoder */
30 #include "decode-vfp.c.inc"
31 #include "decode-vfp-uncond.c.inc"
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.
37  */
38 uint64_t vfp_expand_imm(int size, uint8_t imm8)
40     uint64_t imm;
42     switch (size) {
43     case MO_64:
44         imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
45             (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) |
46             extract32(imm8, 0, 6);
47         imm <<= 48;
48         break;
49     case MO_32:
50         imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
51             (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) |
52             (extract32(imm8, 0, 6) << 3);
53         imm <<= 16;
54         break;
55     case MO_16:
56         imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
57             (extract32(imm8, 6, 1) ? 0x3000 : 0x4000) |
58             (extract32(imm8, 0, 6) << 6);
59         break;
60     default:
61         g_assert_not_reached();
62     }
63     return imm;
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
69  * 16 bits.
70  */
71 static inline long vfp_f16_offset(unsigned reg, bool top)
73     long offs = vfp_reg_offset(false, reg);
74 #ifdef HOST_WORDS_BIGENDIAN
75     if (!top) {
76         offs += 2;
77     }
78 #else
79     if (top) {
80         offs += 2;
81     }
82 #endif
83     return offs;
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
90  * return false.
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.
94  */
95 static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled)
97     if (s->fp_excp_el) {
98         /* M-profile handled this earlier, in disas_m_nocp() */
99         assert (!arm_dc_feature(s, ARM_FEATURE_M));
100         gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
101                            syn_fp_access_trap(1, 0xe, false),
102                            s->fp_excp_el);
103         return false;
104     }
106     if (!s->vfp_enabled && !ignore_vfp_enabled) {
107         assert(!arm_dc_feature(s, ARM_FEATURE_M));
108         unallocated_encoding(s);
109         return false;
110     }
112     if (arm_dc_feature(s, ARM_FEATURE_M)) {
113         /* Handle M-profile lazy FP state mechanics */
115         /* Trigger lazy-state preservation if necessary */
116         if (s->v7m_lspact) {
117             /*
118              * Lazy state saving affects external memory and also the NVIC,
119              * so we must mark it as an IO operation for icount (and cause
120              * this to be the last insn in the TB).
121              */
122             if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
123                 s->base.is_jmp = DISAS_UPDATE_EXIT;
124                 gen_io_start();
125             }
126             gen_helper_v7m_preserve_fp_state(cpu_env);
127             /*
128              * If the preserve_fp_state helper doesn't throw an exception
129              * then it will clear LSPACT; we don't need to repeat this for
130              * any further FP insns in this TB.
131              */
132             s->v7m_lspact = false;
133         }
135         /* Update ownership of FP context: set FPCCR.S to match current state */
136         if (s->v8m_fpccr_s_wrong) {
137             TCGv_i32 tmp;
139             tmp = load_cpu_field(v7m.fpccr[M_REG_S]);
140             if (s->v8m_secure) {
141                 tcg_gen_ori_i32(tmp, tmp, R_V7M_FPCCR_S_MASK);
142             } else {
143                 tcg_gen_andi_i32(tmp, tmp, ~R_V7M_FPCCR_S_MASK);
144             }
145             store_cpu_field(tmp, v7m.fpccr[M_REG_S]);
146             /* Don't need to do this for any further FP insns in this TB */
147             s->v8m_fpccr_s_wrong = false;
148         }
150         if (s->v7m_new_fp_ctxt_needed) {
151             /*
152              * Create new FP context by updating CONTROL.FPCA, CONTROL.SFPA
153              * and the FPSCR.
154              */
155             TCGv_i32 control, fpscr;
156             uint32_t bits = R_V7M_CONTROL_FPCA_MASK;
158             fpscr = load_cpu_field(v7m.fpdscr[s->v8m_secure]);
159             gen_helper_vfp_set_fpscr(cpu_env, fpscr);
160             tcg_temp_free_i32(fpscr);
161             /*
162              * We don't need to arrange to end the TB, because the only
163              * parts of FPSCR which we cache in the TB flags are the VECLEN
164              * and VECSTRIDE, and those don't exist for M-profile.
165              */
167             if (s->v8m_secure) {
168                 bits |= R_V7M_CONTROL_SFPA_MASK;
169             }
170             control = load_cpu_field(v7m.control[M_REG_S]);
171             tcg_gen_ori_i32(control, control, bits);
172             store_cpu_field(control, v7m.control[M_REG_S]);
173             /* Don't need to do this for any further FP insns in this TB */
174             s->v7m_new_fp_ctxt_needed = false;
175         }
176     }
178     return true;
182  * The most usual kind of VFP access check, for everything except
183  * FMXR/FMRX to the always-available special registers.
184  */
185 static bool vfp_access_check(DisasContext *s)
187     return full_vfp_access_check(s, false);
190 static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
192     uint32_t rd, rn, rm;
193     int sz = a->sz;
195     if (!dc_isar_feature(aa32_vsel, s)) {
196         return false;
197     }
199     if (sz == 3 && !dc_isar_feature(aa32_fpdp_v2, s)) {
200         return false;
201     }
203     if (sz == 1 && !dc_isar_feature(aa32_fp16_arith, s)) {
204         return false;
205     }
207     /* UNDEF accesses to D16-D31 if they don't exist */
208     if (sz == 3 && !dc_isar_feature(aa32_simd_r32, s) &&
209         ((a->vm | a->vn | a->vd) & 0x10)) {
210         return false;
211     }
213     rd = a->vd;
214     rn = a->vn;
215     rm = a->vm;
217     if (!vfp_access_check(s)) {
218         return true;
219     }
221     if (sz == 3) {
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         vfp_load_reg64(frn, rn);
240         vfp_load_reg64(frm, rm);
241         switch (a->cc) {
242         case 0: /* eq: Z */
243             tcg_gen_movcond_i64(TCG_COND_EQ, dest, zf, zero,
244                                 frn, frm);
245             break;
246         case 1: /* vs: V */
247             tcg_gen_movcond_i64(TCG_COND_LT, dest, vf, zero,
248                                 frn, frm);
249             break;
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,
254                                 frn, frm);
255             tcg_temp_free_i64(tmp);
256             break;
257         case 3: /* gt: !Z && N == V */
258             tcg_gen_movcond_i64(TCG_COND_NE, dest, zf, zero,
259                                 frn, frm);
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,
263                                 dest, frm);
264             tcg_temp_free_i64(tmp);
265             break;
266         }
267         vfp_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);
277     } else {
278         TCGv_i32 frn, frm, dest;
279         TCGv_i32 tmp, zero;
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         vfp_load_reg32(frn, rn);
287         vfp_load_reg32(frm, rm);
288         switch (a->cc) {
289         case 0: /* eq: Z */
290             tcg_gen_movcond_i32(TCG_COND_EQ, dest, cpu_ZF, zero,
291                                 frn, frm);
292             break;
293         case 1: /* vs: V */
294             tcg_gen_movcond_i32(TCG_COND_LT, dest, cpu_VF, zero,
295                                 frn, frm);
296             break;
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,
301                                 frn, frm);
302             tcg_temp_free_i32(tmp);
303             break;
304         case 3: /* gt: !Z && N == V */
305             tcg_gen_movcond_i32(TCG_COND_NE, dest, cpu_ZF, zero,
306                                 frn, frm);
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,
310                                 dest, frm);
311             tcg_temp_free_i32(tmp);
312             break;
313         }
314         /* For fp16 the top half is always zeroes */
315         if (sz == 1) {
316             tcg_gen_andi_i32(dest, dest, 0xffff);
317         }
318         vfp_store_reg32(dest, rd);
319         tcg_temp_free_i32(frn);
320         tcg_temp_free_i32(frm);
321         tcg_temp_free_i32(dest);
323         tcg_temp_free_i32(zero);
324     }
326     return true;
330  * Table for converting the most common AArch32 encoding of
331  * rounding mode to arm_fprounding order (which matches the
332  * common AArch64 order); see ARM ARM pseudocode FPDecodeRM().
333  */
334 static const uint8_t fp_decode_rm[] = {
335     FPROUNDING_TIEAWAY,
336     FPROUNDING_TIEEVEN,
337     FPROUNDING_POSINF,
338     FPROUNDING_NEGINF,
341 static bool trans_VRINT(DisasContext *s, arg_VRINT *a)
343     uint32_t rd, rm;
344     int sz = a->sz;
345     TCGv_ptr fpst;
346     TCGv_i32 tcg_rmode;
347     int rounding = fp_decode_rm[a->rm];
349     if (!dc_isar_feature(aa32_vrint, s)) {
350         return false;
351     }
353     if (sz == 3 && !dc_isar_feature(aa32_fpdp_v2, s)) {
354         return false;
355     }
357     if (sz == 1 && !dc_isar_feature(aa32_fp16_arith, s)) {
358         return false;
359     }
361     /* UNDEF accesses to D16-D31 if they don't exist */
362     if (sz == 3 && !dc_isar_feature(aa32_simd_r32, s) &&
363         ((a->vm | a->vd) & 0x10)) {
364         return false;
365     }
367     rd = a->vd;
368     rm = a->vm;
370     if (!vfp_access_check(s)) {
371         return true;
372     }
374     if (sz == 1) {
375         fpst = fpstatus_ptr(FPST_FPCR_F16);
376     } else {
377         fpst = fpstatus_ptr(FPST_FPCR);
378     }
380     tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding));
381     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
383     if (sz == 3) {
384         TCGv_i64 tcg_op;
385         TCGv_i64 tcg_res;
386         tcg_op = tcg_temp_new_i64();
387         tcg_res = tcg_temp_new_i64();
388         vfp_load_reg64(tcg_op, rm);
389         gen_helper_rintd(tcg_res, tcg_op, fpst);
390         vfp_store_reg64(tcg_res, rd);
391         tcg_temp_free_i64(tcg_op);
392         tcg_temp_free_i64(tcg_res);
393     } else {
394         TCGv_i32 tcg_op;
395         TCGv_i32 tcg_res;
396         tcg_op = tcg_temp_new_i32();
397         tcg_res = tcg_temp_new_i32();
398         vfp_load_reg32(tcg_op, rm);
399         if (sz == 1) {
400             gen_helper_rinth(tcg_res, tcg_op, fpst);
401         } else {
402             gen_helper_rints(tcg_res, tcg_op, fpst);
403         }
404         vfp_store_reg32(tcg_res, rd);
405         tcg_temp_free_i32(tcg_op);
406         tcg_temp_free_i32(tcg_res);
407     }
409     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
410     tcg_temp_free_i32(tcg_rmode);
412     tcg_temp_free_ptr(fpst);
413     return true;
416 static bool trans_VCVT(DisasContext *s, arg_VCVT *a)
418     uint32_t rd, rm;
419     int sz = a->sz;
420     TCGv_ptr fpst;
421     TCGv_i32 tcg_rmode, tcg_shift;
422     int rounding = fp_decode_rm[a->rm];
423     bool is_signed = a->op;
425     if (!dc_isar_feature(aa32_vcvt_dr, s)) {
426         return false;
427     }
429     if (sz == 3 && !dc_isar_feature(aa32_fpdp_v2, s)) {
430         return false;
431     }
433     if (sz == 1 && !dc_isar_feature(aa32_fp16_arith, s)) {
434         return false;
435     }
437     /* UNDEF accesses to D16-D31 if they don't exist */
438     if (sz == 3 && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
439         return false;
440     }
442     rd = a->vd;
443     rm = a->vm;
445     if (!vfp_access_check(s)) {
446         return true;
447     }
449     if (sz == 1) {
450         fpst = fpstatus_ptr(FPST_FPCR_F16);
451     } else {
452         fpst = fpstatus_ptr(FPST_FPCR);
453     }
455     tcg_shift = tcg_const_i32(0);
457     tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding));
458     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
460     if (sz == 3) {
461         TCGv_i64 tcg_double, tcg_res;
462         TCGv_i32 tcg_tmp;
463         tcg_double = tcg_temp_new_i64();
464         tcg_res = tcg_temp_new_i64();
465         tcg_tmp = tcg_temp_new_i32();
466         vfp_load_reg64(tcg_double, rm);
467         if (is_signed) {
468             gen_helper_vfp_tosld(tcg_res, tcg_double, tcg_shift, fpst);
469         } else {
470             gen_helper_vfp_tould(tcg_res, tcg_double, tcg_shift, fpst);
471         }
472         tcg_gen_extrl_i64_i32(tcg_tmp, tcg_res);
473         vfp_store_reg32(tcg_tmp, rd);
474         tcg_temp_free_i32(tcg_tmp);
475         tcg_temp_free_i64(tcg_res);
476         tcg_temp_free_i64(tcg_double);
477     } else {
478         TCGv_i32 tcg_single, tcg_res;
479         tcg_single = tcg_temp_new_i32();
480         tcg_res = tcg_temp_new_i32();
481         vfp_load_reg32(tcg_single, rm);
482         if (sz == 1) {
483             if (is_signed) {
484                 gen_helper_vfp_toslh(tcg_res, tcg_single, tcg_shift, fpst);
485             } else {
486                 gen_helper_vfp_toulh(tcg_res, tcg_single, tcg_shift, fpst);
487             }
488         } else {
489             if (is_signed) {
490                 gen_helper_vfp_tosls(tcg_res, tcg_single, tcg_shift, fpst);
491             } else {
492                 gen_helper_vfp_touls(tcg_res, tcg_single, tcg_shift, fpst);
493             }
494         }
495         vfp_store_reg32(tcg_res, rd);
496         tcg_temp_free_i32(tcg_res);
497         tcg_temp_free_i32(tcg_single);
498     }
500     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
501     tcg_temp_free_i32(tcg_rmode);
503     tcg_temp_free_i32(tcg_shift);
505     tcg_temp_free_ptr(fpst);
507     return true;
510 static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a)
512     /* VMOV scalar to general purpose register */
513     TCGv_i32 tmp;
515     /* SIZE == MO_32 is a VFP instruction; otherwise NEON.  */
516     if (a->size == MO_32
517         ? !dc_isar_feature(aa32_fpsp_v2, s)
518         : !arm_dc_feature(s, ARM_FEATURE_NEON)) {
519         return false;
520     }
522     /* UNDEF accesses to D16-D31 if they don't exist */
523     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
524         return false;
525     }
527     if (!vfp_access_check(s)) {
528         return true;
529     }
531     tmp = tcg_temp_new_i32();
532     read_neon_element32(tmp, a->vn, a->index, a->size | (a->u ? 0 : MO_SIGN));
533     store_reg(s, a->rt, tmp);
535     return true;
538 static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a)
540     /* VMOV general purpose register to scalar */
541     TCGv_i32 tmp;
543     /* SIZE == MO_32 is a VFP instruction; otherwise NEON.  */
544     if (a->size == MO_32
545         ? !dc_isar_feature(aa32_fpsp_v2, s)
546         : !arm_dc_feature(s, ARM_FEATURE_NEON)) {
547         return false;
548     }
550     /* UNDEF accesses to D16-D31 if they don't exist */
551     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
552         return false;
553     }
555     if (!vfp_access_check(s)) {
556         return true;
557     }
559     tmp = load_reg(s, a->rt);
560     write_neon_element32(tmp, a->vn, a->index, a->size);
561     tcg_temp_free_i32(tmp);
563     return true;
566 static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
568     /* VDUP (general purpose register) */
569     TCGv_i32 tmp;
570     int size, vec_size;
572     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
573         return false;
574     }
576     /* UNDEF accesses to D16-D31 if they don't exist */
577     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
578         return false;
579     }
581     if (a->b && a->e) {
582         return false;
583     }
585     if (a->q && (a->vn & 1)) {
586         return false;
587     }
589     vec_size = a->q ? 16 : 8;
590     if (a->b) {
591         size = 0;
592     } else if (a->e) {
593         size = 1;
594     } else {
595         size = 2;
596     }
598     if (!vfp_access_check(s)) {
599         return true;
600     }
602     tmp = load_reg(s, a->rt);
603     tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(a->vn),
604                          vec_size, vec_size, tmp);
605     tcg_temp_free_i32(tmp);
607     return true;
610 static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
612     TCGv_i32 tmp;
613     bool ignore_vfp_enabled = false;
615     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
616         return false;
617     }
619     if (arm_dc_feature(s, ARM_FEATURE_M)) {
620         /*
621          * The only M-profile VFP vmrs/vmsr sysreg is FPSCR.
622          * Accesses to R15 are UNPREDICTABLE; we choose to undef.
623          * (FPSCR -> r15 is a special case which writes to the PSR flags.)
624          */
625         if (a->rt == 15 && (!a->l || a->reg != ARM_VFP_FPSCR)) {
626             return false;
627         }
628     }
630     switch (a->reg) {
631     case ARM_VFP_FPSID:
632         /*
633          * VFPv2 allows access to FPSID from userspace; VFPv3 restricts
634          * all ID registers to privileged access only.
635          */
636         if (IS_USER(s) && dc_isar_feature(aa32_fpsp_v3, s)) {
637             return false;
638         }
639         ignore_vfp_enabled = true;
640         break;
641     case ARM_VFP_MVFR0:
642     case ARM_VFP_MVFR1:
643         if (IS_USER(s) || !arm_dc_feature(s, ARM_FEATURE_MVFR)) {
644             return false;
645         }
646         ignore_vfp_enabled = true;
647         break;
648     case ARM_VFP_MVFR2:
649         if (IS_USER(s) || !arm_dc_feature(s, ARM_FEATURE_V8)) {
650             return false;
651         }
652         ignore_vfp_enabled = true;
653         break;
654     case ARM_VFP_FPSCR:
655         break;
656     case ARM_VFP_FPEXC:
657         if (IS_USER(s)) {
658             return false;
659         }
660         ignore_vfp_enabled = true;
661         break;
662     case ARM_VFP_FPINST:
663     case ARM_VFP_FPINST2:
664         /* Not present in VFPv3 */
665         if (IS_USER(s) || dc_isar_feature(aa32_fpsp_v3, s)) {
666             return false;
667         }
668         break;
669     default:
670         return false;
671     }
673     if (!full_vfp_access_check(s, ignore_vfp_enabled)) {
674         return true;
675     }
677     if (a->l) {
678         /* VMRS, move VFP special register to gp register */
679         switch (a->reg) {
680         case ARM_VFP_MVFR0:
681         case ARM_VFP_MVFR1:
682         case ARM_VFP_MVFR2:
683         case ARM_VFP_FPSID:
684             if (s->current_el == 1) {
685                 TCGv_i32 tcg_reg, tcg_rt;
687                 gen_set_condexec(s);
688                 gen_set_pc_im(s, s->pc_curr);
689                 tcg_reg = tcg_const_i32(a->reg);
690                 tcg_rt = tcg_const_i32(a->rt);
691                 gen_helper_check_hcr_el2_trap(cpu_env, tcg_rt, tcg_reg);
692                 tcg_temp_free_i32(tcg_reg);
693                 tcg_temp_free_i32(tcg_rt);
694             }
695             /* fall through */
696         case ARM_VFP_FPEXC:
697         case ARM_VFP_FPINST:
698         case ARM_VFP_FPINST2:
699             tmp = load_cpu_field(vfp.xregs[a->reg]);
700             break;
701         case ARM_VFP_FPSCR:
702             if (a->rt == 15) {
703                 tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
704                 tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
705             } else {
706                 tmp = tcg_temp_new_i32();
707                 gen_helper_vfp_get_fpscr(tmp, cpu_env);
708             }
709             break;
710         default:
711             g_assert_not_reached();
712         }
714         if (a->rt == 15) {
715             /* Set the 4 flag bits in the CPSR.  */
716             gen_set_nzcv(tmp);
717             tcg_temp_free_i32(tmp);
718         } else {
719             store_reg(s, a->rt, tmp);
720         }
721     } else {
722         /* VMSR, move gp register to VFP special register */
723         switch (a->reg) {
724         case ARM_VFP_FPSID:
725         case ARM_VFP_MVFR0:
726         case ARM_VFP_MVFR1:
727         case ARM_VFP_MVFR2:
728             /* Writes are ignored.  */
729             break;
730         case ARM_VFP_FPSCR:
731             tmp = load_reg(s, a->rt);
732             gen_helper_vfp_set_fpscr(cpu_env, tmp);
733             tcg_temp_free_i32(tmp);
734             gen_lookup_tb(s);
735             break;
736         case ARM_VFP_FPEXC:
737             /*
738              * TODO: VFP subarchitecture support.
739              * For now, keep the EN bit only
740              */
741             tmp = load_reg(s, a->rt);
742             tcg_gen_andi_i32(tmp, tmp, 1 << 30);
743             store_cpu_field(tmp, vfp.xregs[a->reg]);
744             gen_lookup_tb(s);
745             break;
746         case ARM_VFP_FPINST:
747         case ARM_VFP_FPINST2:
748             tmp = load_reg(s, a->rt);
749             store_cpu_field(tmp, vfp.xregs[a->reg]);
750             break;
751         default:
752             g_assert_not_reached();
753         }
754     }
756     return true;
759 static bool trans_VMOV_half(DisasContext *s, arg_VMOV_single *a)
761     TCGv_i32 tmp;
763     if (!dc_isar_feature(aa32_fp16_arith, s)) {
764         return false;
765     }
767     if (a->rt == 15) {
768         /* UNPREDICTABLE; we choose to UNDEF */
769         return false;
770     }
772     if (!vfp_access_check(s)) {
773         return true;
774     }
776     if (a->l) {
777         /* VFP to general purpose register */
778         tmp = tcg_temp_new_i32();
779         vfp_load_reg32(tmp, a->vn);
780         tcg_gen_andi_i32(tmp, tmp, 0xffff);
781         store_reg(s, a->rt, tmp);
782     } else {
783         /* general purpose register to VFP */
784         tmp = load_reg(s, a->rt);
785         tcg_gen_andi_i32(tmp, tmp, 0xffff);
786         vfp_store_reg32(tmp, a->vn);
787         tcg_temp_free_i32(tmp);
788     }
790     return true;
793 static bool trans_VMOV_single(DisasContext *s, arg_VMOV_single *a)
795     TCGv_i32 tmp;
797     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
798         return false;
799     }
801     if (!vfp_access_check(s)) {
802         return true;
803     }
805     if (a->l) {
806         /* VFP to general purpose register */
807         tmp = tcg_temp_new_i32();
808         vfp_load_reg32(tmp, a->vn);
809         if (a->rt == 15) {
810             /* Set the 4 flag bits in the CPSR.  */
811             gen_set_nzcv(tmp);
812             tcg_temp_free_i32(tmp);
813         } else {
814             store_reg(s, a->rt, tmp);
815         }
816     } else {
817         /* general purpose register to VFP */
818         tmp = load_reg(s, a->rt);
819         vfp_store_reg32(tmp, a->vn);
820         tcg_temp_free_i32(tmp);
821     }
823     return true;
826 static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a)
828     TCGv_i32 tmp;
830     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
831         return false;
832     }
834     /*
835      * VMOV between two general-purpose registers and two single precision
836      * floating point registers
837      */
838     if (!vfp_access_check(s)) {
839         return true;
840     }
842     if (a->op) {
843         /* fpreg to gpreg */
844         tmp = tcg_temp_new_i32();
845         vfp_load_reg32(tmp, a->vm);
846         store_reg(s, a->rt, tmp);
847         tmp = tcg_temp_new_i32();
848         vfp_load_reg32(tmp, a->vm + 1);
849         store_reg(s, a->rt2, tmp);
850     } else {
851         /* gpreg to fpreg */
852         tmp = load_reg(s, a->rt);
853         vfp_store_reg32(tmp, a->vm);
854         tcg_temp_free_i32(tmp);
855         tmp = load_reg(s, a->rt2);
856         vfp_store_reg32(tmp, a->vm + 1);
857         tcg_temp_free_i32(tmp);
858     }
860     return true;
863 static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_dp *a)
865     TCGv_i32 tmp;
867     /*
868      * VMOV between two general-purpose registers and one double precision
869      * floating point register.  Note that this does not require support
870      * for double precision arithmetic.
871      */
872     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
873         return false;
874     }
876     /* UNDEF accesses to D16-D31 if they don't exist */
877     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
878         return false;
879     }
881     if (!vfp_access_check(s)) {
882         return true;
883     }
885     if (a->op) {
886         /* fpreg to gpreg */
887         tmp = tcg_temp_new_i32();
888         vfp_load_reg32(tmp, a->vm * 2);
889         store_reg(s, a->rt, tmp);
890         tmp = tcg_temp_new_i32();
891         vfp_load_reg32(tmp, a->vm * 2 + 1);
892         store_reg(s, a->rt2, tmp);
893     } else {
894         /* gpreg to fpreg */
895         tmp = load_reg(s, a->rt);
896         vfp_store_reg32(tmp, a->vm * 2);
897         tcg_temp_free_i32(tmp);
898         tmp = load_reg(s, a->rt2);
899         vfp_store_reg32(tmp, a->vm * 2 + 1);
900         tcg_temp_free_i32(tmp);
901     }
903     return true;
906 static bool trans_VLDR_VSTR_hp(DisasContext *s, arg_VLDR_VSTR_sp *a)
908     uint32_t offset;
909     TCGv_i32 addr, tmp;
911     if (!dc_isar_feature(aa32_fp16_arith, s)) {
912         return false;
913     }
915     if (!vfp_access_check(s)) {
916         return true;
917     }
919     /* imm8 field is offset/2 for fp16, unlike fp32 and fp64 */
920     offset = a->imm << 1;
921     if (!a->u) {
922         offset = -offset;
923     }
925     /* For thumb, use of PC is UNPREDICTABLE.  */
926     addr = add_reg_for_lit(s, a->rn, offset);
927     tmp = tcg_temp_new_i32();
928     if (a->l) {
929         gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
930         vfp_store_reg32(tmp, a->vd);
931     } else {
932         vfp_load_reg32(tmp, a->vd);
933         gen_aa32_st16(s, tmp, addr, get_mem_index(s));
934     }
935     tcg_temp_free_i32(tmp);
936     tcg_temp_free_i32(addr);
938     return true;
941 static bool trans_VLDR_VSTR_sp(DisasContext *s, arg_VLDR_VSTR_sp *a)
943     uint32_t offset;
944     TCGv_i32 addr, tmp;
946     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
947         return false;
948     }
950     if (!vfp_access_check(s)) {
951         return true;
952     }
954     offset = a->imm << 2;
955     if (!a->u) {
956         offset = -offset;
957     }
959     /* For thumb, use of PC is UNPREDICTABLE.  */
960     addr = add_reg_for_lit(s, a->rn, offset);
961     tmp = tcg_temp_new_i32();
962     if (a->l) {
963         gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
964         vfp_store_reg32(tmp, a->vd);
965     } else {
966         vfp_load_reg32(tmp, a->vd);
967         gen_aa32_st32(s, tmp, addr, get_mem_index(s));
968     }
969     tcg_temp_free_i32(tmp);
970     tcg_temp_free_i32(addr);
972     return true;
975 static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a)
977     uint32_t offset;
978     TCGv_i32 addr;
979     TCGv_i64 tmp;
981     /* Note that this does not require support for double arithmetic.  */
982     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
983         return false;
984     }
986     /* UNDEF accesses to D16-D31 if they don't exist */
987     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
988         return false;
989     }
991     if (!vfp_access_check(s)) {
992         return true;
993     }
995     offset = a->imm << 2;
996     if (!a->u) {
997         offset = -offset;
998     }
1000     /* For thumb, use of PC is UNPREDICTABLE.  */
1001     addr = add_reg_for_lit(s, a->rn, offset);
1002     tmp = tcg_temp_new_i64();
1003     if (a->l) {
1004         gen_aa32_ld64(s, tmp, addr, get_mem_index(s));
1005         vfp_store_reg64(tmp, a->vd);
1006     } else {
1007         vfp_load_reg64(tmp, a->vd);
1008         gen_aa32_st64(s, tmp, addr, get_mem_index(s));
1009     }
1010     tcg_temp_free_i64(tmp);
1011     tcg_temp_free_i32(addr);
1013     return true;
1016 static bool trans_VLDM_VSTM_sp(DisasContext *s, arg_VLDM_VSTM_sp *a)
1018     uint32_t offset;
1019     TCGv_i32 addr, tmp;
1020     int i, n;
1022     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1023         return false;
1024     }
1026     n = a->imm;
1028     if (n == 0 || (a->vd + n) > 32) {
1029         /*
1030          * UNPREDICTABLE cases for bad immediates: we choose to
1031          * UNDEF to avoid generating huge numbers of TCG ops
1032          */
1033         return false;
1034     }
1035     if (a->rn == 15 && a->w) {
1036         /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1037         return false;
1038     }
1040     if (!vfp_access_check(s)) {
1041         return true;
1042     }
1044     /* For thumb, use of PC is UNPREDICTABLE.  */
1045     addr = add_reg_for_lit(s, a->rn, 0);
1046     if (a->p) {
1047         /* pre-decrement */
1048         tcg_gen_addi_i32(addr, addr, -(a->imm << 2));
1049     }
1051     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
1052         /*
1053          * Here 'addr' is the lowest address we will store to,
1054          * and is either the old SP (if post-increment) or
1055          * the new SP (if pre-decrement). For post-increment
1056          * where the old value is below the limit and the new
1057          * value is above, it is UNKNOWN whether the limit check
1058          * triggers; we choose to trigger.
1059          */
1060         gen_helper_v8m_stackcheck(cpu_env, addr);
1061     }
1063     offset = 4;
1064     tmp = tcg_temp_new_i32();
1065     for (i = 0; i < n; i++) {
1066         if (a->l) {
1067             /* load */
1068             gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
1069             vfp_store_reg32(tmp, a->vd + i);
1070         } else {
1071             /* store */
1072             vfp_load_reg32(tmp, a->vd + i);
1073             gen_aa32_st32(s, tmp, addr, get_mem_index(s));
1074         }
1075         tcg_gen_addi_i32(addr, addr, offset);
1076     }
1077     tcg_temp_free_i32(tmp);
1078     if (a->w) {
1079         /* writeback */
1080         if (a->p) {
1081             offset = -offset * n;
1082             tcg_gen_addi_i32(addr, addr, offset);
1083         }
1084         store_reg(s, a->rn, addr);
1085     } else {
1086         tcg_temp_free_i32(addr);
1087     }
1089     return true;
1092 static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a)
1094     uint32_t offset;
1095     TCGv_i32 addr;
1096     TCGv_i64 tmp;
1097     int i, n;
1099     /* Note that this does not require support for double arithmetic.  */
1100     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1101         return false;
1102     }
1104     n = a->imm >> 1;
1106     if (n == 0 || (a->vd + n) > 32 || n > 16) {
1107         /*
1108          * UNPREDICTABLE cases for bad immediates: we choose to
1109          * UNDEF to avoid generating huge numbers of TCG ops
1110          */
1111         return false;
1112     }
1113     if (a->rn == 15 && a->w) {
1114         /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1115         return false;
1116     }
1118     /* UNDEF accesses to D16-D31 if they don't exist */
1119     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd + n) > 16) {
1120         return false;
1121     }
1123     if (!vfp_access_check(s)) {
1124         return true;
1125     }
1127     /* For thumb, use of PC is UNPREDICTABLE.  */
1128     addr = add_reg_for_lit(s, a->rn, 0);
1129     if (a->p) {
1130         /* pre-decrement */
1131         tcg_gen_addi_i32(addr, addr, -(a->imm << 2));
1132     }
1134     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
1135         /*
1136          * Here 'addr' is the lowest address we will store to,
1137          * and is either the old SP (if post-increment) or
1138          * the new SP (if pre-decrement). For post-increment
1139          * where the old value is below the limit and the new
1140          * value is above, it is UNKNOWN whether the limit check
1141          * triggers; we choose to trigger.
1142          */
1143         gen_helper_v8m_stackcheck(cpu_env, addr);
1144     }
1146     offset = 8;
1147     tmp = tcg_temp_new_i64();
1148     for (i = 0; i < n; i++) {
1149         if (a->l) {
1150             /* load */
1151             gen_aa32_ld64(s, tmp, addr, get_mem_index(s));
1152             vfp_store_reg64(tmp, a->vd + i);
1153         } else {
1154             /* store */
1155             vfp_load_reg64(tmp, a->vd + i);
1156             gen_aa32_st64(s, tmp, addr, get_mem_index(s));
1157         }
1158         tcg_gen_addi_i32(addr, addr, offset);
1159     }
1160     tcg_temp_free_i64(tmp);
1161     if (a->w) {
1162         /* writeback */
1163         if (a->p) {
1164             offset = -offset * n;
1165         } else if (a->imm & 1) {
1166             offset = 4;
1167         } else {
1168             offset = 0;
1169         }
1171         if (offset != 0) {
1172             tcg_gen_addi_i32(addr, addr, offset);
1173         }
1174         store_reg(s, a->rn, addr);
1175     } else {
1176         tcg_temp_free_i32(addr);
1177     }
1179     return true;
1183  * Types for callbacks for do_vfp_3op_sp() and do_vfp_3op_dp().
1184  * The callback should emit code to write a value to vd. If
1185  * do_vfp_3op_{sp,dp}() was passed reads_vd then the TCGv vd
1186  * will contain the old value of the relevant VFP register;
1187  * otherwise it must be written to only.
1188  */
1189 typedef void VFPGen3OpSPFn(TCGv_i32 vd,
1190                            TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst);
1191 typedef void VFPGen3OpDPFn(TCGv_i64 vd,
1192                            TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst);
1195  * Types for callbacks for do_vfp_2op_sp() and do_vfp_2op_dp().
1196  * The callback should emit code to write a value to vd (which
1197  * should be written to only).
1198  */
1199 typedef void VFPGen2OpSPFn(TCGv_i32 vd, TCGv_i32 vm);
1200 typedef void VFPGen2OpDPFn(TCGv_i64 vd, TCGv_i64 vm);
1203  * Return true if the specified S reg is in a scalar bank
1204  * (ie if it is s0..s7)
1205  */
1206 static inline bool vfp_sreg_is_scalar(int reg)
1208     return (reg & 0x18) == 0;
1212  * Return true if the specified D reg is in a scalar bank
1213  * (ie if it is d0..d3 or d16..d19)
1214  */
1215 static inline bool vfp_dreg_is_scalar(int reg)
1217     return (reg & 0xc) == 0;
1221  * Advance the S reg number forwards by delta within its bank
1222  * (ie increment the low 3 bits but leave the rest the same)
1223  */
1224 static inline int vfp_advance_sreg(int reg, int delta)
1226     return ((reg + delta) & 0x7) | (reg & ~0x7);
1230  * Advance the D reg number forwards by delta within its bank
1231  * (ie increment the low 2 bits but leave the rest the same)
1232  */
1233 static inline int vfp_advance_dreg(int reg, int delta)
1235     return ((reg + delta) & 0x3) | (reg & ~0x3);
1239  * Perform a 3-operand VFP data processing instruction. fn is the
1240  * callback to do the actual operation; this function deals with the
1241  * code to handle looping around for VFP vector processing.
1242  */
1243 static bool do_vfp_3op_sp(DisasContext *s, VFPGen3OpSPFn *fn,
1244                           int vd, int vn, int vm, bool reads_vd)
1246     uint32_t delta_m = 0;
1247     uint32_t delta_d = 0;
1248     int veclen = s->vec_len;
1249     TCGv_i32 f0, f1, fd;
1250     TCGv_ptr fpst;
1252     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1253         return false;
1254     }
1256     if (!dc_isar_feature(aa32_fpshvec, s) &&
1257         (veclen != 0 || s->vec_stride != 0)) {
1258         return false;
1259     }
1261     if (!vfp_access_check(s)) {
1262         return true;
1263     }
1265     if (veclen > 0) {
1266         /* Figure out what type of vector operation this is.  */
1267         if (vfp_sreg_is_scalar(vd)) {
1268             /* scalar */
1269             veclen = 0;
1270         } else {
1271             delta_d = s->vec_stride + 1;
1273             if (vfp_sreg_is_scalar(vm)) {
1274                 /* mixed scalar/vector */
1275                 delta_m = 0;
1276             } else {
1277                 /* vector */
1278                 delta_m = delta_d;
1279             }
1280         }
1281     }
1283     f0 = tcg_temp_new_i32();
1284     f1 = tcg_temp_new_i32();
1285     fd = tcg_temp_new_i32();
1286     fpst = fpstatus_ptr(FPST_FPCR);
1288     vfp_load_reg32(f0, vn);
1289     vfp_load_reg32(f1, vm);
1291     for (;;) {
1292         if (reads_vd) {
1293             vfp_load_reg32(fd, vd);
1294         }
1295         fn(fd, f0, f1, fpst);
1296         vfp_store_reg32(fd, vd);
1298         if (veclen == 0) {
1299             break;
1300         }
1302         /* Set up the operands for the next iteration */
1303         veclen--;
1304         vd = vfp_advance_sreg(vd, delta_d);
1305         vn = vfp_advance_sreg(vn, delta_d);
1306         vfp_load_reg32(f0, vn);
1307         if (delta_m) {
1308             vm = vfp_advance_sreg(vm, delta_m);
1309             vfp_load_reg32(f1, vm);
1310         }
1311     }
1313     tcg_temp_free_i32(f0);
1314     tcg_temp_free_i32(f1);
1315     tcg_temp_free_i32(fd);
1316     tcg_temp_free_ptr(fpst);
1318     return true;
1321 static bool do_vfp_3op_hp(DisasContext *s, VFPGen3OpSPFn *fn,
1322                           int vd, int vn, int vm, bool reads_vd)
1324     /*
1325      * Do a half-precision operation. Functionally this is
1326      * the same as do_vfp_3op_sp(), except:
1327      *  - it uses the FPST_FPCR_F16
1328      *  - it doesn't need the VFP vector handling (fp16 is a
1329      *    v8 feature, and in v8 VFP vectors don't exist)
1330      *  - it does the aa32_fp16_arith feature test
1331      */
1332     TCGv_i32 f0, f1, fd;
1333     TCGv_ptr fpst;
1335     if (!dc_isar_feature(aa32_fp16_arith, s)) {
1336         return false;
1337     }
1339     if (s->vec_len != 0 || s->vec_stride != 0) {
1340         return false;
1341     }
1343     if (!vfp_access_check(s)) {
1344         return true;
1345     }
1347     f0 = tcg_temp_new_i32();
1348     f1 = tcg_temp_new_i32();
1349     fd = tcg_temp_new_i32();
1350     fpst = fpstatus_ptr(FPST_FPCR_F16);
1352     vfp_load_reg32(f0, vn);
1353     vfp_load_reg32(f1, vm);
1355     if (reads_vd) {
1356         vfp_load_reg32(fd, vd);
1357     }
1358     fn(fd, f0, f1, fpst);
1359     vfp_store_reg32(fd, vd);
1361     tcg_temp_free_i32(f0);
1362     tcg_temp_free_i32(f1);
1363     tcg_temp_free_i32(fd);
1364     tcg_temp_free_ptr(fpst);
1366     return true;
1369 static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn,
1370                           int vd, int vn, int vm, bool reads_vd)
1372     uint32_t delta_m = 0;
1373     uint32_t delta_d = 0;
1374     int veclen = s->vec_len;
1375     TCGv_i64 f0, f1, fd;
1376     TCGv_ptr fpst;
1378     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
1379         return false;
1380     }
1382     /* UNDEF accesses to D16-D31 if they don't exist */
1383     if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) {
1384         return false;
1385     }
1387     if (!dc_isar_feature(aa32_fpshvec, s) &&
1388         (veclen != 0 || s->vec_stride != 0)) {
1389         return false;
1390     }
1392     if (!vfp_access_check(s)) {
1393         return true;
1394     }
1396     if (veclen > 0) {
1397         /* Figure out what type of vector operation this is.  */
1398         if (vfp_dreg_is_scalar(vd)) {
1399             /* scalar */
1400             veclen = 0;
1401         } else {
1402             delta_d = (s->vec_stride >> 1) + 1;
1404             if (vfp_dreg_is_scalar(vm)) {
1405                 /* mixed scalar/vector */
1406                 delta_m = 0;
1407             } else {
1408                 /* vector */
1409                 delta_m = delta_d;
1410             }
1411         }
1412     }
1414     f0 = tcg_temp_new_i64();
1415     f1 = tcg_temp_new_i64();
1416     fd = tcg_temp_new_i64();
1417     fpst = fpstatus_ptr(FPST_FPCR);
1419     vfp_load_reg64(f0, vn);
1420     vfp_load_reg64(f1, vm);
1422     for (;;) {
1423         if (reads_vd) {
1424             vfp_load_reg64(fd, vd);
1425         }
1426         fn(fd, f0, f1, fpst);
1427         vfp_store_reg64(fd, vd);
1429         if (veclen == 0) {
1430             break;
1431         }
1432         /* Set up the operands for the next iteration */
1433         veclen--;
1434         vd = vfp_advance_dreg(vd, delta_d);
1435         vn = vfp_advance_dreg(vn, delta_d);
1436         vfp_load_reg64(f0, vn);
1437         if (delta_m) {
1438             vm = vfp_advance_dreg(vm, delta_m);
1439             vfp_load_reg64(f1, vm);
1440         }
1441     }
1443     tcg_temp_free_i64(f0);
1444     tcg_temp_free_i64(f1);
1445     tcg_temp_free_i64(fd);
1446     tcg_temp_free_ptr(fpst);
1448     return true;
1451 static bool do_vfp_2op_sp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
1453     uint32_t delta_m = 0;
1454     uint32_t delta_d = 0;
1455     int veclen = s->vec_len;
1456     TCGv_i32 f0, fd;
1458     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1459         return false;
1460     }
1462     if (!dc_isar_feature(aa32_fpshvec, s) &&
1463         (veclen != 0 || s->vec_stride != 0)) {
1464         return false;
1465     }
1467     if (!vfp_access_check(s)) {
1468         return true;
1469     }
1471     if (veclen > 0) {
1472         /* Figure out what type of vector operation this is.  */
1473         if (vfp_sreg_is_scalar(vd)) {
1474             /* scalar */
1475             veclen = 0;
1476         } else {
1477             delta_d = s->vec_stride + 1;
1479             if (vfp_sreg_is_scalar(vm)) {
1480                 /* mixed scalar/vector */
1481                 delta_m = 0;
1482             } else {
1483                 /* vector */
1484                 delta_m = delta_d;
1485             }
1486         }
1487     }
1489     f0 = tcg_temp_new_i32();
1490     fd = tcg_temp_new_i32();
1492     vfp_load_reg32(f0, vm);
1494     for (;;) {
1495         fn(fd, f0);
1496         vfp_store_reg32(fd, vd);
1498         if (veclen == 0) {
1499             break;
1500         }
1502         if (delta_m == 0) {
1503             /* single source one-many */
1504             while (veclen--) {
1505                 vd = vfp_advance_sreg(vd, delta_d);
1506                 vfp_store_reg32(fd, vd);
1507             }
1508             break;
1509         }
1511         /* Set up the operands for the next iteration */
1512         veclen--;
1513         vd = vfp_advance_sreg(vd, delta_d);
1514         vm = vfp_advance_sreg(vm, delta_m);
1515         vfp_load_reg32(f0, vm);
1516     }
1518     tcg_temp_free_i32(f0);
1519     tcg_temp_free_i32(fd);
1521     return true;
1524 static bool do_vfp_2op_hp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
1526     /*
1527      * Do a half-precision operation. Functionally this is
1528      * the same as do_vfp_2op_sp(), except:
1529      *  - it doesn't need the VFP vector handling (fp16 is a
1530      *    v8 feature, and in v8 VFP vectors don't exist)
1531      *  - it does the aa32_fp16_arith feature test
1532      */
1533     TCGv_i32 f0;
1535     if (!dc_isar_feature(aa32_fp16_arith, s)) {
1536         return false;
1537     }
1539     if (s->vec_len != 0 || s->vec_stride != 0) {
1540         return false;
1541     }
1543     if (!vfp_access_check(s)) {
1544         return true;
1545     }
1547     f0 = tcg_temp_new_i32();
1548     vfp_load_reg32(f0, vm);
1549     fn(f0, f0);
1550     vfp_store_reg32(f0, vd);
1551     tcg_temp_free_i32(f0);
1553     return true;
1556 static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm)
1558     uint32_t delta_m = 0;
1559     uint32_t delta_d = 0;
1560     int veclen = s->vec_len;
1561     TCGv_i64 f0, fd;
1563     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
1564         return false;
1565     }
1567     /* UNDEF accesses to D16-D31 if they don't exist */
1568     if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) {
1569         return false;
1570     }
1572     if (!dc_isar_feature(aa32_fpshvec, s) &&
1573         (veclen != 0 || s->vec_stride != 0)) {
1574         return false;
1575     }
1577     if (!vfp_access_check(s)) {
1578         return true;
1579     }
1581     if (veclen > 0) {
1582         /* Figure out what type of vector operation this is.  */
1583         if (vfp_dreg_is_scalar(vd)) {
1584             /* scalar */
1585             veclen = 0;
1586         } else {
1587             delta_d = (s->vec_stride >> 1) + 1;
1589             if (vfp_dreg_is_scalar(vm)) {
1590                 /* mixed scalar/vector */
1591                 delta_m = 0;
1592             } else {
1593                 /* vector */
1594                 delta_m = delta_d;
1595             }
1596         }
1597     }
1599     f0 = tcg_temp_new_i64();
1600     fd = tcg_temp_new_i64();
1602     vfp_load_reg64(f0, vm);
1604     for (;;) {
1605         fn(fd, f0);
1606         vfp_store_reg64(fd, vd);
1608         if (veclen == 0) {
1609             break;
1610         }
1612         if (delta_m == 0) {
1613             /* single source one-many */
1614             while (veclen--) {
1615                 vd = vfp_advance_dreg(vd, delta_d);
1616                 vfp_store_reg64(fd, vd);
1617             }
1618             break;
1619         }
1621         /* Set up the operands for the next iteration */
1622         veclen--;
1623         vd = vfp_advance_dreg(vd, delta_d);
1624         vd = vfp_advance_dreg(vm, delta_m);
1625         vfp_load_reg64(f0, vm);
1626     }
1628     tcg_temp_free_i64(f0);
1629     tcg_temp_free_i64(fd);
1631     return true;
1634 static void gen_VMLA_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1636     /* Note that order of inputs to the add matters for NaNs */
1637     TCGv_i32 tmp = tcg_temp_new_i32();
1639     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1640     gen_helper_vfp_addh(vd, vd, tmp, fpst);
1641     tcg_temp_free_i32(tmp);
1644 static bool trans_VMLA_hp(DisasContext *s, arg_VMLA_sp *a)
1646     return do_vfp_3op_hp(s, gen_VMLA_hp, a->vd, a->vn, a->vm, true);
1649 static void gen_VMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1651     /* Note that order of inputs to the add matters for NaNs */
1652     TCGv_i32 tmp = tcg_temp_new_i32();
1654     gen_helper_vfp_muls(tmp, vn, vm, fpst);
1655     gen_helper_vfp_adds(vd, vd, tmp, fpst);
1656     tcg_temp_free_i32(tmp);
1659 static bool trans_VMLA_sp(DisasContext *s, arg_VMLA_sp *a)
1661     return do_vfp_3op_sp(s, gen_VMLA_sp, a->vd, a->vn, a->vm, true);
1664 static void gen_VMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1666     /* Note that order of inputs to the add matters for NaNs */
1667     TCGv_i64 tmp = tcg_temp_new_i64();
1669     gen_helper_vfp_muld(tmp, vn, vm, fpst);
1670     gen_helper_vfp_addd(vd, vd, tmp, fpst);
1671     tcg_temp_free_i64(tmp);
1674 static bool trans_VMLA_dp(DisasContext *s, arg_VMLA_dp *a)
1676     return do_vfp_3op_dp(s, gen_VMLA_dp, a->vd, a->vn, a->vm, true);
1679 static void gen_VMLS_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1681     /*
1682      * VMLS: vd = vd + -(vn * vm)
1683      * Note that order of inputs to the add matters for NaNs.
1684      */
1685     TCGv_i32 tmp = tcg_temp_new_i32();
1687     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1688     gen_helper_vfp_negh(tmp, tmp);
1689     gen_helper_vfp_addh(vd, vd, tmp, fpst);
1690     tcg_temp_free_i32(tmp);
1693 static bool trans_VMLS_hp(DisasContext *s, arg_VMLS_sp *a)
1695     return do_vfp_3op_hp(s, gen_VMLS_hp, a->vd, a->vn, a->vm, true);
1698 static void gen_VMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1700     /*
1701      * VMLS: vd = vd + -(vn * vm)
1702      * Note that order of inputs to the add matters for NaNs.
1703      */
1704     TCGv_i32 tmp = tcg_temp_new_i32();
1706     gen_helper_vfp_muls(tmp, vn, vm, fpst);
1707     gen_helper_vfp_negs(tmp, tmp);
1708     gen_helper_vfp_adds(vd, vd, tmp, fpst);
1709     tcg_temp_free_i32(tmp);
1712 static bool trans_VMLS_sp(DisasContext *s, arg_VMLS_sp *a)
1714     return do_vfp_3op_sp(s, gen_VMLS_sp, a->vd, a->vn, a->vm, true);
1717 static void gen_VMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1719     /*
1720      * VMLS: vd = vd + -(vn * vm)
1721      * Note that order of inputs to the add matters for NaNs.
1722      */
1723     TCGv_i64 tmp = tcg_temp_new_i64();
1725     gen_helper_vfp_muld(tmp, vn, vm, fpst);
1726     gen_helper_vfp_negd(tmp, tmp);
1727     gen_helper_vfp_addd(vd, vd, tmp, fpst);
1728     tcg_temp_free_i64(tmp);
1731 static bool trans_VMLS_dp(DisasContext *s, arg_VMLS_dp *a)
1733     return do_vfp_3op_dp(s, gen_VMLS_dp, a->vd, a->vn, a->vm, true);
1736 static void gen_VNMLS_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1738     /*
1739      * VNMLS: -fd + (fn * fm)
1740      * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1741      * plausible looking simplifications because this will give wrong results
1742      * for NaNs.
1743      */
1744     TCGv_i32 tmp = tcg_temp_new_i32();
1746     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1747     gen_helper_vfp_negh(vd, vd);
1748     gen_helper_vfp_addh(vd, vd, tmp, fpst);
1749     tcg_temp_free_i32(tmp);
1752 static bool trans_VNMLS_hp(DisasContext *s, arg_VNMLS_sp *a)
1754     return do_vfp_3op_hp(s, gen_VNMLS_hp, a->vd, a->vn, a->vm, true);
1757 static void gen_VNMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1759     /*
1760      * VNMLS: -fd + (fn * fm)
1761      * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1762      * plausible looking simplifications because this will give wrong results
1763      * for NaNs.
1764      */
1765     TCGv_i32 tmp = tcg_temp_new_i32();
1767     gen_helper_vfp_muls(tmp, vn, vm, fpst);
1768     gen_helper_vfp_negs(vd, vd);
1769     gen_helper_vfp_adds(vd, vd, tmp, fpst);
1770     tcg_temp_free_i32(tmp);
1773 static bool trans_VNMLS_sp(DisasContext *s, arg_VNMLS_sp *a)
1775     return do_vfp_3op_sp(s, gen_VNMLS_sp, a->vd, a->vn, a->vm, true);
1778 static void gen_VNMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1780     /*
1781      * VNMLS: -fd + (fn * fm)
1782      * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1783      * plausible looking simplifications because this will give wrong results
1784      * for NaNs.
1785      */
1786     TCGv_i64 tmp = tcg_temp_new_i64();
1788     gen_helper_vfp_muld(tmp, vn, vm, fpst);
1789     gen_helper_vfp_negd(vd, vd);
1790     gen_helper_vfp_addd(vd, vd, tmp, fpst);
1791     tcg_temp_free_i64(tmp);
1794 static bool trans_VNMLS_dp(DisasContext *s, arg_VNMLS_dp *a)
1796     return do_vfp_3op_dp(s, gen_VNMLS_dp, a->vd, a->vn, a->vm, true);
1799 static void gen_VNMLA_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1801     /* VNMLA: -fd + -(fn * fm) */
1802     TCGv_i32 tmp = tcg_temp_new_i32();
1804     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1805     gen_helper_vfp_negh(tmp, tmp);
1806     gen_helper_vfp_negh(vd, vd);
1807     gen_helper_vfp_addh(vd, vd, tmp, fpst);
1808     tcg_temp_free_i32(tmp);
1811 static bool trans_VNMLA_hp(DisasContext *s, arg_VNMLA_sp *a)
1813     return do_vfp_3op_hp(s, gen_VNMLA_hp, a->vd, a->vn, a->vm, true);
1816 static void gen_VNMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1818     /* VNMLA: -fd + -(fn * fm) */
1819     TCGv_i32 tmp = tcg_temp_new_i32();
1821     gen_helper_vfp_muls(tmp, vn, vm, fpst);
1822     gen_helper_vfp_negs(tmp, tmp);
1823     gen_helper_vfp_negs(vd, vd);
1824     gen_helper_vfp_adds(vd, vd, tmp, fpst);
1825     tcg_temp_free_i32(tmp);
1828 static bool trans_VNMLA_sp(DisasContext *s, arg_VNMLA_sp *a)
1830     return do_vfp_3op_sp(s, gen_VNMLA_sp, a->vd, a->vn, a->vm, true);
1833 static void gen_VNMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1835     /* VNMLA: -fd + (fn * fm) */
1836     TCGv_i64 tmp = tcg_temp_new_i64();
1838     gen_helper_vfp_muld(tmp, vn, vm, fpst);
1839     gen_helper_vfp_negd(tmp, tmp);
1840     gen_helper_vfp_negd(vd, vd);
1841     gen_helper_vfp_addd(vd, vd, tmp, fpst);
1842     tcg_temp_free_i64(tmp);
1845 static bool trans_VNMLA_dp(DisasContext *s, arg_VNMLA_dp *a)
1847     return do_vfp_3op_dp(s, gen_VNMLA_dp, a->vd, a->vn, a->vm, true);
1850 static bool trans_VMUL_hp(DisasContext *s, arg_VMUL_sp *a)
1852     return do_vfp_3op_hp(s, gen_helper_vfp_mulh, a->vd, a->vn, a->vm, false);
1855 static bool trans_VMUL_sp(DisasContext *s, arg_VMUL_sp *a)
1857     return do_vfp_3op_sp(s, gen_helper_vfp_muls, a->vd, a->vn, a->vm, false);
1860 static bool trans_VMUL_dp(DisasContext *s, arg_VMUL_dp *a)
1862     return do_vfp_3op_dp(s, gen_helper_vfp_muld, a->vd, a->vn, a->vm, false);
1865 static void gen_VNMUL_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1867     /* VNMUL: -(fn * fm) */
1868     gen_helper_vfp_mulh(vd, vn, vm, fpst);
1869     gen_helper_vfp_negh(vd, vd);
1872 static bool trans_VNMUL_hp(DisasContext *s, arg_VNMUL_sp *a)
1874     return do_vfp_3op_hp(s, gen_VNMUL_hp, a->vd, a->vn, a->vm, false);
1877 static void gen_VNMUL_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1879     /* VNMUL: -(fn * fm) */
1880     gen_helper_vfp_muls(vd, vn, vm, fpst);
1881     gen_helper_vfp_negs(vd, vd);
1884 static bool trans_VNMUL_sp(DisasContext *s, arg_VNMUL_sp *a)
1886     return do_vfp_3op_sp(s, gen_VNMUL_sp, a->vd, a->vn, a->vm, false);
1889 static void gen_VNMUL_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1891     /* VNMUL: -(fn * fm) */
1892     gen_helper_vfp_muld(vd, vn, vm, fpst);
1893     gen_helper_vfp_negd(vd, vd);
1896 static bool trans_VNMUL_dp(DisasContext *s, arg_VNMUL_dp *a)
1898     return do_vfp_3op_dp(s, gen_VNMUL_dp, a->vd, a->vn, a->vm, false);
1901 static bool trans_VADD_hp(DisasContext *s, arg_VADD_sp *a)
1903     return do_vfp_3op_hp(s, gen_helper_vfp_addh, a->vd, a->vn, a->vm, false);
1906 static bool trans_VADD_sp(DisasContext *s, arg_VADD_sp *a)
1908     return do_vfp_3op_sp(s, gen_helper_vfp_adds, a->vd, a->vn, a->vm, false);
1911 static bool trans_VADD_dp(DisasContext *s, arg_VADD_dp *a)
1913     return do_vfp_3op_dp(s, gen_helper_vfp_addd, a->vd, a->vn, a->vm, false);
1916 static bool trans_VSUB_hp(DisasContext *s, arg_VSUB_sp *a)
1918     return do_vfp_3op_hp(s, gen_helper_vfp_subh, a->vd, a->vn, a->vm, false);
1921 static bool trans_VSUB_sp(DisasContext *s, arg_VSUB_sp *a)
1923     return do_vfp_3op_sp(s, gen_helper_vfp_subs, a->vd, a->vn, a->vm, false);
1926 static bool trans_VSUB_dp(DisasContext *s, arg_VSUB_dp *a)
1928     return do_vfp_3op_dp(s, gen_helper_vfp_subd, a->vd, a->vn, a->vm, false);
1931 static bool trans_VDIV_hp(DisasContext *s, arg_VDIV_sp *a)
1933     return do_vfp_3op_hp(s, gen_helper_vfp_divh, a->vd, a->vn, a->vm, false);
1936 static bool trans_VDIV_sp(DisasContext *s, arg_VDIV_sp *a)
1938     return do_vfp_3op_sp(s, gen_helper_vfp_divs, a->vd, a->vn, a->vm, false);
1941 static bool trans_VDIV_dp(DisasContext *s, arg_VDIV_dp *a)
1943     return do_vfp_3op_dp(s, gen_helper_vfp_divd, a->vd, a->vn, a->vm, false);
1946 static bool trans_VMINNM_hp(DisasContext *s, arg_VMINNM_sp *a)
1948     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1949         return false;
1950     }
1951     return do_vfp_3op_hp(s, gen_helper_vfp_minnumh,
1952                          a->vd, a->vn, a->vm, false);
1955 static bool trans_VMAXNM_hp(DisasContext *s, arg_VMAXNM_sp *a)
1957     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1958         return false;
1959     }
1960     return do_vfp_3op_hp(s, gen_helper_vfp_maxnumh,
1961                          a->vd, a->vn, a->vm, false);
1964 static bool trans_VMINNM_sp(DisasContext *s, arg_VMINNM_sp *a)
1966     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1967         return false;
1968     }
1969     return do_vfp_3op_sp(s, gen_helper_vfp_minnums,
1970                          a->vd, a->vn, a->vm, false);
1973 static bool trans_VMAXNM_sp(DisasContext *s, arg_VMAXNM_sp *a)
1975     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1976         return false;
1977     }
1978     return do_vfp_3op_sp(s, gen_helper_vfp_maxnums,
1979                          a->vd, a->vn, a->vm, false);
1982 static bool trans_VMINNM_dp(DisasContext *s, arg_VMINNM_dp *a)
1984     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1985         return false;
1986     }
1987     return do_vfp_3op_dp(s, gen_helper_vfp_minnumd,
1988                          a->vd, a->vn, a->vm, false);
1991 static bool trans_VMAXNM_dp(DisasContext *s, arg_VMAXNM_dp *a)
1993     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1994         return false;
1995     }
1996     return do_vfp_3op_dp(s, gen_helper_vfp_maxnumd,
1997                          a->vd, a->vn, a->vm, false);
2000 static bool do_vfm_hp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
2002     /*
2003      * VFNMA : fd = muladd(-fd,  fn, fm)
2004      * VFNMS : fd = muladd(-fd, -fn, fm)
2005      * VFMA  : fd = muladd( fd,  fn, fm)
2006      * VFMS  : fd = muladd( fd, -fn, fm)
2007      *
2008      * These are fused multiply-add, and must be done as one floating
2009      * point operation with no rounding between the multiplication and
2010      * addition steps.  NB that doing the negations here as separate
2011      * steps is correct : an input NaN should come out with its sign
2012      * bit flipped if it is a negated-input.
2013      */
2014     TCGv_ptr fpst;
2015     TCGv_i32 vn, vm, vd;
2017     /*
2018      * Present in VFPv4 only, and only with the FP16 extension.
2019      * Note that we can't rely on the SIMDFMAC check alone, because
2020      * in a Neon-no-VFP core that ID register field will be non-zero.
2021      */
2022     if (!dc_isar_feature(aa32_fp16_arith, s) ||
2023         !dc_isar_feature(aa32_simdfmac, s) ||
2024         !dc_isar_feature(aa32_fpsp_v2, s)) {
2025         return false;
2026     }
2028     if (s->vec_len != 0 || s->vec_stride != 0) {
2029         return false;
2030     }
2032     if (!vfp_access_check(s)) {
2033         return true;
2034     }
2036     vn = tcg_temp_new_i32();
2037     vm = tcg_temp_new_i32();
2038     vd = tcg_temp_new_i32();
2040     vfp_load_reg32(vn, a->vn);
2041     vfp_load_reg32(vm, a->vm);
2042     if (neg_n) {
2043         /* VFNMS, VFMS */
2044         gen_helper_vfp_negh(vn, vn);
2045     }
2046     vfp_load_reg32(vd, a->vd);
2047     if (neg_d) {
2048         /* VFNMA, VFNMS */
2049         gen_helper_vfp_negh(vd, vd);
2050     }
2051     fpst = fpstatus_ptr(FPST_FPCR_F16);
2052     gen_helper_vfp_muladdh(vd, vn, vm, vd, fpst);
2053     vfp_store_reg32(vd, a->vd);
2055     tcg_temp_free_ptr(fpst);
2056     tcg_temp_free_i32(vn);
2057     tcg_temp_free_i32(vm);
2058     tcg_temp_free_i32(vd);
2060     return true;
2063 static bool do_vfm_sp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
2065     /*
2066      * VFNMA : fd = muladd(-fd,  fn, fm)
2067      * VFNMS : fd = muladd(-fd, -fn, fm)
2068      * VFMA  : fd = muladd( fd,  fn, fm)
2069      * VFMS  : fd = muladd( fd, -fn, fm)
2070      *
2071      * These are fused multiply-add, and must be done as one floating
2072      * point operation with no rounding between the multiplication and
2073      * addition steps.  NB that doing the negations here as separate
2074      * steps is correct : an input NaN should come out with its sign
2075      * bit flipped if it is a negated-input.
2076      */
2077     TCGv_ptr fpst;
2078     TCGv_i32 vn, vm, vd;
2080     /*
2081      * Present in VFPv4 only.
2082      * Note that we can't rely on the SIMDFMAC check alone, because
2083      * in a Neon-no-VFP core that ID register field will be non-zero.
2084      */
2085     if (!dc_isar_feature(aa32_simdfmac, s) ||
2086         !dc_isar_feature(aa32_fpsp_v2, s)) {
2087         return false;
2088     }
2089     /*
2090      * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
2091      * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
2092      */
2093     if (s->vec_len != 0 || s->vec_stride != 0) {
2094         return false;
2095     }
2097     if (!vfp_access_check(s)) {
2098         return true;
2099     }
2101     vn = tcg_temp_new_i32();
2102     vm = tcg_temp_new_i32();
2103     vd = tcg_temp_new_i32();
2105     vfp_load_reg32(vn, a->vn);
2106     vfp_load_reg32(vm, a->vm);
2107     if (neg_n) {
2108         /* VFNMS, VFMS */
2109         gen_helper_vfp_negs(vn, vn);
2110     }
2111     vfp_load_reg32(vd, a->vd);
2112     if (neg_d) {
2113         /* VFNMA, VFNMS */
2114         gen_helper_vfp_negs(vd, vd);
2115     }
2116     fpst = fpstatus_ptr(FPST_FPCR);
2117     gen_helper_vfp_muladds(vd, vn, vm, vd, fpst);
2118     vfp_store_reg32(vd, a->vd);
2120     tcg_temp_free_ptr(fpst);
2121     tcg_temp_free_i32(vn);
2122     tcg_temp_free_i32(vm);
2123     tcg_temp_free_i32(vd);
2125     return true;
2128 static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d)
2130     /*
2131      * VFNMA : fd = muladd(-fd,  fn, fm)
2132      * VFNMS : fd = muladd(-fd, -fn, fm)
2133      * VFMA  : fd = muladd( fd,  fn, fm)
2134      * VFMS  : fd = muladd( fd, -fn, fm)
2135      *
2136      * These are fused multiply-add, and must be done as one floating
2137      * point operation with no rounding between the multiplication and
2138      * addition steps.  NB that doing the negations here as separate
2139      * steps is correct : an input NaN should come out with its sign
2140      * bit flipped if it is a negated-input.
2141      */
2142     TCGv_ptr fpst;
2143     TCGv_i64 vn, vm, vd;
2145     /*
2146      * Present in VFPv4 only.
2147      * Note that we can't rely on the SIMDFMAC check alone, because
2148      * in a Neon-no-VFP core that ID register field will be non-zero.
2149      */
2150     if (!dc_isar_feature(aa32_simdfmac, s) ||
2151         !dc_isar_feature(aa32_fpdp_v2, s)) {
2152         return false;
2153     }
2154     /*
2155      * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
2156      * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
2157      */
2158     if (s->vec_len != 0 || s->vec_stride != 0) {
2159         return false;
2160     }
2162     /* UNDEF accesses to D16-D31 if they don't exist. */
2163     if (!dc_isar_feature(aa32_simd_r32, s) &&
2164         ((a->vd | a->vn | a->vm) & 0x10)) {
2165         return false;
2166     }
2168     if (!vfp_access_check(s)) {
2169         return true;
2170     }
2172     vn = tcg_temp_new_i64();
2173     vm = tcg_temp_new_i64();
2174     vd = tcg_temp_new_i64();
2176     vfp_load_reg64(vn, a->vn);
2177     vfp_load_reg64(vm, a->vm);
2178     if (neg_n) {
2179         /* VFNMS, VFMS */
2180         gen_helper_vfp_negd(vn, vn);
2181     }
2182     vfp_load_reg64(vd, a->vd);
2183     if (neg_d) {
2184         /* VFNMA, VFNMS */
2185         gen_helper_vfp_negd(vd, vd);
2186     }
2187     fpst = fpstatus_ptr(FPST_FPCR);
2188     gen_helper_vfp_muladdd(vd, vn, vm, vd, fpst);
2189     vfp_store_reg64(vd, a->vd);
2191     tcg_temp_free_ptr(fpst);
2192     tcg_temp_free_i64(vn);
2193     tcg_temp_free_i64(vm);
2194     tcg_temp_free_i64(vd);
2196     return true;
2199 #define MAKE_ONE_VFM_TRANS_FN(INSN, PREC, NEGN, NEGD)                   \
2200     static bool trans_##INSN##_##PREC(DisasContext *s,                  \
2201                                       arg_##INSN##_##PREC *a)           \
2202     {                                                                   \
2203         return do_vfm_##PREC(s, a, NEGN, NEGD);                         \
2204     }
2206 #define MAKE_VFM_TRANS_FNS(PREC) \
2207     MAKE_ONE_VFM_TRANS_FN(VFMA, PREC, false, false) \
2208     MAKE_ONE_VFM_TRANS_FN(VFMS, PREC, true, false) \
2209     MAKE_ONE_VFM_TRANS_FN(VFNMA, PREC, false, true) \
2210     MAKE_ONE_VFM_TRANS_FN(VFNMS, PREC, true, true)
2212 MAKE_VFM_TRANS_FNS(hp)
2213 MAKE_VFM_TRANS_FNS(sp)
2214 MAKE_VFM_TRANS_FNS(dp)
2216 static bool trans_VMOV_imm_hp(DisasContext *s, arg_VMOV_imm_sp *a)
2218     TCGv_i32 fd;
2220     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2221         return false;
2222     }
2224     if (s->vec_len != 0 || s->vec_stride != 0) {
2225         return false;
2226     }
2228     if (!vfp_access_check(s)) {
2229         return true;
2230     }
2232     fd = tcg_const_i32(vfp_expand_imm(MO_16, a->imm));
2233     vfp_store_reg32(fd, a->vd);
2234     tcg_temp_free_i32(fd);
2235     return true;
2238 static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
2240     uint32_t delta_d = 0;
2241     int veclen = s->vec_len;
2242     TCGv_i32 fd;
2243     uint32_t vd;
2245     vd = a->vd;
2247     if (!dc_isar_feature(aa32_fpsp_v3, s)) {
2248         return false;
2249     }
2251     if (!dc_isar_feature(aa32_fpshvec, s) &&
2252         (veclen != 0 || s->vec_stride != 0)) {
2253         return false;
2254     }
2256     if (!vfp_access_check(s)) {
2257         return true;
2258     }
2260     if (veclen > 0) {
2261         /* Figure out what type of vector operation this is.  */
2262         if (vfp_sreg_is_scalar(vd)) {
2263             /* scalar */
2264             veclen = 0;
2265         } else {
2266             delta_d = s->vec_stride + 1;
2267         }
2268     }
2270     fd = tcg_const_i32(vfp_expand_imm(MO_32, a->imm));
2272     for (;;) {
2273         vfp_store_reg32(fd, vd);
2275         if (veclen == 0) {
2276             break;
2277         }
2279         /* Set up the operands for the next iteration */
2280         veclen--;
2281         vd = vfp_advance_sreg(vd, delta_d);
2282     }
2284     tcg_temp_free_i32(fd);
2285     return true;
2288 static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
2290     uint32_t delta_d = 0;
2291     int veclen = s->vec_len;
2292     TCGv_i64 fd;
2293     uint32_t vd;
2295     vd = a->vd;
2297     if (!dc_isar_feature(aa32_fpdp_v3, s)) {
2298         return false;
2299     }
2301     /* UNDEF accesses to D16-D31 if they don't exist. */
2302     if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) {
2303         return false;
2304     }
2306     if (!dc_isar_feature(aa32_fpshvec, s) &&
2307         (veclen != 0 || s->vec_stride != 0)) {
2308         return false;
2309     }
2311     if (!vfp_access_check(s)) {
2312         return true;
2313     }
2315     if (veclen > 0) {
2316         /* Figure out what type of vector operation this is.  */
2317         if (vfp_dreg_is_scalar(vd)) {
2318             /* scalar */
2319             veclen = 0;
2320         } else {
2321             delta_d = (s->vec_stride >> 1) + 1;
2322         }
2323     }
2325     fd = tcg_const_i64(vfp_expand_imm(MO_64, a->imm));
2327     for (;;) {
2328         vfp_store_reg64(fd, vd);
2330         if (veclen == 0) {
2331             break;
2332         }
2334         /* Set up the operands for the next iteration */
2335         veclen--;
2336         vd = vfp_advance_dreg(vd, delta_d);
2337     }
2339     tcg_temp_free_i64(fd);
2340     return true;
2343 #define DO_VFP_2OP(INSN, PREC, FN)                              \
2344     static bool trans_##INSN##_##PREC(DisasContext *s,          \
2345                                       arg_##INSN##_##PREC *a)   \
2346     {                                                           \
2347         return do_vfp_2op_##PREC(s, FN, a->vd, a->vm);          \
2348     }
2350 DO_VFP_2OP(VMOV_reg, sp, tcg_gen_mov_i32)
2351 DO_VFP_2OP(VMOV_reg, dp, tcg_gen_mov_i64)
2353 DO_VFP_2OP(VABS, hp, gen_helper_vfp_absh)
2354 DO_VFP_2OP(VABS, sp, gen_helper_vfp_abss)
2355 DO_VFP_2OP(VABS, dp, gen_helper_vfp_absd)
2357 DO_VFP_2OP(VNEG, hp, gen_helper_vfp_negh)
2358 DO_VFP_2OP(VNEG, sp, gen_helper_vfp_negs)
2359 DO_VFP_2OP(VNEG, dp, gen_helper_vfp_negd)
2361 static void gen_VSQRT_hp(TCGv_i32 vd, TCGv_i32 vm)
2363     gen_helper_vfp_sqrth(vd, vm, cpu_env);
2366 static void gen_VSQRT_sp(TCGv_i32 vd, TCGv_i32 vm)
2368     gen_helper_vfp_sqrts(vd, vm, cpu_env);
2371 static void gen_VSQRT_dp(TCGv_i64 vd, TCGv_i64 vm)
2373     gen_helper_vfp_sqrtd(vd, vm, cpu_env);
2376 DO_VFP_2OP(VSQRT, hp, gen_VSQRT_hp)
2377 DO_VFP_2OP(VSQRT, sp, gen_VSQRT_sp)
2378 DO_VFP_2OP(VSQRT, dp, gen_VSQRT_dp)
2380 static bool trans_VCMP_hp(DisasContext *s, arg_VCMP_sp *a)
2382     TCGv_i32 vd, vm;
2384     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2385         return false;
2386     }
2388     /* Vm/M bits must be zero for the Z variant */
2389     if (a->z && a->vm != 0) {
2390         return false;
2391     }
2393     if (!vfp_access_check(s)) {
2394         return true;
2395     }
2397     vd = tcg_temp_new_i32();
2398     vm = tcg_temp_new_i32();
2400     vfp_load_reg32(vd, a->vd);
2401     if (a->z) {
2402         tcg_gen_movi_i32(vm, 0);
2403     } else {
2404         vfp_load_reg32(vm, a->vm);
2405     }
2407     if (a->e) {
2408         gen_helper_vfp_cmpeh(vd, vm, cpu_env);
2409     } else {
2410         gen_helper_vfp_cmph(vd, vm, cpu_env);
2411     }
2413     tcg_temp_free_i32(vd);
2414     tcg_temp_free_i32(vm);
2416     return true;
2419 static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a)
2421     TCGv_i32 vd, vm;
2423     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2424         return false;
2425     }
2427     /* Vm/M bits must be zero for the Z variant */
2428     if (a->z && a->vm != 0) {
2429         return false;
2430     }
2432     if (!vfp_access_check(s)) {
2433         return true;
2434     }
2436     vd = tcg_temp_new_i32();
2437     vm = tcg_temp_new_i32();
2439     vfp_load_reg32(vd, a->vd);
2440     if (a->z) {
2441         tcg_gen_movi_i32(vm, 0);
2442     } else {
2443         vfp_load_reg32(vm, a->vm);
2444     }
2446     if (a->e) {
2447         gen_helper_vfp_cmpes(vd, vm, cpu_env);
2448     } else {
2449         gen_helper_vfp_cmps(vd, vm, cpu_env);
2450     }
2452     tcg_temp_free_i32(vd);
2453     tcg_temp_free_i32(vm);
2455     return true;
2458 static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a)
2460     TCGv_i64 vd, vm;
2462     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2463         return false;
2464     }
2466     /* Vm/M bits must be zero for the Z variant */
2467     if (a->z && a->vm != 0) {
2468         return false;
2469     }
2471     /* UNDEF accesses to D16-D31 if they don't exist. */
2472     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
2473         return false;
2474     }
2476     if (!vfp_access_check(s)) {
2477         return true;
2478     }
2480     vd = tcg_temp_new_i64();
2481     vm = tcg_temp_new_i64();
2483     vfp_load_reg64(vd, a->vd);
2484     if (a->z) {
2485         tcg_gen_movi_i64(vm, 0);
2486     } else {
2487         vfp_load_reg64(vm, a->vm);
2488     }
2490     if (a->e) {
2491         gen_helper_vfp_cmped(vd, vm, cpu_env);
2492     } else {
2493         gen_helper_vfp_cmpd(vd, vm, cpu_env);
2494     }
2496     tcg_temp_free_i64(vd);
2497     tcg_temp_free_i64(vm);
2499     return true;
2502 static bool trans_VCVT_f32_f16(DisasContext *s, arg_VCVT_f32_f16 *a)
2504     TCGv_ptr fpst;
2505     TCGv_i32 ahp_mode;
2506     TCGv_i32 tmp;
2508     if (!dc_isar_feature(aa32_fp16_spconv, s)) {
2509         return false;
2510     }
2512     if (!vfp_access_check(s)) {
2513         return true;
2514     }
2516     fpst = fpstatus_ptr(FPST_FPCR);
2517     ahp_mode = get_ahp_flag();
2518     tmp = tcg_temp_new_i32();
2519     /* The T bit tells us if we want the low or high 16 bits of Vm */
2520     tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t));
2521     gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp_mode);
2522     vfp_store_reg32(tmp, a->vd);
2523     tcg_temp_free_i32(ahp_mode);
2524     tcg_temp_free_ptr(fpst);
2525     tcg_temp_free_i32(tmp);
2526     return true;
2529 static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a)
2531     TCGv_ptr fpst;
2532     TCGv_i32 ahp_mode;
2533     TCGv_i32 tmp;
2534     TCGv_i64 vd;
2536     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2537         return false;
2538     }
2540     if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
2541         return false;
2542     }
2544     /* UNDEF accesses to D16-D31 if they don't exist. */
2545     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd  & 0x10)) {
2546         return false;
2547     }
2549     if (!vfp_access_check(s)) {
2550         return true;
2551     }
2553     fpst = fpstatus_ptr(FPST_FPCR);
2554     ahp_mode = get_ahp_flag();
2555     tmp = tcg_temp_new_i32();
2556     /* The T bit tells us if we want the low or high 16 bits of Vm */
2557     tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t));
2558     vd = tcg_temp_new_i64();
2559     gen_helper_vfp_fcvt_f16_to_f64(vd, tmp, fpst, ahp_mode);
2560     vfp_store_reg64(vd, a->vd);
2561     tcg_temp_free_i32(ahp_mode);
2562     tcg_temp_free_ptr(fpst);
2563     tcg_temp_free_i32(tmp);
2564     tcg_temp_free_i64(vd);
2565     return true;
2568 static bool trans_VCVT_f16_f32(DisasContext *s, arg_VCVT_f16_f32 *a)
2570     TCGv_ptr fpst;
2571     TCGv_i32 ahp_mode;
2572     TCGv_i32 tmp;
2574     if (!dc_isar_feature(aa32_fp16_spconv, s)) {
2575         return false;
2576     }
2578     if (!vfp_access_check(s)) {
2579         return true;
2580     }
2582     fpst = fpstatus_ptr(FPST_FPCR);
2583     ahp_mode = get_ahp_flag();
2584     tmp = tcg_temp_new_i32();
2586     vfp_load_reg32(tmp, a->vm);
2587     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp_mode);
2588     tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t));
2589     tcg_temp_free_i32(ahp_mode);
2590     tcg_temp_free_ptr(fpst);
2591     tcg_temp_free_i32(tmp);
2592     return true;
2595 static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a)
2597     TCGv_ptr fpst;
2598     TCGv_i32 ahp_mode;
2599     TCGv_i32 tmp;
2600     TCGv_i64 vm;
2602     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2603         return false;
2604     }
2606     if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
2607         return false;
2608     }
2610     /* UNDEF accesses to D16-D31 if they don't exist. */
2611     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm  & 0x10)) {
2612         return false;
2613     }
2615     if (!vfp_access_check(s)) {
2616         return true;
2617     }
2619     fpst = fpstatus_ptr(FPST_FPCR);
2620     ahp_mode = get_ahp_flag();
2621     tmp = tcg_temp_new_i32();
2622     vm = tcg_temp_new_i64();
2624     vfp_load_reg64(vm, a->vm);
2625     gen_helper_vfp_fcvt_f64_to_f16(tmp, vm, fpst, ahp_mode);
2626     tcg_temp_free_i64(vm);
2627     tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t));
2628     tcg_temp_free_i32(ahp_mode);
2629     tcg_temp_free_ptr(fpst);
2630     tcg_temp_free_i32(tmp);
2631     return true;
2634 static bool trans_VRINTR_hp(DisasContext *s, arg_VRINTR_sp *a)
2636     TCGv_ptr fpst;
2637     TCGv_i32 tmp;
2639     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2640         return false;
2641     }
2643     if (!vfp_access_check(s)) {
2644         return true;
2645     }
2647     tmp = tcg_temp_new_i32();
2648     vfp_load_reg32(tmp, a->vm);
2649     fpst = fpstatus_ptr(FPST_FPCR_F16);
2650     gen_helper_rinth(tmp, tmp, fpst);
2651     vfp_store_reg32(tmp, a->vd);
2652     tcg_temp_free_ptr(fpst);
2653     tcg_temp_free_i32(tmp);
2654     return true;
2657 static bool trans_VRINTR_sp(DisasContext *s, arg_VRINTR_sp *a)
2659     TCGv_ptr fpst;
2660     TCGv_i32 tmp;
2662     if (!dc_isar_feature(aa32_vrint, s)) {
2663         return false;
2664     }
2666     if (!vfp_access_check(s)) {
2667         return true;
2668     }
2670     tmp = tcg_temp_new_i32();
2671     vfp_load_reg32(tmp, a->vm);
2672     fpst = fpstatus_ptr(FPST_FPCR);
2673     gen_helper_rints(tmp, tmp, fpst);
2674     vfp_store_reg32(tmp, a->vd);
2675     tcg_temp_free_ptr(fpst);
2676     tcg_temp_free_i32(tmp);
2677     return true;
2680 static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a)
2682     TCGv_ptr fpst;
2683     TCGv_i64 tmp;
2685     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2686         return false;
2687     }
2689     if (!dc_isar_feature(aa32_vrint, s)) {
2690         return false;
2691     }
2693     /* UNDEF accesses to D16-D31 if they don't exist. */
2694     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
2695         return false;
2696     }
2698     if (!vfp_access_check(s)) {
2699         return true;
2700     }
2702     tmp = tcg_temp_new_i64();
2703     vfp_load_reg64(tmp, a->vm);
2704     fpst = fpstatus_ptr(FPST_FPCR);
2705     gen_helper_rintd(tmp, tmp, fpst);
2706     vfp_store_reg64(tmp, a->vd);
2707     tcg_temp_free_ptr(fpst);
2708     tcg_temp_free_i64(tmp);
2709     return true;
2712 static bool trans_VRINTZ_hp(DisasContext *s, arg_VRINTZ_sp *a)
2714     TCGv_ptr fpst;
2715     TCGv_i32 tmp;
2716     TCGv_i32 tcg_rmode;
2718     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2719         return false;
2720     }
2722     if (!vfp_access_check(s)) {
2723         return true;
2724     }
2726     tmp = tcg_temp_new_i32();
2727     vfp_load_reg32(tmp, a->vm);
2728     fpst = fpstatus_ptr(FPST_FPCR_F16);
2729     tcg_rmode = tcg_const_i32(float_round_to_zero);
2730     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2731     gen_helper_rinth(tmp, tmp, fpst);
2732     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2733     vfp_store_reg32(tmp, a->vd);
2734     tcg_temp_free_ptr(fpst);
2735     tcg_temp_free_i32(tcg_rmode);
2736     tcg_temp_free_i32(tmp);
2737     return true;
2740 static bool trans_VRINTZ_sp(DisasContext *s, arg_VRINTZ_sp *a)
2742     TCGv_ptr fpst;
2743     TCGv_i32 tmp;
2744     TCGv_i32 tcg_rmode;
2746     if (!dc_isar_feature(aa32_vrint, s)) {
2747         return false;
2748     }
2750     if (!vfp_access_check(s)) {
2751         return true;
2752     }
2754     tmp = tcg_temp_new_i32();
2755     vfp_load_reg32(tmp, a->vm);
2756     fpst = fpstatus_ptr(FPST_FPCR);
2757     tcg_rmode = tcg_const_i32(float_round_to_zero);
2758     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2759     gen_helper_rints(tmp, tmp, fpst);
2760     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2761     vfp_store_reg32(tmp, a->vd);
2762     tcg_temp_free_ptr(fpst);
2763     tcg_temp_free_i32(tcg_rmode);
2764     tcg_temp_free_i32(tmp);
2765     return true;
2768 static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a)
2770     TCGv_ptr fpst;
2771     TCGv_i64 tmp;
2772     TCGv_i32 tcg_rmode;
2774     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2775         return false;
2776     }
2778     if (!dc_isar_feature(aa32_vrint, s)) {
2779         return false;
2780     }
2782     /* UNDEF accesses to D16-D31 if they don't exist. */
2783     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
2784         return false;
2785     }
2787     if (!vfp_access_check(s)) {
2788         return true;
2789     }
2791     tmp = tcg_temp_new_i64();
2792     vfp_load_reg64(tmp, a->vm);
2793     fpst = fpstatus_ptr(FPST_FPCR);
2794     tcg_rmode = tcg_const_i32(float_round_to_zero);
2795     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2796     gen_helper_rintd(tmp, tmp, fpst);
2797     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2798     vfp_store_reg64(tmp, a->vd);
2799     tcg_temp_free_ptr(fpst);
2800     tcg_temp_free_i64(tmp);
2801     tcg_temp_free_i32(tcg_rmode);
2802     return true;
2805 static bool trans_VRINTX_hp(DisasContext *s, arg_VRINTX_sp *a)
2807     TCGv_ptr fpst;
2808     TCGv_i32 tmp;
2810     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2811         return false;
2812     }
2814     if (!vfp_access_check(s)) {
2815         return true;
2816     }
2818     tmp = tcg_temp_new_i32();
2819     vfp_load_reg32(tmp, a->vm);
2820     fpst = fpstatus_ptr(FPST_FPCR_F16);
2821     gen_helper_rinth_exact(tmp, tmp, fpst);
2822     vfp_store_reg32(tmp, a->vd);
2823     tcg_temp_free_ptr(fpst);
2824     tcg_temp_free_i32(tmp);
2825     return true;
2828 static bool trans_VRINTX_sp(DisasContext *s, arg_VRINTX_sp *a)
2830     TCGv_ptr fpst;
2831     TCGv_i32 tmp;
2833     if (!dc_isar_feature(aa32_vrint, s)) {
2834         return false;
2835     }
2837     if (!vfp_access_check(s)) {
2838         return true;
2839     }
2841     tmp = tcg_temp_new_i32();
2842     vfp_load_reg32(tmp, a->vm);
2843     fpst = fpstatus_ptr(FPST_FPCR);
2844     gen_helper_rints_exact(tmp, tmp, fpst);
2845     vfp_store_reg32(tmp, a->vd);
2846     tcg_temp_free_ptr(fpst);
2847     tcg_temp_free_i32(tmp);
2848     return true;
2851 static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a)
2853     TCGv_ptr fpst;
2854     TCGv_i64 tmp;
2856     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2857         return false;
2858     }
2860     if (!dc_isar_feature(aa32_vrint, s)) {
2861         return false;
2862     }
2864     /* UNDEF accesses to D16-D31 if they don't exist. */
2865     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
2866         return false;
2867     }
2869     if (!vfp_access_check(s)) {
2870         return true;
2871     }
2873     tmp = tcg_temp_new_i64();
2874     vfp_load_reg64(tmp, a->vm);
2875     fpst = fpstatus_ptr(FPST_FPCR);
2876     gen_helper_rintd_exact(tmp, tmp, fpst);
2877     vfp_store_reg64(tmp, a->vd);
2878     tcg_temp_free_ptr(fpst);
2879     tcg_temp_free_i64(tmp);
2880     return true;
2883 static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a)
2885     TCGv_i64 vd;
2886     TCGv_i32 vm;
2888     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2889         return false;
2890     }
2892     /* UNDEF accesses to D16-D31 if they don't exist. */
2893     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
2894         return false;
2895     }
2897     if (!vfp_access_check(s)) {
2898         return true;
2899     }
2901     vm = tcg_temp_new_i32();
2902     vd = tcg_temp_new_i64();
2903     vfp_load_reg32(vm, a->vm);
2904     gen_helper_vfp_fcvtds(vd, vm, cpu_env);
2905     vfp_store_reg64(vd, a->vd);
2906     tcg_temp_free_i32(vm);
2907     tcg_temp_free_i64(vd);
2908     return true;
2911 static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a)
2913     TCGv_i64 vm;
2914     TCGv_i32 vd;
2916     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2917         return false;
2918     }
2920     /* UNDEF accesses to D16-D31 if they don't exist. */
2921     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
2922         return false;
2923     }
2925     if (!vfp_access_check(s)) {
2926         return true;
2927     }
2929     vd = tcg_temp_new_i32();
2930     vm = tcg_temp_new_i64();
2931     vfp_load_reg64(vm, a->vm);
2932     gen_helper_vfp_fcvtsd(vd, vm, cpu_env);
2933     vfp_store_reg32(vd, a->vd);
2934     tcg_temp_free_i32(vd);
2935     tcg_temp_free_i64(vm);
2936     return true;
2939 static bool trans_VCVT_int_hp(DisasContext *s, arg_VCVT_int_sp *a)
2941     TCGv_i32 vm;
2942     TCGv_ptr fpst;
2944     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2945         return false;
2946     }
2948     if (!vfp_access_check(s)) {
2949         return true;
2950     }
2952     vm = tcg_temp_new_i32();
2953     vfp_load_reg32(vm, a->vm);
2954     fpst = fpstatus_ptr(FPST_FPCR_F16);
2955     if (a->s) {
2956         /* i32 -> f16 */
2957         gen_helper_vfp_sitoh(vm, vm, fpst);
2958     } else {
2959         /* u32 -> f16 */
2960         gen_helper_vfp_uitoh(vm, vm, fpst);
2961     }
2962     vfp_store_reg32(vm, a->vd);
2963     tcg_temp_free_i32(vm);
2964     tcg_temp_free_ptr(fpst);
2965     return true;
2968 static bool trans_VCVT_int_sp(DisasContext *s, arg_VCVT_int_sp *a)
2970     TCGv_i32 vm;
2971     TCGv_ptr fpst;
2973     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2974         return false;
2975     }
2977     if (!vfp_access_check(s)) {
2978         return true;
2979     }
2981     vm = tcg_temp_new_i32();
2982     vfp_load_reg32(vm, a->vm);
2983     fpst = fpstatus_ptr(FPST_FPCR);
2984     if (a->s) {
2985         /* i32 -> f32 */
2986         gen_helper_vfp_sitos(vm, vm, fpst);
2987     } else {
2988         /* u32 -> f32 */
2989         gen_helper_vfp_uitos(vm, vm, fpst);
2990     }
2991     vfp_store_reg32(vm, a->vd);
2992     tcg_temp_free_i32(vm);
2993     tcg_temp_free_ptr(fpst);
2994     return true;
2997 static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a)
2999     TCGv_i32 vm;
3000     TCGv_i64 vd;
3001     TCGv_ptr fpst;
3003     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3004         return false;
3005     }
3007     /* UNDEF accesses to D16-D31 if they don't exist. */
3008     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
3009         return false;
3010     }
3012     if (!vfp_access_check(s)) {
3013         return true;
3014     }
3016     vm = tcg_temp_new_i32();
3017     vd = tcg_temp_new_i64();
3018     vfp_load_reg32(vm, a->vm);
3019     fpst = fpstatus_ptr(FPST_FPCR);
3020     if (a->s) {
3021         /* i32 -> f64 */
3022         gen_helper_vfp_sitod(vd, vm, fpst);
3023     } else {
3024         /* u32 -> f64 */
3025         gen_helper_vfp_uitod(vd, vm, fpst);
3026     }
3027     vfp_store_reg64(vd, a->vd);
3028     tcg_temp_free_i32(vm);
3029     tcg_temp_free_i64(vd);
3030     tcg_temp_free_ptr(fpst);
3031     return true;
3034 static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a)
3036     TCGv_i32 vd;
3037     TCGv_i64 vm;
3039     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3040         return false;
3041     }
3043     if (!dc_isar_feature(aa32_jscvt, s)) {
3044         return false;
3045     }
3047     /* UNDEF accesses to D16-D31 if they don't exist. */
3048     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
3049         return false;
3050     }
3052     if (!vfp_access_check(s)) {
3053         return true;
3054     }
3056     vm = tcg_temp_new_i64();
3057     vd = tcg_temp_new_i32();
3058     vfp_load_reg64(vm, a->vm);
3059     gen_helper_vjcvt(vd, vm, cpu_env);
3060     vfp_store_reg32(vd, a->vd);
3061     tcg_temp_free_i64(vm);
3062     tcg_temp_free_i32(vd);
3063     return true;
3066 static bool trans_VCVT_fix_hp(DisasContext *s, arg_VCVT_fix_sp *a)
3068     TCGv_i32 vd, shift;
3069     TCGv_ptr fpst;
3070     int frac_bits;
3072     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3073         return false;
3074     }
3076     if (!vfp_access_check(s)) {
3077         return true;
3078     }
3080     frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
3082     vd = tcg_temp_new_i32();
3083     vfp_load_reg32(vd, a->vd);
3085     fpst = fpstatus_ptr(FPST_FPCR_F16);
3086     shift = tcg_const_i32(frac_bits);
3088     /* Switch on op:U:sx bits */
3089     switch (a->opc) {
3090     case 0:
3091         gen_helper_vfp_shtoh_round_to_nearest(vd, vd, shift, fpst);
3092         break;
3093     case 1:
3094         gen_helper_vfp_sltoh_round_to_nearest(vd, vd, shift, fpst);
3095         break;
3096     case 2:
3097         gen_helper_vfp_uhtoh_round_to_nearest(vd, vd, shift, fpst);
3098         break;
3099     case 3:
3100         gen_helper_vfp_ultoh_round_to_nearest(vd, vd, shift, fpst);
3101         break;
3102     case 4:
3103         gen_helper_vfp_toshh_round_to_zero(vd, vd, shift, fpst);
3104         break;
3105     case 5:
3106         gen_helper_vfp_toslh_round_to_zero(vd, vd, shift, fpst);
3107         break;
3108     case 6:
3109         gen_helper_vfp_touhh_round_to_zero(vd, vd, shift, fpst);
3110         break;
3111     case 7:
3112         gen_helper_vfp_toulh_round_to_zero(vd, vd, shift, fpst);
3113         break;
3114     default:
3115         g_assert_not_reached();
3116     }
3118     vfp_store_reg32(vd, a->vd);
3119     tcg_temp_free_i32(vd);
3120     tcg_temp_free_i32(shift);
3121     tcg_temp_free_ptr(fpst);
3122     return true;
3125 static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a)
3127     TCGv_i32 vd, shift;
3128     TCGv_ptr fpst;
3129     int frac_bits;
3131     if (!dc_isar_feature(aa32_fpsp_v3, s)) {
3132         return false;
3133     }
3135     if (!vfp_access_check(s)) {
3136         return true;
3137     }
3139     frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
3141     vd = tcg_temp_new_i32();
3142     vfp_load_reg32(vd, a->vd);
3144     fpst = fpstatus_ptr(FPST_FPCR);
3145     shift = tcg_const_i32(frac_bits);
3147     /* Switch on op:U:sx bits */
3148     switch (a->opc) {
3149     case 0:
3150         gen_helper_vfp_shtos_round_to_nearest(vd, vd, shift, fpst);
3151         break;
3152     case 1:
3153         gen_helper_vfp_sltos_round_to_nearest(vd, vd, shift, fpst);
3154         break;
3155     case 2:
3156         gen_helper_vfp_uhtos_round_to_nearest(vd, vd, shift, fpst);
3157         break;
3158     case 3:
3159         gen_helper_vfp_ultos_round_to_nearest(vd, vd, shift, fpst);
3160         break;
3161     case 4:
3162         gen_helper_vfp_toshs_round_to_zero(vd, vd, shift, fpst);
3163         break;
3164     case 5:
3165         gen_helper_vfp_tosls_round_to_zero(vd, vd, shift, fpst);
3166         break;
3167     case 6:
3168         gen_helper_vfp_touhs_round_to_zero(vd, vd, shift, fpst);
3169         break;
3170     case 7:
3171         gen_helper_vfp_touls_round_to_zero(vd, vd, shift, fpst);
3172         break;
3173     default:
3174         g_assert_not_reached();
3175     }
3177     vfp_store_reg32(vd, a->vd);
3178     tcg_temp_free_i32(vd);
3179     tcg_temp_free_i32(shift);
3180     tcg_temp_free_ptr(fpst);
3181     return true;
3184 static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
3186     TCGv_i64 vd;
3187     TCGv_i32 shift;
3188     TCGv_ptr fpst;
3189     int frac_bits;
3191     if (!dc_isar_feature(aa32_fpdp_v3, s)) {
3192         return false;
3193     }
3195     /* UNDEF accesses to D16-D31 if they don't exist. */
3196     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
3197         return false;
3198     }
3200     if (!vfp_access_check(s)) {
3201         return true;
3202     }
3204     frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
3206     vd = tcg_temp_new_i64();
3207     vfp_load_reg64(vd, a->vd);
3209     fpst = fpstatus_ptr(FPST_FPCR);
3210     shift = tcg_const_i32(frac_bits);
3212     /* Switch on op:U:sx bits */
3213     switch (a->opc) {
3214     case 0:
3215         gen_helper_vfp_shtod_round_to_nearest(vd, vd, shift, fpst);
3216         break;
3217     case 1:
3218         gen_helper_vfp_sltod_round_to_nearest(vd, vd, shift, fpst);
3219         break;
3220     case 2:
3221         gen_helper_vfp_uhtod_round_to_nearest(vd, vd, shift, fpst);
3222         break;
3223     case 3:
3224         gen_helper_vfp_ultod_round_to_nearest(vd, vd, shift, fpst);
3225         break;
3226     case 4:
3227         gen_helper_vfp_toshd_round_to_zero(vd, vd, shift, fpst);
3228         break;
3229     case 5:
3230         gen_helper_vfp_tosld_round_to_zero(vd, vd, shift, fpst);
3231         break;
3232     case 6:
3233         gen_helper_vfp_touhd_round_to_zero(vd, vd, shift, fpst);
3234         break;
3235     case 7:
3236         gen_helper_vfp_tould_round_to_zero(vd, vd, shift, fpst);
3237         break;
3238     default:
3239         g_assert_not_reached();
3240     }
3242     vfp_store_reg64(vd, a->vd);
3243     tcg_temp_free_i64(vd);
3244     tcg_temp_free_i32(shift);
3245     tcg_temp_free_ptr(fpst);
3246     return true;
3249 static bool trans_VCVT_hp_int(DisasContext *s, arg_VCVT_sp_int *a)
3251     TCGv_i32 vm;
3252     TCGv_ptr fpst;
3254     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3255         return false;
3256     }
3258     if (!vfp_access_check(s)) {
3259         return true;
3260     }
3262     fpst = fpstatus_ptr(FPST_FPCR_F16);
3263     vm = tcg_temp_new_i32();
3264     vfp_load_reg32(vm, a->vm);
3266     if (a->s) {
3267         if (a->rz) {
3268             gen_helper_vfp_tosizh(vm, vm, fpst);
3269         } else {
3270             gen_helper_vfp_tosih(vm, vm, fpst);
3271         }
3272     } else {
3273         if (a->rz) {
3274             gen_helper_vfp_touizh(vm, vm, fpst);
3275         } else {
3276             gen_helper_vfp_touih(vm, vm, fpst);
3277         }
3278     }
3279     vfp_store_reg32(vm, a->vd);
3280     tcg_temp_free_i32(vm);
3281     tcg_temp_free_ptr(fpst);
3282     return true;
3285 static bool trans_VCVT_sp_int(DisasContext *s, arg_VCVT_sp_int *a)
3287     TCGv_i32 vm;
3288     TCGv_ptr fpst;
3290     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
3291         return false;
3292     }
3294     if (!vfp_access_check(s)) {
3295         return true;
3296     }
3298     fpst = fpstatus_ptr(FPST_FPCR);
3299     vm = tcg_temp_new_i32();
3300     vfp_load_reg32(vm, a->vm);
3302     if (a->s) {
3303         if (a->rz) {
3304             gen_helper_vfp_tosizs(vm, vm, fpst);
3305         } else {
3306             gen_helper_vfp_tosis(vm, vm, fpst);
3307         }
3308     } else {
3309         if (a->rz) {
3310             gen_helper_vfp_touizs(vm, vm, fpst);
3311         } else {
3312             gen_helper_vfp_touis(vm, vm, fpst);
3313         }
3314     }
3315     vfp_store_reg32(vm, a->vd);
3316     tcg_temp_free_i32(vm);
3317     tcg_temp_free_ptr(fpst);
3318     return true;
3321 static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
3323     TCGv_i32 vd;
3324     TCGv_i64 vm;
3325     TCGv_ptr fpst;
3327     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3328         return false;
3329     }
3331     /* UNDEF accesses to D16-D31 if they don't exist. */
3332     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
3333         return false;
3334     }
3336     if (!vfp_access_check(s)) {
3337         return true;
3338     }
3340     fpst = fpstatus_ptr(FPST_FPCR);
3341     vm = tcg_temp_new_i64();
3342     vd = tcg_temp_new_i32();
3343     vfp_load_reg64(vm, a->vm);
3345     if (a->s) {
3346         if (a->rz) {
3347             gen_helper_vfp_tosizd(vd, vm, fpst);
3348         } else {
3349             gen_helper_vfp_tosid(vd, vm, fpst);
3350         }
3351     } else {
3352         if (a->rz) {
3353             gen_helper_vfp_touizd(vd, vm, fpst);
3354         } else {
3355             gen_helper_vfp_touid(vd, vm, fpst);
3356         }
3357     }
3358     vfp_store_reg32(vd, a->vd);
3359     tcg_temp_free_i32(vd);
3360     tcg_temp_free_i64(vm);
3361     tcg_temp_free_ptr(fpst);
3362     return true;
3366  * Decode VLLDM and VLSTM are nonstandard because:
3367  *  * if there is no FPU then these insns must NOP in
3368  *    Secure state and UNDEF in Nonsecure state
3369  *  * if there is an FPU then these insns do not have
3370  *    the usual behaviour that vfp_access_check() provides of
3371  *    being controlled by CPACR/NSACR enable bits or the
3372  *    lazy-stacking logic.
3373  */
3374 static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
3376     TCGv_i32 fptr;
3378     if (!arm_dc_feature(s, ARM_FEATURE_M) ||
3379         !arm_dc_feature(s, ARM_FEATURE_V8)) {
3380         return false;
3381     }
3382     /*
3383      * If not secure, UNDEF. We must emit code for this
3384      * rather than returning false so that this takes
3385      * precedence over the m-nocp.decode NOCP fallback.
3386      */
3387     if (!s->v8m_secure) {
3388         unallocated_encoding(s);
3389         return true;
3390     }
3391     /* If no fpu, NOP. */
3392     if (!dc_isar_feature(aa32_vfp, s)) {
3393         return true;
3394     }
3396     fptr = load_reg(s, a->rn);
3397     if (a->l) {
3398         gen_helper_v7m_vlldm(cpu_env, fptr);
3399     } else {
3400         gen_helper_v7m_vlstm(cpu_env, fptr);
3401     }
3402     tcg_temp_free_i32(fptr);
3404     /* End the TB, because we have updated FP control bits */
3405     s->base.is_jmp = DISAS_UPDATE_EXIT;
3406     return true;
3409 static bool trans_NOCP(DisasContext *s, arg_nocp *a)
3411     /*
3412      * Handle M-profile early check for disabled coprocessor:
3413      * all we need to do here is emit the NOCP exception if
3414      * the coprocessor is disabled. Otherwise we return false
3415      * and the real VFP/etc decode will handle the insn.
3416      */
3417     assert(arm_dc_feature(s, ARM_FEATURE_M));
3419     if (a->cp == 11) {
3420         a->cp = 10;
3421     }
3422     if (arm_dc_feature(s, ARM_FEATURE_V8_1M) &&
3423         (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) {
3424         /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
3425         a->cp = 10;
3426     }
3428     if (a->cp != 10) {
3429         gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
3430                            syn_uncategorized(), default_exception_el(s));
3431         return true;
3432     }
3434     if (s->fp_excp_el != 0) {
3435         gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
3436                            syn_uncategorized(), s->fp_excp_el);
3437         return true;
3438     }
3440     return false;
3443 static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a)
3445     /* This range needs a coprocessor check for v8.1M and later only */
3446     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
3447         return false;
3448     }
3449     return trans_NOCP(s, a);
3452 static bool trans_VINS(DisasContext *s, arg_VINS *a)
3454     TCGv_i32 rd, rm;
3456     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3457         return false;
3458     }
3460     if (s->vec_len != 0 || s->vec_stride != 0) {
3461         return false;
3462     }
3464     if (!vfp_access_check(s)) {
3465         return true;
3466     }
3468     /* Insert low half of Vm into high half of Vd */
3469     rm = tcg_temp_new_i32();
3470     rd = tcg_temp_new_i32();
3471     vfp_load_reg32(rm, a->vm);
3472     vfp_load_reg32(rd, a->vd);
3473     tcg_gen_deposit_i32(rd, rd, rm, 16, 16);
3474     vfp_store_reg32(rd, a->vd);
3475     tcg_temp_free_i32(rm);
3476     tcg_temp_free_i32(rd);
3477     return true;
3480 static bool trans_VMOVX(DisasContext *s, arg_VINS *a)
3482     TCGv_i32 rm;
3484     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3485         return false;
3486     }
3488     if (s->vec_len != 0 || s->vec_stride != 0) {
3489         return false;
3490     }
3492     if (!vfp_access_check(s)) {
3493         return true;
3494     }
3496     /* Set Vd to high half of Vm */
3497     rm = tcg_temp_new_i32();
3498     vfp_load_reg32(rm, a->vm);
3499     tcg_gen_shri_i32(rm, rm, 16);
3500     vfp_store_reg32(rm, a->vd);
3501     tcg_temp_free_i32(rm);
3502     return true;