target/arm: Implement M-profile FPSCR_nzcvqc
[qemu/ar7.git] / target / arm / translate-vfp.c.inc
blobd698f3e1cd130a993a9a86850aa93d4506974dd0
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;
611  * M-profile provides two different sets of instructions that can
612  * access floating point system registers: VMSR/VMRS (which move
613  * to/from a general purpose register) and VLDR/VSTR sysreg (which
614  * move directly to/from memory). In some cases there are also side
615  * effects which must happen after any write to memory (which could
616  * cause an exception). So we implement the common logic for the
617  * sysreg access in gen_M_fp_sysreg_write() and gen_M_fp_sysreg_read(),
618  * which take pointers to callback functions which will perform the
619  * actual "read/write general purpose register" and "read/write
620  * memory" operations.
621  */
624  * Emit code to store the sysreg to its final destination; frees the
625  * TCG temp 'value' it is passed.
626  */
627 typedef void fp_sysreg_storefn(DisasContext *s, void *opaque, TCGv_i32 value);
629  * Emit code to load the value to be copied to the sysreg; returns
630  * a new TCG temporary
631  */
632 typedef TCGv_i32 fp_sysreg_loadfn(DisasContext *s, void *opaque);
634 /* Common decode/access checks for fp sysreg read/write */
635 typedef enum FPSysRegCheckResult {
636     FPSysRegCheckFailed, /* caller should return false */
637     FPSysRegCheckDone, /* caller should return true */
638     FPSysRegCheckContinue, /* caller should continue generating code */
639 } FPSysRegCheckResult;
641 static FPSysRegCheckResult fp_sysreg_checks(DisasContext *s, int regno)
643     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
644         return FPSysRegCheckFailed;
645     }
647     switch (regno) {
648     case ARM_VFP_FPSCR:
649     case QEMU_VFP_FPSCR_NZCV:
650         break;
651     case ARM_VFP_FPSCR_NZCVQC:
652         if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
653             return false;
654         }
655         break;
656     default:
657         return FPSysRegCheckFailed;
658     }
660     if (!vfp_access_check(s)) {
661         return FPSysRegCheckDone;
662     }
664     return FPSysRegCheckContinue;
667 static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
669                                   fp_sysreg_loadfn *loadfn,
670                                  void *opaque)
672     /* Do a write to an M-profile floating point system register */
673     TCGv_i32 tmp;
675     switch (fp_sysreg_checks(s, regno)) {
676     case FPSysRegCheckFailed:
677         return false;
678     case FPSysRegCheckDone:
679         return true;
680     case FPSysRegCheckContinue:
681         break;
682     }
684     switch (regno) {
685     case ARM_VFP_FPSCR:
686         tmp = loadfn(s, opaque);
687         gen_helper_vfp_set_fpscr(cpu_env, tmp);
688         tcg_temp_free_i32(tmp);
689         gen_lookup_tb(s);
690         break;
691     case ARM_VFP_FPSCR_NZCVQC:
692     {
693         TCGv_i32 fpscr;
694         tmp = loadfn(s, opaque);
695         /*
696          * TODO: when we implement MVE, write the QC bit.
697          * For non-MVE, QC is RES0.
698          */
699         tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK);
700         fpscr = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
701         tcg_gen_andi_i32(fpscr, fpscr, ~FPCR_NZCV_MASK);
702         tcg_gen_or_i32(fpscr, fpscr, tmp);
703         store_cpu_field(fpscr, vfp.xregs[ARM_VFP_FPSCR]);
704         tcg_temp_free_i32(tmp);
705         break;
706     }
707     default:
708         g_assert_not_reached();
709     }
710     return true;
713 static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
714                                 fp_sysreg_storefn *storefn,
715                                 void *opaque)
717     /* Do a read from an M-profile floating point system register */
718     TCGv_i32 tmp;
720     switch (fp_sysreg_checks(s, regno)) {
721     case FPSysRegCheckFailed:
722         return false;
723     case FPSysRegCheckDone:
724         return true;
725     case FPSysRegCheckContinue:
726         break;
727     }
729     switch (regno) {
730     case ARM_VFP_FPSCR:
731         tmp = tcg_temp_new_i32();
732         gen_helper_vfp_get_fpscr(tmp, cpu_env);
733         storefn(s, opaque, tmp);
734         break;
735     case ARM_VFP_FPSCR_NZCVQC:
736         /*
737          * TODO: MVE has a QC bit, which we probably won't store
738          * in the xregs[] field. For non-MVE, where QC is RES0,
739          * we can just fall through to the FPSCR_NZCV case.
740          */
741     case QEMU_VFP_FPSCR_NZCV:
742         /*
743          * Read just NZCV; this is a special case to avoid the
744          * helper call for the "VMRS to CPSR.NZCV" insn.
745          */
746         tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
747         tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
748         storefn(s, opaque, tmp);
749         break;
750     default:
751         g_assert_not_reached();
752     }
753     return true;
756 static void fp_sysreg_to_gpr(DisasContext *s, void *opaque, TCGv_i32 value)
758     arg_VMSR_VMRS *a = opaque;
760     if (a->rt == 15) {
761         /* Set the 4 flag bits in the CPSR */
762         gen_set_nzcv(value);
763         tcg_temp_free_i32(value);
764     } else {
765         store_reg(s, a->rt, value);
766     }
769 static TCGv_i32 gpr_to_fp_sysreg(DisasContext *s, void *opaque)
771     arg_VMSR_VMRS *a = opaque;
773     return load_reg(s, a->rt);
776 static bool gen_M_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
778     /*
779      * Accesses to R15 are UNPREDICTABLE; we choose to undef.
780      * FPSCR -> r15 is a special case which writes to the PSR flags;
781      * set a->reg to a special value to tell gen_M_fp_sysreg_read()
782      * we only care about the top 4 bits of FPSCR there.
783      */
784     if (a->rt == 15) {
785         if (a->l && a->reg == ARM_VFP_FPSCR) {
786             a->reg = QEMU_VFP_FPSCR_NZCV;
787         } else {
788             return false;
789         }
790     }
792     if (a->l) {
793         /* VMRS, move FP system register to gp register */
794         return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_gpr, a);
795     } else {
796         /* VMSR, move gp register to FP system register */
797         return gen_M_fp_sysreg_write(s, a->reg, gpr_to_fp_sysreg, a);
798     }
801 static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
803     TCGv_i32 tmp;
804     bool ignore_vfp_enabled = false;
806     if (arm_dc_feature(s, ARM_FEATURE_M)) {
807         return gen_M_VMSR_VMRS(s, a);
808     }
810     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
811         return false;
812     }
814     switch (a->reg) {
815     case ARM_VFP_FPSID:
816         /*
817          * VFPv2 allows access to FPSID from userspace; VFPv3 restricts
818          * all ID registers to privileged access only.
819          */
820         if (IS_USER(s) && dc_isar_feature(aa32_fpsp_v3, s)) {
821             return false;
822         }
823         ignore_vfp_enabled = true;
824         break;
825     case ARM_VFP_MVFR0:
826     case ARM_VFP_MVFR1:
827         if (IS_USER(s) || !arm_dc_feature(s, ARM_FEATURE_MVFR)) {
828             return false;
829         }
830         ignore_vfp_enabled = true;
831         break;
832     case ARM_VFP_MVFR2:
833         if (IS_USER(s) || !arm_dc_feature(s, ARM_FEATURE_V8)) {
834             return false;
835         }
836         ignore_vfp_enabled = true;
837         break;
838     case ARM_VFP_FPSCR:
839         break;
840     case ARM_VFP_FPEXC:
841         if (IS_USER(s)) {
842             return false;
843         }
844         ignore_vfp_enabled = true;
845         break;
846     case ARM_VFP_FPINST:
847     case ARM_VFP_FPINST2:
848         /* Not present in VFPv3 */
849         if (IS_USER(s) || dc_isar_feature(aa32_fpsp_v3, s)) {
850             return false;
851         }
852         break;
853     default:
854         return false;
855     }
857     if (!full_vfp_access_check(s, ignore_vfp_enabled)) {
858         return true;
859     }
861     if (a->l) {
862         /* VMRS, move VFP special register to gp register */
863         switch (a->reg) {
864         case ARM_VFP_MVFR0:
865         case ARM_VFP_MVFR1:
866         case ARM_VFP_MVFR2:
867         case ARM_VFP_FPSID:
868             if (s->current_el == 1) {
869                 TCGv_i32 tcg_reg, tcg_rt;
871                 gen_set_condexec(s);
872                 gen_set_pc_im(s, s->pc_curr);
873                 tcg_reg = tcg_const_i32(a->reg);
874                 tcg_rt = tcg_const_i32(a->rt);
875                 gen_helper_check_hcr_el2_trap(cpu_env, tcg_rt, tcg_reg);
876                 tcg_temp_free_i32(tcg_reg);
877                 tcg_temp_free_i32(tcg_rt);
878             }
879             /* fall through */
880         case ARM_VFP_FPEXC:
881         case ARM_VFP_FPINST:
882         case ARM_VFP_FPINST2:
883             tmp = load_cpu_field(vfp.xregs[a->reg]);
884             break;
885         case ARM_VFP_FPSCR:
886             if (a->rt == 15) {
887                 tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
888                 tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
889             } else {
890                 tmp = tcg_temp_new_i32();
891                 gen_helper_vfp_get_fpscr(tmp, cpu_env);
892             }
893             break;
894         default:
895             g_assert_not_reached();
896         }
898         if (a->rt == 15) {
899             /* Set the 4 flag bits in the CPSR.  */
900             gen_set_nzcv(tmp);
901             tcg_temp_free_i32(tmp);
902         } else {
903             store_reg(s, a->rt, tmp);
904         }
905     } else {
906         /* VMSR, move gp register to VFP special register */
907         switch (a->reg) {
908         case ARM_VFP_FPSID:
909         case ARM_VFP_MVFR0:
910         case ARM_VFP_MVFR1:
911         case ARM_VFP_MVFR2:
912             /* Writes are ignored.  */
913             break;
914         case ARM_VFP_FPSCR:
915             tmp = load_reg(s, a->rt);
916             gen_helper_vfp_set_fpscr(cpu_env, tmp);
917             tcg_temp_free_i32(tmp);
918             gen_lookup_tb(s);
919             break;
920         case ARM_VFP_FPEXC:
921             /*
922              * TODO: VFP subarchitecture support.
923              * For now, keep the EN bit only
924              */
925             tmp = load_reg(s, a->rt);
926             tcg_gen_andi_i32(tmp, tmp, 1 << 30);
927             store_cpu_field(tmp, vfp.xregs[a->reg]);
928             gen_lookup_tb(s);
929             break;
930         case ARM_VFP_FPINST:
931         case ARM_VFP_FPINST2:
932             tmp = load_reg(s, a->rt);
933             store_cpu_field(tmp, vfp.xregs[a->reg]);
934             break;
935         default:
936             g_assert_not_reached();
937         }
938     }
940     return true;
943 static void fp_sysreg_to_memory(DisasContext *s, void *opaque, TCGv_i32 value)
945     arg_vldr_sysreg *a = opaque;
946     uint32_t offset = a->imm;
947     TCGv_i32 addr;
949     if (!a->a) {
950         offset = - offset;
951     }
953     addr = load_reg(s, a->rn);
954     if (a->p) {
955         tcg_gen_addi_i32(addr, addr, offset);
956     }
958     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
959         gen_helper_v8m_stackcheck(cpu_env, addr);
960     }
962     gen_aa32_st_i32(s, value, addr, get_mem_index(s),
963                     MO_UL | MO_ALIGN | s->be_data);
964     tcg_temp_free_i32(value);
966     if (a->w) {
967         /* writeback */
968         if (!a->p) {
969             tcg_gen_addi_i32(addr, addr, offset);
970         }
971         store_reg(s, a->rn, addr);
972     } else {
973         tcg_temp_free_i32(addr);
974     }
977 static TCGv_i32 memory_to_fp_sysreg(DisasContext *s, void *opaque)
979     arg_vldr_sysreg *a = opaque;
980     uint32_t offset = a->imm;
981     TCGv_i32 addr;
982     TCGv_i32 value = tcg_temp_new_i32();
984     if (!a->a) {
985         offset = - offset;
986     }
988     addr = load_reg(s, a->rn);
989     if (a->p) {
990         tcg_gen_addi_i32(addr, addr, offset);
991     }
993     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
994         gen_helper_v8m_stackcheck(cpu_env, addr);
995     }
997     gen_aa32_ld_i32(s, value, addr, get_mem_index(s),
998                     MO_UL | MO_ALIGN | s->be_data);
1000     if (a->w) {
1001         /* writeback */
1002         if (!a->p) {
1003             tcg_gen_addi_i32(addr, addr, offset);
1004         }
1005         store_reg(s, a->rn, addr);
1006     } else {
1007         tcg_temp_free_i32(addr);
1008     }
1009     return value;
1012 static bool trans_VLDR_sysreg(DisasContext *s, arg_vldr_sysreg *a)
1014     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
1015         return false;
1016     }
1017     if (a->rn == 15) {
1018         return false;
1019     }
1020     return gen_M_fp_sysreg_write(s, a->reg, memory_to_fp_sysreg, a);
1023 static bool trans_VSTR_sysreg(DisasContext *s, arg_vldr_sysreg *a)
1025     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
1026         return false;
1027     }
1028     if (a->rn == 15) {
1029         return false;
1030     }
1031     return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_memory, a);
1034 static bool trans_VMOV_half(DisasContext *s, arg_VMOV_single *a)
1036     TCGv_i32 tmp;
1038     if (!dc_isar_feature(aa32_fp16_arith, s)) {
1039         return false;
1040     }
1042     if (a->rt == 15) {
1043         /* UNPREDICTABLE; we choose to UNDEF */
1044         return false;
1045     }
1047     if (!vfp_access_check(s)) {
1048         return true;
1049     }
1051     if (a->l) {
1052         /* VFP to general purpose register */
1053         tmp = tcg_temp_new_i32();
1054         vfp_load_reg32(tmp, a->vn);
1055         tcg_gen_andi_i32(tmp, tmp, 0xffff);
1056         store_reg(s, a->rt, tmp);
1057     } else {
1058         /* general purpose register to VFP */
1059         tmp = load_reg(s, a->rt);
1060         tcg_gen_andi_i32(tmp, tmp, 0xffff);
1061         vfp_store_reg32(tmp, a->vn);
1062         tcg_temp_free_i32(tmp);
1063     }
1065     return true;
1068 static bool trans_VMOV_single(DisasContext *s, arg_VMOV_single *a)
1070     TCGv_i32 tmp;
1072     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1073         return false;
1074     }
1076     if (!vfp_access_check(s)) {
1077         return true;
1078     }
1080     if (a->l) {
1081         /* VFP to general purpose register */
1082         tmp = tcg_temp_new_i32();
1083         vfp_load_reg32(tmp, a->vn);
1084         if (a->rt == 15) {
1085             /* Set the 4 flag bits in the CPSR.  */
1086             gen_set_nzcv(tmp);
1087             tcg_temp_free_i32(tmp);
1088         } else {
1089             store_reg(s, a->rt, tmp);
1090         }
1091     } else {
1092         /* general purpose register to VFP */
1093         tmp = load_reg(s, a->rt);
1094         vfp_store_reg32(tmp, a->vn);
1095         tcg_temp_free_i32(tmp);
1096     }
1098     return true;
1101 static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a)
1103     TCGv_i32 tmp;
1105     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1106         return false;
1107     }
1109     /*
1110      * VMOV between two general-purpose registers and two single precision
1111      * floating point registers
1112      */
1113     if (!vfp_access_check(s)) {
1114         return true;
1115     }
1117     if (a->op) {
1118         /* fpreg to gpreg */
1119         tmp = tcg_temp_new_i32();
1120         vfp_load_reg32(tmp, a->vm);
1121         store_reg(s, a->rt, tmp);
1122         tmp = tcg_temp_new_i32();
1123         vfp_load_reg32(tmp, a->vm + 1);
1124         store_reg(s, a->rt2, tmp);
1125     } else {
1126         /* gpreg to fpreg */
1127         tmp = load_reg(s, a->rt);
1128         vfp_store_reg32(tmp, a->vm);
1129         tcg_temp_free_i32(tmp);
1130         tmp = load_reg(s, a->rt2);
1131         vfp_store_reg32(tmp, a->vm + 1);
1132         tcg_temp_free_i32(tmp);
1133     }
1135     return true;
1138 static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_dp *a)
1140     TCGv_i32 tmp;
1142     /*
1143      * VMOV between two general-purpose registers and one double precision
1144      * floating point register.  Note that this does not require support
1145      * for double precision arithmetic.
1146      */
1147     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1148         return false;
1149     }
1151     /* UNDEF accesses to D16-D31 if they don't exist */
1152     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
1153         return false;
1154     }
1156     if (!vfp_access_check(s)) {
1157         return true;
1158     }
1160     if (a->op) {
1161         /* fpreg to gpreg */
1162         tmp = tcg_temp_new_i32();
1163         vfp_load_reg32(tmp, a->vm * 2);
1164         store_reg(s, a->rt, tmp);
1165         tmp = tcg_temp_new_i32();
1166         vfp_load_reg32(tmp, a->vm * 2 + 1);
1167         store_reg(s, a->rt2, tmp);
1168     } else {
1169         /* gpreg to fpreg */
1170         tmp = load_reg(s, a->rt);
1171         vfp_store_reg32(tmp, a->vm * 2);
1172         tcg_temp_free_i32(tmp);
1173         tmp = load_reg(s, a->rt2);
1174         vfp_store_reg32(tmp, a->vm * 2 + 1);
1175         tcg_temp_free_i32(tmp);
1176     }
1178     return true;
1181 static bool trans_VLDR_VSTR_hp(DisasContext *s, arg_VLDR_VSTR_sp *a)
1183     uint32_t offset;
1184     TCGv_i32 addr, tmp;
1186     if (!dc_isar_feature(aa32_fp16_arith, s)) {
1187         return false;
1188     }
1190     if (!vfp_access_check(s)) {
1191         return true;
1192     }
1194     /* imm8 field is offset/2 for fp16, unlike fp32 and fp64 */
1195     offset = a->imm << 1;
1196     if (!a->u) {
1197         offset = -offset;
1198     }
1200     /* For thumb, use of PC is UNPREDICTABLE.  */
1201     addr = add_reg_for_lit(s, a->rn, offset);
1202     tmp = tcg_temp_new_i32();
1203     if (a->l) {
1204         gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
1205         vfp_store_reg32(tmp, a->vd);
1206     } else {
1207         vfp_load_reg32(tmp, a->vd);
1208         gen_aa32_st16(s, tmp, addr, get_mem_index(s));
1209     }
1210     tcg_temp_free_i32(tmp);
1211     tcg_temp_free_i32(addr);
1213     return true;
1216 static bool trans_VLDR_VSTR_sp(DisasContext *s, arg_VLDR_VSTR_sp *a)
1218     uint32_t offset;
1219     TCGv_i32 addr, tmp;
1221     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1222         return false;
1223     }
1225     if (!vfp_access_check(s)) {
1226         return true;
1227     }
1229     offset = a->imm << 2;
1230     if (!a->u) {
1231         offset = -offset;
1232     }
1234     /* For thumb, use of PC is UNPREDICTABLE.  */
1235     addr = add_reg_for_lit(s, a->rn, offset);
1236     tmp = tcg_temp_new_i32();
1237     if (a->l) {
1238         gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
1239         vfp_store_reg32(tmp, a->vd);
1240     } else {
1241         vfp_load_reg32(tmp, a->vd);
1242         gen_aa32_st32(s, tmp, addr, get_mem_index(s));
1243     }
1244     tcg_temp_free_i32(tmp);
1245     tcg_temp_free_i32(addr);
1247     return true;
1250 static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a)
1252     uint32_t offset;
1253     TCGv_i32 addr;
1254     TCGv_i64 tmp;
1256     /* Note that this does not require support for double arithmetic.  */
1257     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1258         return false;
1259     }
1261     /* UNDEF accesses to D16-D31 if they don't exist */
1262     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
1263         return false;
1264     }
1266     if (!vfp_access_check(s)) {
1267         return true;
1268     }
1270     offset = a->imm << 2;
1271     if (!a->u) {
1272         offset = -offset;
1273     }
1275     /* For thumb, use of PC is UNPREDICTABLE.  */
1276     addr = add_reg_for_lit(s, a->rn, offset);
1277     tmp = tcg_temp_new_i64();
1278     if (a->l) {
1279         gen_aa32_ld64(s, tmp, addr, get_mem_index(s));
1280         vfp_store_reg64(tmp, a->vd);
1281     } else {
1282         vfp_load_reg64(tmp, a->vd);
1283         gen_aa32_st64(s, tmp, addr, get_mem_index(s));
1284     }
1285     tcg_temp_free_i64(tmp);
1286     tcg_temp_free_i32(addr);
1288     return true;
1291 static bool trans_VLDM_VSTM_sp(DisasContext *s, arg_VLDM_VSTM_sp *a)
1293     uint32_t offset;
1294     TCGv_i32 addr, tmp;
1295     int i, n;
1297     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1298         return false;
1299     }
1301     n = a->imm;
1303     if (n == 0 || (a->vd + n) > 32) {
1304         /*
1305          * UNPREDICTABLE cases for bad immediates: we choose to
1306          * UNDEF to avoid generating huge numbers of TCG ops
1307          */
1308         return false;
1309     }
1310     if (a->rn == 15 && a->w) {
1311         /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1312         return false;
1313     }
1315     if (!vfp_access_check(s)) {
1316         return true;
1317     }
1319     /* For thumb, use of PC is UNPREDICTABLE.  */
1320     addr = add_reg_for_lit(s, a->rn, 0);
1321     if (a->p) {
1322         /* pre-decrement */
1323         tcg_gen_addi_i32(addr, addr, -(a->imm << 2));
1324     }
1326     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
1327         /*
1328          * Here 'addr' is the lowest address we will store to,
1329          * and is either the old SP (if post-increment) or
1330          * the new SP (if pre-decrement). For post-increment
1331          * where the old value is below the limit and the new
1332          * value is above, it is UNKNOWN whether the limit check
1333          * triggers; we choose to trigger.
1334          */
1335         gen_helper_v8m_stackcheck(cpu_env, addr);
1336     }
1338     offset = 4;
1339     tmp = tcg_temp_new_i32();
1340     for (i = 0; i < n; i++) {
1341         if (a->l) {
1342             /* load */
1343             gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
1344             vfp_store_reg32(tmp, a->vd + i);
1345         } else {
1346             /* store */
1347             vfp_load_reg32(tmp, a->vd + i);
1348             gen_aa32_st32(s, tmp, addr, get_mem_index(s));
1349         }
1350         tcg_gen_addi_i32(addr, addr, offset);
1351     }
1352     tcg_temp_free_i32(tmp);
1353     if (a->w) {
1354         /* writeback */
1355         if (a->p) {
1356             offset = -offset * n;
1357             tcg_gen_addi_i32(addr, addr, offset);
1358         }
1359         store_reg(s, a->rn, addr);
1360     } else {
1361         tcg_temp_free_i32(addr);
1362     }
1364     return true;
1367 static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a)
1369     uint32_t offset;
1370     TCGv_i32 addr;
1371     TCGv_i64 tmp;
1372     int i, n;
1374     /* Note that this does not require support for double arithmetic.  */
1375     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1376         return false;
1377     }
1379     n = a->imm >> 1;
1381     if (n == 0 || (a->vd + n) > 32 || n > 16) {
1382         /*
1383          * UNPREDICTABLE cases for bad immediates: we choose to
1384          * UNDEF to avoid generating huge numbers of TCG ops
1385          */
1386         return false;
1387     }
1388     if (a->rn == 15 && a->w) {
1389         /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1390         return false;
1391     }
1393     /* UNDEF accesses to D16-D31 if they don't exist */
1394     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd + n) > 16) {
1395         return false;
1396     }
1398     if (!vfp_access_check(s)) {
1399         return true;
1400     }
1402     /* For thumb, use of PC is UNPREDICTABLE.  */
1403     addr = add_reg_for_lit(s, a->rn, 0);
1404     if (a->p) {
1405         /* pre-decrement */
1406         tcg_gen_addi_i32(addr, addr, -(a->imm << 2));
1407     }
1409     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
1410         /*
1411          * Here 'addr' is the lowest address we will store to,
1412          * and is either the old SP (if post-increment) or
1413          * the new SP (if pre-decrement). For post-increment
1414          * where the old value is below the limit and the new
1415          * value is above, it is UNKNOWN whether the limit check
1416          * triggers; we choose to trigger.
1417          */
1418         gen_helper_v8m_stackcheck(cpu_env, addr);
1419     }
1421     offset = 8;
1422     tmp = tcg_temp_new_i64();
1423     for (i = 0; i < n; i++) {
1424         if (a->l) {
1425             /* load */
1426             gen_aa32_ld64(s, tmp, addr, get_mem_index(s));
1427             vfp_store_reg64(tmp, a->vd + i);
1428         } else {
1429             /* store */
1430             vfp_load_reg64(tmp, a->vd + i);
1431             gen_aa32_st64(s, tmp, addr, get_mem_index(s));
1432         }
1433         tcg_gen_addi_i32(addr, addr, offset);
1434     }
1435     tcg_temp_free_i64(tmp);
1436     if (a->w) {
1437         /* writeback */
1438         if (a->p) {
1439             offset = -offset * n;
1440         } else if (a->imm & 1) {
1441             offset = 4;
1442         } else {
1443             offset = 0;
1444         }
1446         if (offset != 0) {
1447             tcg_gen_addi_i32(addr, addr, offset);
1448         }
1449         store_reg(s, a->rn, addr);
1450     } else {
1451         tcg_temp_free_i32(addr);
1452     }
1454     return true;
1458  * Types for callbacks for do_vfp_3op_sp() and do_vfp_3op_dp().
1459  * The callback should emit code to write a value to vd. If
1460  * do_vfp_3op_{sp,dp}() was passed reads_vd then the TCGv vd
1461  * will contain the old value of the relevant VFP register;
1462  * otherwise it must be written to only.
1463  */
1464 typedef void VFPGen3OpSPFn(TCGv_i32 vd,
1465                            TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst);
1466 typedef void VFPGen3OpDPFn(TCGv_i64 vd,
1467                            TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst);
1470  * Types for callbacks for do_vfp_2op_sp() and do_vfp_2op_dp().
1471  * The callback should emit code to write a value to vd (which
1472  * should be written to only).
1473  */
1474 typedef void VFPGen2OpSPFn(TCGv_i32 vd, TCGv_i32 vm);
1475 typedef void VFPGen2OpDPFn(TCGv_i64 vd, TCGv_i64 vm);
1478  * Return true if the specified S reg is in a scalar bank
1479  * (ie if it is s0..s7)
1480  */
1481 static inline bool vfp_sreg_is_scalar(int reg)
1483     return (reg & 0x18) == 0;
1487  * Return true if the specified D reg is in a scalar bank
1488  * (ie if it is d0..d3 or d16..d19)
1489  */
1490 static inline bool vfp_dreg_is_scalar(int reg)
1492     return (reg & 0xc) == 0;
1496  * Advance the S reg number forwards by delta within its bank
1497  * (ie increment the low 3 bits but leave the rest the same)
1498  */
1499 static inline int vfp_advance_sreg(int reg, int delta)
1501     return ((reg + delta) & 0x7) | (reg & ~0x7);
1505  * Advance the D reg number forwards by delta within its bank
1506  * (ie increment the low 2 bits but leave the rest the same)
1507  */
1508 static inline int vfp_advance_dreg(int reg, int delta)
1510     return ((reg + delta) & 0x3) | (reg & ~0x3);
1514  * Perform a 3-operand VFP data processing instruction. fn is the
1515  * callback to do the actual operation; this function deals with the
1516  * code to handle looping around for VFP vector processing.
1517  */
1518 static bool do_vfp_3op_sp(DisasContext *s, VFPGen3OpSPFn *fn,
1519                           int vd, int vn, int vm, bool reads_vd)
1521     uint32_t delta_m = 0;
1522     uint32_t delta_d = 0;
1523     int veclen = s->vec_len;
1524     TCGv_i32 f0, f1, fd;
1525     TCGv_ptr fpst;
1527     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1528         return false;
1529     }
1531     if (!dc_isar_feature(aa32_fpshvec, s) &&
1532         (veclen != 0 || s->vec_stride != 0)) {
1533         return false;
1534     }
1536     if (!vfp_access_check(s)) {
1537         return true;
1538     }
1540     if (veclen > 0) {
1541         /* Figure out what type of vector operation this is.  */
1542         if (vfp_sreg_is_scalar(vd)) {
1543             /* scalar */
1544             veclen = 0;
1545         } else {
1546             delta_d = s->vec_stride + 1;
1548             if (vfp_sreg_is_scalar(vm)) {
1549                 /* mixed scalar/vector */
1550                 delta_m = 0;
1551             } else {
1552                 /* vector */
1553                 delta_m = delta_d;
1554             }
1555         }
1556     }
1558     f0 = tcg_temp_new_i32();
1559     f1 = tcg_temp_new_i32();
1560     fd = tcg_temp_new_i32();
1561     fpst = fpstatus_ptr(FPST_FPCR);
1563     vfp_load_reg32(f0, vn);
1564     vfp_load_reg32(f1, vm);
1566     for (;;) {
1567         if (reads_vd) {
1568             vfp_load_reg32(fd, vd);
1569         }
1570         fn(fd, f0, f1, fpst);
1571         vfp_store_reg32(fd, vd);
1573         if (veclen == 0) {
1574             break;
1575         }
1577         /* Set up the operands for the next iteration */
1578         veclen--;
1579         vd = vfp_advance_sreg(vd, delta_d);
1580         vn = vfp_advance_sreg(vn, delta_d);
1581         vfp_load_reg32(f0, vn);
1582         if (delta_m) {
1583             vm = vfp_advance_sreg(vm, delta_m);
1584             vfp_load_reg32(f1, vm);
1585         }
1586     }
1588     tcg_temp_free_i32(f0);
1589     tcg_temp_free_i32(f1);
1590     tcg_temp_free_i32(fd);
1591     tcg_temp_free_ptr(fpst);
1593     return true;
1596 static bool do_vfp_3op_hp(DisasContext *s, VFPGen3OpSPFn *fn,
1597                           int vd, int vn, int vm, bool reads_vd)
1599     /*
1600      * Do a half-precision operation. Functionally this is
1601      * the same as do_vfp_3op_sp(), except:
1602      *  - it uses the FPST_FPCR_F16
1603      *  - it doesn't need the VFP vector handling (fp16 is a
1604      *    v8 feature, and in v8 VFP vectors don't exist)
1605      *  - it does the aa32_fp16_arith feature test
1606      */
1607     TCGv_i32 f0, f1, fd;
1608     TCGv_ptr fpst;
1610     if (!dc_isar_feature(aa32_fp16_arith, s)) {
1611         return false;
1612     }
1614     if (s->vec_len != 0 || s->vec_stride != 0) {
1615         return false;
1616     }
1618     if (!vfp_access_check(s)) {
1619         return true;
1620     }
1622     f0 = tcg_temp_new_i32();
1623     f1 = tcg_temp_new_i32();
1624     fd = tcg_temp_new_i32();
1625     fpst = fpstatus_ptr(FPST_FPCR_F16);
1627     vfp_load_reg32(f0, vn);
1628     vfp_load_reg32(f1, vm);
1630     if (reads_vd) {
1631         vfp_load_reg32(fd, vd);
1632     }
1633     fn(fd, f0, f1, fpst);
1634     vfp_store_reg32(fd, vd);
1636     tcg_temp_free_i32(f0);
1637     tcg_temp_free_i32(f1);
1638     tcg_temp_free_i32(fd);
1639     tcg_temp_free_ptr(fpst);
1641     return true;
1644 static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn,
1645                           int vd, int vn, int vm, bool reads_vd)
1647     uint32_t delta_m = 0;
1648     uint32_t delta_d = 0;
1649     int veclen = s->vec_len;
1650     TCGv_i64 f0, f1, fd;
1651     TCGv_ptr fpst;
1653     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
1654         return false;
1655     }
1657     /* UNDEF accesses to D16-D31 if they don't exist */
1658     if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) {
1659         return false;
1660     }
1662     if (!dc_isar_feature(aa32_fpshvec, s) &&
1663         (veclen != 0 || s->vec_stride != 0)) {
1664         return false;
1665     }
1667     if (!vfp_access_check(s)) {
1668         return true;
1669     }
1671     if (veclen > 0) {
1672         /* Figure out what type of vector operation this is.  */
1673         if (vfp_dreg_is_scalar(vd)) {
1674             /* scalar */
1675             veclen = 0;
1676         } else {
1677             delta_d = (s->vec_stride >> 1) + 1;
1679             if (vfp_dreg_is_scalar(vm)) {
1680                 /* mixed scalar/vector */
1681                 delta_m = 0;
1682             } else {
1683                 /* vector */
1684                 delta_m = delta_d;
1685             }
1686         }
1687     }
1689     f0 = tcg_temp_new_i64();
1690     f1 = tcg_temp_new_i64();
1691     fd = tcg_temp_new_i64();
1692     fpst = fpstatus_ptr(FPST_FPCR);
1694     vfp_load_reg64(f0, vn);
1695     vfp_load_reg64(f1, vm);
1697     for (;;) {
1698         if (reads_vd) {
1699             vfp_load_reg64(fd, vd);
1700         }
1701         fn(fd, f0, f1, fpst);
1702         vfp_store_reg64(fd, vd);
1704         if (veclen == 0) {
1705             break;
1706         }
1707         /* Set up the operands for the next iteration */
1708         veclen--;
1709         vd = vfp_advance_dreg(vd, delta_d);
1710         vn = vfp_advance_dreg(vn, delta_d);
1711         vfp_load_reg64(f0, vn);
1712         if (delta_m) {
1713             vm = vfp_advance_dreg(vm, delta_m);
1714             vfp_load_reg64(f1, vm);
1715         }
1716     }
1718     tcg_temp_free_i64(f0);
1719     tcg_temp_free_i64(f1);
1720     tcg_temp_free_i64(fd);
1721     tcg_temp_free_ptr(fpst);
1723     return true;
1726 static bool do_vfp_2op_sp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
1728     uint32_t delta_m = 0;
1729     uint32_t delta_d = 0;
1730     int veclen = s->vec_len;
1731     TCGv_i32 f0, fd;
1733     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1734         return false;
1735     }
1737     if (!dc_isar_feature(aa32_fpshvec, s) &&
1738         (veclen != 0 || s->vec_stride != 0)) {
1739         return false;
1740     }
1742     if (!vfp_access_check(s)) {
1743         return true;
1744     }
1746     if (veclen > 0) {
1747         /* Figure out what type of vector operation this is.  */
1748         if (vfp_sreg_is_scalar(vd)) {
1749             /* scalar */
1750             veclen = 0;
1751         } else {
1752             delta_d = s->vec_stride + 1;
1754             if (vfp_sreg_is_scalar(vm)) {
1755                 /* mixed scalar/vector */
1756                 delta_m = 0;
1757             } else {
1758                 /* vector */
1759                 delta_m = delta_d;
1760             }
1761         }
1762     }
1764     f0 = tcg_temp_new_i32();
1765     fd = tcg_temp_new_i32();
1767     vfp_load_reg32(f0, vm);
1769     for (;;) {
1770         fn(fd, f0);
1771         vfp_store_reg32(fd, vd);
1773         if (veclen == 0) {
1774             break;
1775         }
1777         if (delta_m == 0) {
1778             /* single source one-many */
1779             while (veclen--) {
1780                 vd = vfp_advance_sreg(vd, delta_d);
1781                 vfp_store_reg32(fd, vd);
1782             }
1783             break;
1784         }
1786         /* Set up the operands for the next iteration */
1787         veclen--;
1788         vd = vfp_advance_sreg(vd, delta_d);
1789         vm = vfp_advance_sreg(vm, delta_m);
1790         vfp_load_reg32(f0, vm);
1791     }
1793     tcg_temp_free_i32(f0);
1794     tcg_temp_free_i32(fd);
1796     return true;
1799 static bool do_vfp_2op_hp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
1801     /*
1802      * Do a half-precision operation. Functionally this is
1803      * the same as do_vfp_2op_sp(), except:
1804      *  - it doesn't need the VFP vector handling (fp16 is a
1805      *    v8 feature, and in v8 VFP vectors don't exist)
1806      *  - it does the aa32_fp16_arith feature test
1807      */
1808     TCGv_i32 f0;
1810     if (!dc_isar_feature(aa32_fp16_arith, s)) {
1811         return false;
1812     }
1814     if (s->vec_len != 0 || s->vec_stride != 0) {
1815         return false;
1816     }
1818     if (!vfp_access_check(s)) {
1819         return true;
1820     }
1822     f0 = tcg_temp_new_i32();
1823     vfp_load_reg32(f0, vm);
1824     fn(f0, f0);
1825     vfp_store_reg32(f0, vd);
1826     tcg_temp_free_i32(f0);
1828     return true;
1831 static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm)
1833     uint32_t delta_m = 0;
1834     uint32_t delta_d = 0;
1835     int veclen = s->vec_len;
1836     TCGv_i64 f0, fd;
1838     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
1839         return false;
1840     }
1842     /* UNDEF accesses to D16-D31 if they don't exist */
1843     if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) {
1844         return false;
1845     }
1847     if (!dc_isar_feature(aa32_fpshvec, s) &&
1848         (veclen != 0 || s->vec_stride != 0)) {
1849         return false;
1850     }
1852     if (!vfp_access_check(s)) {
1853         return true;
1854     }
1856     if (veclen > 0) {
1857         /* Figure out what type of vector operation this is.  */
1858         if (vfp_dreg_is_scalar(vd)) {
1859             /* scalar */
1860             veclen = 0;
1861         } else {
1862             delta_d = (s->vec_stride >> 1) + 1;
1864             if (vfp_dreg_is_scalar(vm)) {
1865                 /* mixed scalar/vector */
1866                 delta_m = 0;
1867             } else {
1868                 /* vector */
1869                 delta_m = delta_d;
1870             }
1871         }
1872     }
1874     f0 = tcg_temp_new_i64();
1875     fd = tcg_temp_new_i64();
1877     vfp_load_reg64(f0, vm);
1879     for (;;) {
1880         fn(fd, f0);
1881         vfp_store_reg64(fd, vd);
1883         if (veclen == 0) {
1884             break;
1885         }
1887         if (delta_m == 0) {
1888             /* single source one-many */
1889             while (veclen--) {
1890                 vd = vfp_advance_dreg(vd, delta_d);
1891                 vfp_store_reg64(fd, vd);
1892             }
1893             break;
1894         }
1896         /* Set up the operands for the next iteration */
1897         veclen--;
1898         vd = vfp_advance_dreg(vd, delta_d);
1899         vd = vfp_advance_dreg(vm, delta_m);
1900         vfp_load_reg64(f0, vm);
1901     }
1903     tcg_temp_free_i64(f0);
1904     tcg_temp_free_i64(fd);
1906     return true;
1909 static void gen_VMLA_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1911     /* Note that order of inputs to the add matters for NaNs */
1912     TCGv_i32 tmp = tcg_temp_new_i32();
1914     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1915     gen_helper_vfp_addh(vd, vd, tmp, fpst);
1916     tcg_temp_free_i32(tmp);
1919 static bool trans_VMLA_hp(DisasContext *s, arg_VMLA_sp *a)
1921     return do_vfp_3op_hp(s, gen_VMLA_hp, a->vd, a->vn, a->vm, true);
1924 static void gen_VMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1926     /* Note that order of inputs to the add matters for NaNs */
1927     TCGv_i32 tmp = tcg_temp_new_i32();
1929     gen_helper_vfp_muls(tmp, vn, vm, fpst);
1930     gen_helper_vfp_adds(vd, vd, tmp, fpst);
1931     tcg_temp_free_i32(tmp);
1934 static bool trans_VMLA_sp(DisasContext *s, arg_VMLA_sp *a)
1936     return do_vfp_3op_sp(s, gen_VMLA_sp, a->vd, a->vn, a->vm, true);
1939 static void gen_VMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1941     /* Note that order of inputs to the add matters for NaNs */
1942     TCGv_i64 tmp = tcg_temp_new_i64();
1944     gen_helper_vfp_muld(tmp, vn, vm, fpst);
1945     gen_helper_vfp_addd(vd, vd, tmp, fpst);
1946     tcg_temp_free_i64(tmp);
1949 static bool trans_VMLA_dp(DisasContext *s, arg_VMLA_dp *a)
1951     return do_vfp_3op_dp(s, gen_VMLA_dp, a->vd, a->vn, a->vm, true);
1954 static void gen_VMLS_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1956     /*
1957      * VMLS: vd = vd + -(vn * vm)
1958      * Note that order of inputs to the add matters for NaNs.
1959      */
1960     TCGv_i32 tmp = tcg_temp_new_i32();
1962     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1963     gen_helper_vfp_negh(tmp, tmp);
1964     gen_helper_vfp_addh(vd, vd, tmp, fpst);
1965     tcg_temp_free_i32(tmp);
1968 static bool trans_VMLS_hp(DisasContext *s, arg_VMLS_sp *a)
1970     return do_vfp_3op_hp(s, gen_VMLS_hp, a->vd, a->vn, a->vm, true);
1973 static void gen_VMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1975     /*
1976      * VMLS: vd = vd + -(vn * vm)
1977      * Note that order of inputs to the add matters for NaNs.
1978      */
1979     TCGv_i32 tmp = tcg_temp_new_i32();
1981     gen_helper_vfp_muls(tmp, vn, vm, fpst);
1982     gen_helper_vfp_negs(tmp, tmp);
1983     gen_helper_vfp_adds(vd, vd, tmp, fpst);
1984     tcg_temp_free_i32(tmp);
1987 static bool trans_VMLS_sp(DisasContext *s, arg_VMLS_sp *a)
1989     return do_vfp_3op_sp(s, gen_VMLS_sp, a->vd, a->vn, a->vm, true);
1992 static void gen_VMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1994     /*
1995      * VMLS: vd = vd + -(vn * vm)
1996      * Note that order of inputs to the add matters for NaNs.
1997      */
1998     TCGv_i64 tmp = tcg_temp_new_i64();
2000     gen_helper_vfp_muld(tmp, vn, vm, fpst);
2001     gen_helper_vfp_negd(tmp, tmp);
2002     gen_helper_vfp_addd(vd, vd, tmp, fpst);
2003     tcg_temp_free_i64(tmp);
2006 static bool trans_VMLS_dp(DisasContext *s, arg_VMLS_dp *a)
2008     return do_vfp_3op_dp(s, gen_VMLS_dp, a->vd, a->vn, a->vm, true);
2011 static void gen_VNMLS_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
2013     /*
2014      * VNMLS: -fd + (fn * fm)
2015      * Note that it isn't valid to replace (-A + B) with (B - A) or similar
2016      * plausible looking simplifications because this will give wrong results
2017      * for NaNs.
2018      */
2019     TCGv_i32 tmp = tcg_temp_new_i32();
2021     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
2022     gen_helper_vfp_negh(vd, vd);
2023     gen_helper_vfp_addh(vd, vd, tmp, fpst);
2024     tcg_temp_free_i32(tmp);
2027 static bool trans_VNMLS_hp(DisasContext *s, arg_VNMLS_sp *a)
2029     return do_vfp_3op_hp(s, gen_VNMLS_hp, a->vd, a->vn, a->vm, true);
2032 static void gen_VNMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
2034     /*
2035      * VNMLS: -fd + (fn * fm)
2036      * Note that it isn't valid to replace (-A + B) with (B - A) or similar
2037      * plausible looking simplifications because this will give wrong results
2038      * for NaNs.
2039      */
2040     TCGv_i32 tmp = tcg_temp_new_i32();
2042     gen_helper_vfp_muls(tmp, vn, vm, fpst);
2043     gen_helper_vfp_negs(vd, vd);
2044     gen_helper_vfp_adds(vd, vd, tmp, fpst);
2045     tcg_temp_free_i32(tmp);
2048 static bool trans_VNMLS_sp(DisasContext *s, arg_VNMLS_sp *a)
2050     return do_vfp_3op_sp(s, gen_VNMLS_sp, a->vd, a->vn, a->vm, true);
2053 static void gen_VNMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
2055     /*
2056      * VNMLS: -fd + (fn * fm)
2057      * Note that it isn't valid to replace (-A + B) with (B - A) or similar
2058      * plausible looking simplifications because this will give wrong results
2059      * for NaNs.
2060      */
2061     TCGv_i64 tmp = tcg_temp_new_i64();
2063     gen_helper_vfp_muld(tmp, vn, vm, fpst);
2064     gen_helper_vfp_negd(vd, vd);
2065     gen_helper_vfp_addd(vd, vd, tmp, fpst);
2066     tcg_temp_free_i64(tmp);
2069 static bool trans_VNMLS_dp(DisasContext *s, arg_VNMLS_dp *a)
2071     return do_vfp_3op_dp(s, gen_VNMLS_dp, a->vd, a->vn, a->vm, true);
2074 static void gen_VNMLA_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
2076     /* VNMLA: -fd + -(fn * fm) */
2077     TCGv_i32 tmp = tcg_temp_new_i32();
2079     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
2080     gen_helper_vfp_negh(tmp, tmp);
2081     gen_helper_vfp_negh(vd, vd);
2082     gen_helper_vfp_addh(vd, vd, tmp, fpst);
2083     tcg_temp_free_i32(tmp);
2086 static bool trans_VNMLA_hp(DisasContext *s, arg_VNMLA_sp *a)
2088     return do_vfp_3op_hp(s, gen_VNMLA_hp, a->vd, a->vn, a->vm, true);
2091 static void gen_VNMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
2093     /* VNMLA: -fd + -(fn * fm) */
2094     TCGv_i32 tmp = tcg_temp_new_i32();
2096     gen_helper_vfp_muls(tmp, vn, vm, fpst);
2097     gen_helper_vfp_negs(tmp, tmp);
2098     gen_helper_vfp_negs(vd, vd);
2099     gen_helper_vfp_adds(vd, vd, tmp, fpst);
2100     tcg_temp_free_i32(tmp);
2103 static bool trans_VNMLA_sp(DisasContext *s, arg_VNMLA_sp *a)
2105     return do_vfp_3op_sp(s, gen_VNMLA_sp, a->vd, a->vn, a->vm, true);
2108 static void gen_VNMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
2110     /* VNMLA: -fd + (fn * fm) */
2111     TCGv_i64 tmp = tcg_temp_new_i64();
2113     gen_helper_vfp_muld(tmp, vn, vm, fpst);
2114     gen_helper_vfp_negd(tmp, tmp);
2115     gen_helper_vfp_negd(vd, vd);
2116     gen_helper_vfp_addd(vd, vd, tmp, fpst);
2117     tcg_temp_free_i64(tmp);
2120 static bool trans_VNMLA_dp(DisasContext *s, arg_VNMLA_dp *a)
2122     return do_vfp_3op_dp(s, gen_VNMLA_dp, a->vd, a->vn, a->vm, true);
2125 static bool trans_VMUL_hp(DisasContext *s, arg_VMUL_sp *a)
2127     return do_vfp_3op_hp(s, gen_helper_vfp_mulh, a->vd, a->vn, a->vm, false);
2130 static bool trans_VMUL_sp(DisasContext *s, arg_VMUL_sp *a)
2132     return do_vfp_3op_sp(s, gen_helper_vfp_muls, a->vd, a->vn, a->vm, false);
2135 static bool trans_VMUL_dp(DisasContext *s, arg_VMUL_dp *a)
2137     return do_vfp_3op_dp(s, gen_helper_vfp_muld, a->vd, a->vn, a->vm, false);
2140 static void gen_VNMUL_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
2142     /* VNMUL: -(fn * fm) */
2143     gen_helper_vfp_mulh(vd, vn, vm, fpst);
2144     gen_helper_vfp_negh(vd, vd);
2147 static bool trans_VNMUL_hp(DisasContext *s, arg_VNMUL_sp *a)
2149     return do_vfp_3op_hp(s, gen_VNMUL_hp, a->vd, a->vn, a->vm, false);
2152 static void gen_VNMUL_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
2154     /* VNMUL: -(fn * fm) */
2155     gen_helper_vfp_muls(vd, vn, vm, fpst);
2156     gen_helper_vfp_negs(vd, vd);
2159 static bool trans_VNMUL_sp(DisasContext *s, arg_VNMUL_sp *a)
2161     return do_vfp_3op_sp(s, gen_VNMUL_sp, a->vd, a->vn, a->vm, false);
2164 static void gen_VNMUL_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
2166     /* VNMUL: -(fn * fm) */
2167     gen_helper_vfp_muld(vd, vn, vm, fpst);
2168     gen_helper_vfp_negd(vd, vd);
2171 static bool trans_VNMUL_dp(DisasContext *s, arg_VNMUL_dp *a)
2173     return do_vfp_3op_dp(s, gen_VNMUL_dp, a->vd, a->vn, a->vm, false);
2176 static bool trans_VADD_hp(DisasContext *s, arg_VADD_sp *a)
2178     return do_vfp_3op_hp(s, gen_helper_vfp_addh, a->vd, a->vn, a->vm, false);
2181 static bool trans_VADD_sp(DisasContext *s, arg_VADD_sp *a)
2183     return do_vfp_3op_sp(s, gen_helper_vfp_adds, a->vd, a->vn, a->vm, false);
2186 static bool trans_VADD_dp(DisasContext *s, arg_VADD_dp *a)
2188     return do_vfp_3op_dp(s, gen_helper_vfp_addd, a->vd, a->vn, a->vm, false);
2191 static bool trans_VSUB_hp(DisasContext *s, arg_VSUB_sp *a)
2193     return do_vfp_3op_hp(s, gen_helper_vfp_subh, a->vd, a->vn, a->vm, false);
2196 static bool trans_VSUB_sp(DisasContext *s, arg_VSUB_sp *a)
2198     return do_vfp_3op_sp(s, gen_helper_vfp_subs, a->vd, a->vn, a->vm, false);
2201 static bool trans_VSUB_dp(DisasContext *s, arg_VSUB_dp *a)
2203     return do_vfp_3op_dp(s, gen_helper_vfp_subd, a->vd, a->vn, a->vm, false);
2206 static bool trans_VDIV_hp(DisasContext *s, arg_VDIV_sp *a)
2208     return do_vfp_3op_hp(s, gen_helper_vfp_divh, a->vd, a->vn, a->vm, false);
2211 static bool trans_VDIV_sp(DisasContext *s, arg_VDIV_sp *a)
2213     return do_vfp_3op_sp(s, gen_helper_vfp_divs, a->vd, a->vn, a->vm, false);
2216 static bool trans_VDIV_dp(DisasContext *s, arg_VDIV_dp *a)
2218     return do_vfp_3op_dp(s, gen_helper_vfp_divd, a->vd, a->vn, a->vm, false);
2221 static bool trans_VMINNM_hp(DisasContext *s, arg_VMINNM_sp *a)
2223     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
2224         return false;
2225     }
2226     return do_vfp_3op_hp(s, gen_helper_vfp_minnumh,
2227                          a->vd, a->vn, a->vm, false);
2230 static bool trans_VMAXNM_hp(DisasContext *s, arg_VMAXNM_sp *a)
2232     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
2233         return false;
2234     }
2235     return do_vfp_3op_hp(s, gen_helper_vfp_maxnumh,
2236                          a->vd, a->vn, a->vm, false);
2239 static bool trans_VMINNM_sp(DisasContext *s, arg_VMINNM_sp *a)
2241     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
2242         return false;
2243     }
2244     return do_vfp_3op_sp(s, gen_helper_vfp_minnums,
2245                          a->vd, a->vn, a->vm, false);
2248 static bool trans_VMAXNM_sp(DisasContext *s, arg_VMAXNM_sp *a)
2250     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
2251         return false;
2252     }
2253     return do_vfp_3op_sp(s, gen_helper_vfp_maxnums,
2254                          a->vd, a->vn, a->vm, false);
2257 static bool trans_VMINNM_dp(DisasContext *s, arg_VMINNM_dp *a)
2259     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
2260         return false;
2261     }
2262     return do_vfp_3op_dp(s, gen_helper_vfp_minnumd,
2263                          a->vd, a->vn, a->vm, false);
2266 static bool trans_VMAXNM_dp(DisasContext *s, arg_VMAXNM_dp *a)
2268     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
2269         return false;
2270     }
2271     return do_vfp_3op_dp(s, gen_helper_vfp_maxnumd,
2272                          a->vd, a->vn, a->vm, false);
2275 static bool do_vfm_hp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
2277     /*
2278      * VFNMA : fd = muladd(-fd,  fn, fm)
2279      * VFNMS : fd = muladd(-fd, -fn, fm)
2280      * VFMA  : fd = muladd( fd,  fn, fm)
2281      * VFMS  : fd = muladd( fd, -fn, fm)
2282      *
2283      * These are fused multiply-add, and must be done as one floating
2284      * point operation with no rounding between the multiplication and
2285      * addition steps.  NB that doing the negations here as separate
2286      * steps is correct : an input NaN should come out with its sign
2287      * bit flipped if it is a negated-input.
2288      */
2289     TCGv_ptr fpst;
2290     TCGv_i32 vn, vm, vd;
2292     /*
2293      * Present in VFPv4 only, and only with the FP16 extension.
2294      * Note that we can't rely on the SIMDFMAC check alone, because
2295      * in a Neon-no-VFP core that ID register field will be non-zero.
2296      */
2297     if (!dc_isar_feature(aa32_fp16_arith, s) ||
2298         !dc_isar_feature(aa32_simdfmac, s) ||
2299         !dc_isar_feature(aa32_fpsp_v2, s)) {
2300         return false;
2301     }
2303     if (s->vec_len != 0 || s->vec_stride != 0) {
2304         return false;
2305     }
2307     if (!vfp_access_check(s)) {
2308         return true;
2309     }
2311     vn = tcg_temp_new_i32();
2312     vm = tcg_temp_new_i32();
2313     vd = tcg_temp_new_i32();
2315     vfp_load_reg32(vn, a->vn);
2316     vfp_load_reg32(vm, a->vm);
2317     if (neg_n) {
2318         /* VFNMS, VFMS */
2319         gen_helper_vfp_negh(vn, vn);
2320     }
2321     vfp_load_reg32(vd, a->vd);
2322     if (neg_d) {
2323         /* VFNMA, VFNMS */
2324         gen_helper_vfp_negh(vd, vd);
2325     }
2326     fpst = fpstatus_ptr(FPST_FPCR_F16);
2327     gen_helper_vfp_muladdh(vd, vn, vm, vd, fpst);
2328     vfp_store_reg32(vd, a->vd);
2330     tcg_temp_free_ptr(fpst);
2331     tcg_temp_free_i32(vn);
2332     tcg_temp_free_i32(vm);
2333     tcg_temp_free_i32(vd);
2335     return true;
2338 static bool do_vfm_sp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
2340     /*
2341      * VFNMA : fd = muladd(-fd,  fn, fm)
2342      * VFNMS : fd = muladd(-fd, -fn, fm)
2343      * VFMA  : fd = muladd( fd,  fn, fm)
2344      * VFMS  : fd = muladd( fd, -fn, fm)
2345      *
2346      * These are fused multiply-add, and must be done as one floating
2347      * point operation with no rounding between the multiplication and
2348      * addition steps.  NB that doing the negations here as separate
2349      * steps is correct : an input NaN should come out with its sign
2350      * bit flipped if it is a negated-input.
2351      */
2352     TCGv_ptr fpst;
2353     TCGv_i32 vn, vm, vd;
2355     /*
2356      * Present in VFPv4 only.
2357      * Note that we can't rely on the SIMDFMAC check alone, because
2358      * in a Neon-no-VFP core that ID register field will be non-zero.
2359      */
2360     if (!dc_isar_feature(aa32_simdfmac, s) ||
2361         !dc_isar_feature(aa32_fpsp_v2, s)) {
2362         return false;
2363     }
2364     /*
2365      * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
2366      * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
2367      */
2368     if (s->vec_len != 0 || s->vec_stride != 0) {
2369         return false;
2370     }
2372     if (!vfp_access_check(s)) {
2373         return true;
2374     }
2376     vn = tcg_temp_new_i32();
2377     vm = tcg_temp_new_i32();
2378     vd = tcg_temp_new_i32();
2380     vfp_load_reg32(vn, a->vn);
2381     vfp_load_reg32(vm, a->vm);
2382     if (neg_n) {
2383         /* VFNMS, VFMS */
2384         gen_helper_vfp_negs(vn, vn);
2385     }
2386     vfp_load_reg32(vd, a->vd);
2387     if (neg_d) {
2388         /* VFNMA, VFNMS */
2389         gen_helper_vfp_negs(vd, vd);
2390     }
2391     fpst = fpstatus_ptr(FPST_FPCR);
2392     gen_helper_vfp_muladds(vd, vn, vm, vd, fpst);
2393     vfp_store_reg32(vd, a->vd);
2395     tcg_temp_free_ptr(fpst);
2396     tcg_temp_free_i32(vn);
2397     tcg_temp_free_i32(vm);
2398     tcg_temp_free_i32(vd);
2400     return true;
2403 static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d)
2405     /*
2406      * VFNMA : fd = muladd(-fd,  fn, fm)
2407      * VFNMS : fd = muladd(-fd, -fn, fm)
2408      * VFMA  : fd = muladd( fd,  fn, fm)
2409      * VFMS  : fd = muladd( fd, -fn, fm)
2410      *
2411      * These are fused multiply-add, and must be done as one floating
2412      * point operation with no rounding between the multiplication and
2413      * addition steps.  NB that doing the negations here as separate
2414      * steps is correct : an input NaN should come out with its sign
2415      * bit flipped if it is a negated-input.
2416      */
2417     TCGv_ptr fpst;
2418     TCGv_i64 vn, vm, vd;
2420     /*
2421      * Present in VFPv4 only.
2422      * Note that we can't rely on the SIMDFMAC check alone, because
2423      * in a Neon-no-VFP core that ID register field will be non-zero.
2424      */
2425     if (!dc_isar_feature(aa32_simdfmac, s) ||
2426         !dc_isar_feature(aa32_fpdp_v2, s)) {
2427         return false;
2428     }
2429     /*
2430      * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
2431      * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
2432      */
2433     if (s->vec_len != 0 || s->vec_stride != 0) {
2434         return false;
2435     }
2437     /* UNDEF accesses to D16-D31 if they don't exist. */
2438     if (!dc_isar_feature(aa32_simd_r32, s) &&
2439         ((a->vd | a->vn | a->vm) & 0x10)) {
2440         return false;
2441     }
2443     if (!vfp_access_check(s)) {
2444         return true;
2445     }
2447     vn = tcg_temp_new_i64();
2448     vm = tcg_temp_new_i64();
2449     vd = tcg_temp_new_i64();
2451     vfp_load_reg64(vn, a->vn);
2452     vfp_load_reg64(vm, a->vm);
2453     if (neg_n) {
2454         /* VFNMS, VFMS */
2455         gen_helper_vfp_negd(vn, vn);
2456     }
2457     vfp_load_reg64(vd, a->vd);
2458     if (neg_d) {
2459         /* VFNMA, VFNMS */
2460         gen_helper_vfp_negd(vd, vd);
2461     }
2462     fpst = fpstatus_ptr(FPST_FPCR);
2463     gen_helper_vfp_muladdd(vd, vn, vm, vd, fpst);
2464     vfp_store_reg64(vd, a->vd);
2466     tcg_temp_free_ptr(fpst);
2467     tcg_temp_free_i64(vn);
2468     tcg_temp_free_i64(vm);
2469     tcg_temp_free_i64(vd);
2471     return true;
2474 #define MAKE_ONE_VFM_TRANS_FN(INSN, PREC, NEGN, NEGD)                   \
2475     static bool trans_##INSN##_##PREC(DisasContext *s,                  \
2476                                       arg_##INSN##_##PREC *a)           \
2477     {                                                                   \
2478         return do_vfm_##PREC(s, a, NEGN, NEGD);                         \
2479     }
2481 #define MAKE_VFM_TRANS_FNS(PREC) \
2482     MAKE_ONE_VFM_TRANS_FN(VFMA, PREC, false, false) \
2483     MAKE_ONE_VFM_TRANS_FN(VFMS, PREC, true, false) \
2484     MAKE_ONE_VFM_TRANS_FN(VFNMA, PREC, false, true) \
2485     MAKE_ONE_VFM_TRANS_FN(VFNMS, PREC, true, true)
2487 MAKE_VFM_TRANS_FNS(hp)
2488 MAKE_VFM_TRANS_FNS(sp)
2489 MAKE_VFM_TRANS_FNS(dp)
2491 static bool trans_VMOV_imm_hp(DisasContext *s, arg_VMOV_imm_sp *a)
2493     TCGv_i32 fd;
2495     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2496         return false;
2497     }
2499     if (s->vec_len != 0 || s->vec_stride != 0) {
2500         return false;
2501     }
2503     if (!vfp_access_check(s)) {
2504         return true;
2505     }
2507     fd = tcg_const_i32(vfp_expand_imm(MO_16, a->imm));
2508     vfp_store_reg32(fd, a->vd);
2509     tcg_temp_free_i32(fd);
2510     return true;
2513 static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
2515     uint32_t delta_d = 0;
2516     int veclen = s->vec_len;
2517     TCGv_i32 fd;
2518     uint32_t vd;
2520     vd = a->vd;
2522     if (!dc_isar_feature(aa32_fpsp_v3, s)) {
2523         return false;
2524     }
2526     if (!dc_isar_feature(aa32_fpshvec, s) &&
2527         (veclen != 0 || s->vec_stride != 0)) {
2528         return false;
2529     }
2531     if (!vfp_access_check(s)) {
2532         return true;
2533     }
2535     if (veclen > 0) {
2536         /* Figure out what type of vector operation this is.  */
2537         if (vfp_sreg_is_scalar(vd)) {
2538             /* scalar */
2539             veclen = 0;
2540         } else {
2541             delta_d = s->vec_stride + 1;
2542         }
2543     }
2545     fd = tcg_const_i32(vfp_expand_imm(MO_32, a->imm));
2547     for (;;) {
2548         vfp_store_reg32(fd, vd);
2550         if (veclen == 0) {
2551             break;
2552         }
2554         /* Set up the operands for the next iteration */
2555         veclen--;
2556         vd = vfp_advance_sreg(vd, delta_d);
2557     }
2559     tcg_temp_free_i32(fd);
2560     return true;
2563 static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
2565     uint32_t delta_d = 0;
2566     int veclen = s->vec_len;
2567     TCGv_i64 fd;
2568     uint32_t vd;
2570     vd = a->vd;
2572     if (!dc_isar_feature(aa32_fpdp_v3, s)) {
2573         return false;
2574     }
2576     /* UNDEF accesses to D16-D31 if they don't exist. */
2577     if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) {
2578         return false;
2579     }
2581     if (!dc_isar_feature(aa32_fpshvec, s) &&
2582         (veclen != 0 || s->vec_stride != 0)) {
2583         return false;
2584     }
2586     if (!vfp_access_check(s)) {
2587         return true;
2588     }
2590     if (veclen > 0) {
2591         /* Figure out what type of vector operation this is.  */
2592         if (vfp_dreg_is_scalar(vd)) {
2593             /* scalar */
2594             veclen = 0;
2595         } else {
2596             delta_d = (s->vec_stride >> 1) + 1;
2597         }
2598     }
2600     fd = tcg_const_i64(vfp_expand_imm(MO_64, a->imm));
2602     for (;;) {
2603         vfp_store_reg64(fd, vd);
2605         if (veclen == 0) {
2606             break;
2607         }
2609         /* Set up the operands for the next iteration */
2610         veclen--;
2611         vd = vfp_advance_dreg(vd, delta_d);
2612     }
2614     tcg_temp_free_i64(fd);
2615     return true;
2618 #define DO_VFP_2OP(INSN, PREC, FN)                              \
2619     static bool trans_##INSN##_##PREC(DisasContext *s,          \
2620                                       arg_##INSN##_##PREC *a)   \
2621     {                                                           \
2622         return do_vfp_2op_##PREC(s, FN, a->vd, a->vm);          \
2623     }
2625 DO_VFP_2OP(VMOV_reg, sp, tcg_gen_mov_i32)
2626 DO_VFP_2OP(VMOV_reg, dp, tcg_gen_mov_i64)
2628 DO_VFP_2OP(VABS, hp, gen_helper_vfp_absh)
2629 DO_VFP_2OP(VABS, sp, gen_helper_vfp_abss)
2630 DO_VFP_2OP(VABS, dp, gen_helper_vfp_absd)
2632 DO_VFP_2OP(VNEG, hp, gen_helper_vfp_negh)
2633 DO_VFP_2OP(VNEG, sp, gen_helper_vfp_negs)
2634 DO_VFP_2OP(VNEG, dp, gen_helper_vfp_negd)
2636 static void gen_VSQRT_hp(TCGv_i32 vd, TCGv_i32 vm)
2638     gen_helper_vfp_sqrth(vd, vm, cpu_env);
2641 static void gen_VSQRT_sp(TCGv_i32 vd, TCGv_i32 vm)
2643     gen_helper_vfp_sqrts(vd, vm, cpu_env);
2646 static void gen_VSQRT_dp(TCGv_i64 vd, TCGv_i64 vm)
2648     gen_helper_vfp_sqrtd(vd, vm, cpu_env);
2651 DO_VFP_2OP(VSQRT, hp, gen_VSQRT_hp)
2652 DO_VFP_2OP(VSQRT, sp, gen_VSQRT_sp)
2653 DO_VFP_2OP(VSQRT, dp, gen_VSQRT_dp)
2655 static bool trans_VCMP_hp(DisasContext *s, arg_VCMP_sp *a)
2657     TCGv_i32 vd, vm;
2659     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2660         return false;
2661     }
2663     /* Vm/M bits must be zero for the Z variant */
2664     if (a->z && a->vm != 0) {
2665         return false;
2666     }
2668     if (!vfp_access_check(s)) {
2669         return true;
2670     }
2672     vd = tcg_temp_new_i32();
2673     vm = tcg_temp_new_i32();
2675     vfp_load_reg32(vd, a->vd);
2676     if (a->z) {
2677         tcg_gen_movi_i32(vm, 0);
2678     } else {
2679         vfp_load_reg32(vm, a->vm);
2680     }
2682     if (a->e) {
2683         gen_helper_vfp_cmpeh(vd, vm, cpu_env);
2684     } else {
2685         gen_helper_vfp_cmph(vd, vm, cpu_env);
2686     }
2688     tcg_temp_free_i32(vd);
2689     tcg_temp_free_i32(vm);
2691     return true;
2694 static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a)
2696     TCGv_i32 vd, vm;
2698     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2699         return false;
2700     }
2702     /* Vm/M bits must be zero for the Z variant */
2703     if (a->z && a->vm != 0) {
2704         return false;
2705     }
2707     if (!vfp_access_check(s)) {
2708         return true;
2709     }
2711     vd = tcg_temp_new_i32();
2712     vm = tcg_temp_new_i32();
2714     vfp_load_reg32(vd, a->vd);
2715     if (a->z) {
2716         tcg_gen_movi_i32(vm, 0);
2717     } else {
2718         vfp_load_reg32(vm, a->vm);
2719     }
2721     if (a->e) {
2722         gen_helper_vfp_cmpes(vd, vm, cpu_env);
2723     } else {
2724         gen_helper_vfp_cmps(vd, vm, cpu_env);
2725     }
2727     tcg_temp_free_i32(vd);
2728     tcg_temp_free_i32(vm);
2730     return true;
2733 static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a)
2735     TCGv_i64 vd, vm;
2737     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2738         return false;
2739     }
2741     /* Vm/M bits must be zero for the Z variant */
2742     if (a->z && a->vm != 0) {
2743         return false;
2744     }
2746     /* UNDEF accesses to D16-D31 if they don't exist. */
2747     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
2748         return false;
2749     }
2751     if (!vfp_access_check(s)) {
2752         return true;
2753     }
2755     vd = tcg_temp_new_i64();
2756     vm = tcg_temp_new_i64();
2758     vfp_load_reg64(vd, a->vd);
2759     if (a->z) {
2760         tcg_gen_movi_i64(vm, 0);
2761     } else {
2762         vfp_load_reg64(vm, a->vm);
2763     }
2765     if (a->e) {
2766         gen_helper_vfp_cmped(vd, vm, cpu_env);
2767     } else {
2768         gen_helper_vfp_cmpd(vd, vm, cpu_env);
2769     }
2771     tcg_temp_free_i64(vd);
2772     tcg_temp_free_i64(vm);
2774     return true;
2777 static bool trans_VCVT_f32_f16(DisasContext *s, arg_VCVT_f32_f16 *a)
2779     TCGv_ptr fpst;
2780     TCGv_i32 ahp_mode;
2781     TCGv_i32 tmp;
2783     if (!dc_isar_feature(aa32_fp16_spconv, s)) {
2784         return false;
2785     }
2787     if (!vfp_access_check(s)) {
2788         return true;
2789     }
2791     fpst = fpstatus_ptr(FPST_FPCR);
2792     ahp_mode = get_ahp_flag();
2793     tmp = tcg_temp_new_i32();
2794     /* The T bit tells us if we want the low or high 16 bits of Vm */
2795     tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t));
2796     gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp_mode);
2797     vfp_store_reg32(tmp, a->vd);
2798     tcg_temp_free_i32(ahp_mode);
2799     tcg_temp_free_ptr(fpst);
2800     tcg_temp_free_i32(tmp);
2801     return true;
2804 static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a)
2806     TCGv_ptr fpst;
2807     TCGv_i32 ahp_mode;
2808     TCGv_i32 tmp;
2809     TCGv_i64 vd;
2811     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2812         return false;
2813     }
2815     if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
2816         return false;
2817     }
2819     /* UNDEF accesses to D16-D31 if they don't exist. */
2820     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd  & 0x10)) {
2821         return false;
2822     }
2824     if (!vfp_access_check(s)) {
2825         return true;
2826     }
2828     fpst = fpstatus_ptr(FPST_FPCR);
2829     ahp_mode = get_ahp_flag();
2830     tmp = tcg_temp_new_i32();
2831     /* The T bit tells us if we want the low or high 16 bits of Vm */
2832     tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t));
2833     vd = tcg_temp_new_i64();
2834     gen_helper_vfp_fcvt_f16_to_f64(vd, tmp, fpst, ahp_mode);
2835     vfp_store_reg64(vd, a->vd);
2836     tcg_temp_free_i32(ahp_mode);
2837     tcg_temp_free_ptr(fpst);
2838     tcg_temp_free_i32(tmp);
2839     tcg_temp_free_i64(vd);
2840     return true;
2843 static bool trans_VCVT_f16_f32(DisasContext *s, arg_VCVT_f16_f32 *a)
2845     TCGv_ptr fpst;
2846     TCGv_i32 ahp_mode;
2847     TCGv_i32 tmp;
2849     if (!dc_isar_feature(aa32_fp16_spconv, s)) {
2850         return false;
2851     }
2853     if (!vfp_access_check(s)) {
2854         return true;
2855     }
2857     fpst = fpstatus_ptr(FPST_FPCR);
2858     ahp_mode = get_ahp_flag();
2859     tmp = tcg_temp_new_i32();
2861     vfp_load_reg32(tmp, a->vm);
2862     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp_mode);
2863     tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t));
2864     tcg_temp_free_i32(ahp_mode);
2865     tcg_temp_free_ptr(fpst);
2866     tcg_temp_free_i32(tmp);
2867     return true;
2870 static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a)
2872     TCGv_ptr fpst;
2873     TCGv_i32 ahp_mode;
2874     TCGv_i32 tmp;
2875     TCGv_i64 vm;
2877     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2878         return false;
2879     }
2881     if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
2882         return false;
2883     }
2885     /* UNDEF accesses to D16-D31 if they don't exist. */
2886     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm  & 0x10)) {
2887         return false;
2888     }
2890     if (!vfp_access_check(s)) {
2891         return true;
2892     }
2894     fpst = fpstatus_ptr(FPST_FPCR);
2895     ahp_mode = get_ahp_flag();
2896     tmp = tcg_temp_new_i32();
2897     vm = tcg_temp_new_i64();
2899     vfp_load_reg64(vm, a->vm);
2900     gen_helper_vfp_fcvt_f64_to_f16(tmp, vm, fpst, ahp_mode);
2901     tcg_temp_free_i64(vm);
2902     tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t));
2903     tcg_temp_free_i32(ahp_mode);
2904     tcg_temp_free_ptr(fpst);
2905     tcg_temp_free_i32(tmp);
2906     return true;
2909 static bool trans_VRINTR_hp(DisasContext *s, arg_VRINTR_sp *a)
2911     TCGv_ptr fpst;
2912     TCGv_i32 tmp;
2914     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2915         return false;
2916     }
2918     if (!vfp_access_check(s)) {
2919         return true;
2920     }
2922     tmp = tcg_temp_new_i32();
2923     vfp_load_reg32(tmp, a->vm);
2924     fpst = fpstatus_ptr(FPST_FPCR_F16);
2925     gen_helper_rinth(tmp, tmp, fpst);
2926     vfp_store_reg32(tmp, a->vd);
2927     tcg_temp_free_ptr(fpst);
2928     tcg_temp_free_i32(tmp);
2929     return true;
2932 static bool trans_VRINTR_sp(DisasContext *s, arg_VRINTR_sp *a)
2934     TCGv_ptr fpst;
2935     TCGv_i32 tmp;
2937     if (!dc_isar_feature(aa32_vrint, s)) {
2938         return false;
2939     }
2941     if (!vfp_access_check(s)) {
2942         return true;
2943     }
2945     tmp = tcg_temp_new_i32();
2946     vfp_load_reg32(tmp, a->vm);
2947     fpst = fpstatus_ptr(FPST_FPCR);
2948     gen_helper_rints(tmp, tmp, fpst);
2949     vfp_store_reg32(tmp, a->vd);
2950     tcg_temp_free_ptr(fpst);
2951     tcg_temp_free_i32(tmp);
2952     return true;
2955 static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a)
2957     TCGv_ptr fpst;
2958     TCGv_i64 tmp;
2960     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2961         return false;
2962     }
2964     if (!dc_isar_feature(aa32_vrint, s)) {
2965         return false;
2966     }
2968     /* UNDEF accesses to D16-D31 if they don't exist. */
2969     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
2970         return false;
2971     }
2973     if (!vfp_access_check(s)) {
2974         return true;
2975     }
2977     tmp = tcg_temp_new_i64();
2978     vfp_load_reg64(tmp, a->vm);
2979     fpst = fpstatus_ptr(FPST_FPCR);
2980     gen_helper_rintd(tmp, tmp, fpst);
2981     vfp_store_reg64(tmp, a->vd);
2982     tcg_temp_free_ptr(fpst);
2983     tcg_temp_free_i64(tmp);
2984     return true;
2987 static bool trans_VRINTZ_hp(DisasContext *s, arg_VRINTZ_sp *a)
2989     TCGv_ptr fpst;
2990     TCGv_i32 tmp;
2991     TCGv_i32 tcg_rmode;
2993     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2994         return false;
2995     }
2997     if (!vfp_access_check(s)) {
2998         return true;
2999     }
3001     tmp = tcg_temp_new_i32();
3002     vfp_load_reg32(tmp, a->vm);
3003     fpst = fpstatus_ptr(FPST_FPCR_F16);
3004     tcg_rmode = tcg_const_i32(float_round_to_zero);
3005     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
3006     gen_helper_rinth(tmp, tmp, fpst);
3007     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
3008     vfp_store_reg32(tmp, a->vd);
3009     tcg_temp_free_ptr(fpst);
3010     tcg_temp_free_i32(tcg_rmode);
3011     tcg_temp_free_i32(tmp);
3012     return true;
3015 static bool trans_VRINTZ_sp(DisasContext *s, arg_VRINTZ_sp *a)
3017     TCGv_ptr fpst;
3018     TCGv_i32 tmp;
3019     TCGv_i32 tcg_rmode;
3021     if (!dc_isar_feature(aa32_vrint, s)) {
3022         return false;
3023     }
3025     if (!vfp_access_check(s)) {
3026         return true;
3027     }
3029     tmp = tcg_temp_new_i32();
3030     vfp_load_reg32(tmp, a->vm);
3031     fpst = fpstatus_ptr(FPST_FPCR);
3032     tcg_rmode = tcg_const_i32(float_round_to_zero);
3033     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
3034     gen_helper_rints(tmp, tmp, fpst);
3035     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
3036     vfp_store_reg32(tmp, a->vd);
3037     tcg_temp_free_ptr(fpst);
3038     tcg_temp_free_i32(tcg_rmode);
3039     tcg_temp_free_i32(tmp);
3040     return true;
3043 static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a)
3045     TCGv_ptr fpst;
3046     TCGv_i64 tmp;
3047     TCGv_i32 tcg_rmode;
3049     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3050         return false;
3051     }
3053     if (!dc_isar_feature(aa32_vrint, s)) {
3054         return false;
3055     }
3057     /* UNDEF accesses to D16-D31 if they don't exist. */
3058     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
3059         return false;
3060     }
3062     if (!vfp_access_check(s)) {
3063         return true;
3064     }
3066     tmp = tcg_temp_new_i64();
3067     vfp_load_reg64(tmp, a->vm);
3068     fpst = fpstatus_ptr(FPST_FPCR);
3069     tcg_rmode = tcg_const_i32(float_round_to_zero);
3070     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
3071     gen_helper_rintd(tmp, tmp, fpst);
3072     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
3073     vfp_store_reg64(tmp, a->vd);
3074     tcg_temp_free_ptr(fpst);
3075     tcg_temp_free_i64(tmp);
3076     tcg_temp_free_i32(tcg_rmode);
3077     return true;
3080 static bool trans_VRINTX_hp(DisasContext *s, arg_VRINTX_sp *a)
3082     TCGv_ptr fpst;
3083     TCGv_i32 tmp;
3085     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3086         return false;
3087     }
3089     if (!vfp_access_check(s)) {
3090         return true;
3091     }
3093     tmp = tcg_temp_new_i32();
3094     vfp_load_reg32(tmp, a->vm);
3095     fpst = fpstatus_ptr(FPST_FPCR_F16);
3096     gen_helper_rinth_exact(tmp, tmp, fpst);
3097     vfp_store_reg32(tmp, a->vd);
3098     tcg_temp_free_ptr(fpst);
3099     tcg_temp_free_i32(tmp);
3100     return true;
3103 static bool trans_VRINTX_sp(DisasContext *s, arg_VRINTX_sp *a)
3105     TCGv_ptr fpst;
3106     TCGv_i32 tmp;
3108     if (!dc_isar_feature(aa32_vrint, s)) {
3109         return false;
3110     }
3112     if (!vfp_access_check(s)) {
3113         return true;
3114     }
3116     tmp = tcg_temp_new_i32();
3117     vfp_load_reg32(tmp, a->vm);
3118     fpst = fpstatus_ptr(FPST_FPCR);
3119     gen_helper_rints_exact(tmp, tmp, fpst);
3120     vfp_store_reg32(tmp, a->vd);
3121     tcg_temp_free_ptr(fpst);
3122     tcg_temp_free_i32(tmp);
3123     return true;
3126 static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a)
3128     TCGv_ptr fpst;
3129     TCGv_i64 tmp;
3131     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3132         return false;
3133     }
3135     if (!dc_isar_feature(aa32_vrint, s)) {
3136         return false;
3137     }
3139     /* UNDEF accesses to D16-D31 if they don't exist. */
3140     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
3141         return false;
3142     }
3144     if (!vfp_access_check(s)) {
3145         return true;
3146     }
3148     tmp = tcg_temp_new_i64();
3149     vfp_load_reg64(tmp, a->vm);
3150     fpst = fpstatus_ptr(FPST_FPCR);
3151     gen_helper_rintd_exact(tmp, tmp, fpst);
3152     vfp_store_reg64(tmp, a->vd);
3153     tcg_temp_free_ptr(fpst);
3154     tcg_temp_free_i64(tmp);
3155     return true;
3158 static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a)
3160     TCGv_i64 vd;
3161     TCGv_i32 vm;
3163     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3164         return false;
3165     }
3167     /* UNDEF accesses to D16-D31 if they don't exist. */
3168     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
3169         return false;
3170     }
3172     if (!vfp_access_check(s)) {
3173         return true;
3174     }
3176     vm = tcg_temp_new_i32();
3177     vd = tcg_temp_new_i64();
3178     vfp_load_reg32(vm, a->vm);
3179     gen_helper_vfp_fcvtds(vd, vm, cpu_env);
3180     vfp_store_reg64(vd, a->vd);
3181     tcg_temp_free_i32(vm);
3182     tcg_temp_free_i64(vd);
3183     return true;
3186 static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a)
3188     TCGv_i64 vm;
3189     TCGv_i32 vd;
3191     if (!dc_isar_feature(aa32_fpdp_v2, 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->vm & 0x10)) {
3197         return false;
3198     }
3200     if (!vfp_access_check(s)) {
3201         return true;
3202     }
3204     vd = tcg_temp_new_i32();
3205     vm = tcg_temp_new_i64();
3206     vfp_load_reg64(vm, a->vm);
3207     gen_helper_vfp_fcvtsd(vd, vm, cpu_env);
3208     vfp_store_reg32(vd, a->vd);
3209     tcg_temp_free_i32(vd);
3210     tcg_temp_free_i64(vm);
3211     return true;
3214 static bool trans_VCVT_int_hp(DisasContext *s, arg_VCVT_int_sp *a)
3216     TCGv_i32 vm;
3217     TCGv_ptr fpst;
3219     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3220         return false;
3221     }
3223     if (!vfp_access_check(s)) {
3224         return true;
3225     }
3227     vm = tcg_temp_new_i32();
3228     vfp_load_reg32(vm, a->vm);
3229     fpst = fpstatus_ptr(FPST_FPCR_F16);
3230     if (a->s) {
3231         /* i32 -> f16 */
3232         gen_helper_vfp_sitoh(vm, vm, fpst);
3233     } else {
3234         /* u32 -> f16 */
3235         gen_helper_vfp_uitoh(vm, vm, fpst);
3236     }
3237     vfp_store_reg32(vm, a->vd);
3238     tcg_temp_free_i32(vm);
3239     tcg_temp_free_ptr(fpst);
3240     return true;
3243 static bool trans_VCVT_int_sp(DisasContext *s, arg_VCVT_int_sp *a)
3245     TCGv_i32 vm;
3246     TCGv_ptr fpst;
3248     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
3249         return false;
3250     }
3252     if (!vfp_access_check(s)) {
3253         return true;
3254     }
3256     vm = tcg_temp_new_i32();
3257     vfp_load_reg32(vm, a->vm);
3258     fpst = fpstatus_ptr(FPST_FPCR);
3259     if (a->s) {
3260         /* i32 -> f32 */
3261         gen_helper_vfp_sitos(vm, vm, fpst);
3262     } else {
3263         /* u32 -> f32 */
3264         gen_helper_vfp_uitos(vm, vm, fpst);
3265     }
3266     vfp_store_reg32(vm, a->vd);
3267     tcg_temp_free_i32(vm);
3268     tcg_temp_free_ptr(fpst);
3269     return true;
3272 static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a)
3274     TCGv_i32 vm;
3275     TCGv_i64 vd;
3276     TCGv_ptr fpst;
3278     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3279         return false;
3280     }
3282     /* UNDEF accesses to D16-D31 if they don't exist. */
3283     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
3284         return false;
3285     }
3287     if (!vfp_access_check(s)) {
3288         return true;
3289     }
3291     vm = tcg_temp_new_i32();
3292     vd = tcg_temp_new_i64();
3293     vfp_load_reg32(vm, a->vm);
3294     fpst = fpstatus_ptr(FPST_FPCR);
3295     if (a->s) {
3296         /* i32 -> f64 */
3297         gen_helper_vfp_sitod(vd, vm, fpst);
3298     } else {
3299         /* u32 -> f64 */
3300         gen_helper_vfp_uitod(vd, vm, fpst);
3301     }
3302     vfp_store_reg64(vd, a->vd);
3303     tcg_temp_free_i32(vm);
3304     tcg_temp_free_i64(vd);
3305     tcg_temp_free_ptr(fpst);
3306     return true;
3309 static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a)
3311     TCGv_i32 vd;
3312     TCGv_i64 vm;
3314     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3315         return false;
3316     }
3318     if (!dc_isar_feature(aa32_jscvt, s)) {
3319         return false;
3320     }
3322     /* UNDEF accesses to D16-D31 if they don't exist. */
3323     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
3324         return false;
3325     }
3327     if (!vfp_access_check(s)) {
3328         return true;
3329     }
3331     vm = tcg_temp_new_i64();
3332     vd = tcg_temp_new_i32();
3333     vfp_load_reg64(vm, a->vm);
3334     gen_helper_vjcvt(vd, vm, cpu_env);
3335     vfp_store_reg32(vd, a->vd);
3336     tcg_temp_free_i64(vm);
3337     tcg_temp_free_i32(vd);
3338     return true;
3341 static bool trans_VCVT_fix_hp(DisasContext *s, arg_VCVT_fix_sp *a)
3343     TCGv_i32 vd, shift;
3344     TCGv_ptr fpst;
3345     int frac_bits;
3347     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3348         return false;
3349     }
3351     if (!vfp_access_check(s)) {
3352         return true;
3353     }
3355     frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
3357     vd = tcg_temp_new_i32();
3358     vfp_load_reg32(vd, a->vd);
3360     fpst = fpstatus_ptr(FPST_FPCR_F16);
3361     shift = tcg_const_i32(frac_bits);
3363     /* Switch on op:U:sx bits */
3364     switch (a->opc) {
3365     case 0:
3366         gen_helper_vfp_shtoh_round_to_nearest(vd, vd, shift, fpst);
3367         break;
3368     case 1:
3369         gen_helper_vfp_sltoh_round_to_nearest(vd, vd, shift, fpst);
3370         break;
3371     case 2:
3372         gen_helper_vfp_uhtoh_round_to_nearest(vd, vd, shift, fpst);
3373         break;
3374     case 3:
3375         gen_helper_vfp_ultoh_round_to_nearest(vd, vd, shift, fpst);
3376         break;
3377     case 4:
3378         gen_helper_vfp_toshh_round_to_zero(vd, vd, shift, fpst);
3379         break;
3380     case 5:
3381         gen_helper_vfp_toslh_round_to_zero(vd, vd, shift, fpst);
3382         break;
3383     case 6:
3384         gen_helper_vfp_touhh_round_to_zero(vd, vd, shift, fpst);
3385         break;
3386     case 7:
3387         gen_helper_vfp_toulh_round_to_zero(vd, vd, shift, fpst);
3388         break;
3389     default:
3390         g_assert_not_reached();
3391     }
3393     vfp_store_reg32(vd, a->vd);
3394     tcg_temp_free_i32(vd);
3395     tcg_temp_free_i32(shift);
3396     tcg_temp_free_ptr(fpst);
3397     return true;
3400 static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a)
3402     TCGv_i32 vd, shift;
3403     TCGv_ptr fpst;
3404     int frac_bits;
3406     if (!dc_isar_feature(aa32_fpsp_v3, s)) {
3407         return false;
3408     }
3410     if (!vfp_access_check(s)) {
3411         return true;
3412     }
3414     frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
3416     vd = tcg_temp_new_i32();
3417     vfp_load_reg32(vd, a->vd);
3419     fpst = fpstatus_ptr(FPST_FPCR);
3420     shift = tcg_const_i32(frac_bits);
3422     /* Switch on op:U:sx bits */
3423     switch (a->opc) {
3424     case 0:
3425         gen_helper_vfp_shtos_round_to_nearest(vd, vd, shift, fpst);
3426         break;
3427     case 1:
3428         gen_helper_vfp_sltos_round_to_nearest(vd, vd, shift, fpst);
3429         break;
3430     case 2:
3431         gen_helper_vfp_uhtos_round_to_nearest(vd, vd, shift, fpst);
3432         break;
3433     case 3:
3434         gen_helper_vfp_ultos_round_to_nearest(vd, vd, shift, fpst);
3435         break;
3436     case 4:
3437         gen_helper_vfp_toshs_round_to_zero(vd, vd, shift, fpst);
3438         break;
3439     case 5:
3440         gen_helper_vfp_tosls_round_to_zero(vd, vd, shift, fpst);
3441         break;
3442     case 6:
3443         gen_helper_vfp_touhs_round_to_zero(vd, vd, shift, fpst);
3444         break;
3445     case 7:
3446         gen_helper_vfp_touls_round_to_zero(vd, vd, shift, fpst);
3447         break;
3448     default:
3449         g_assert_not_reached();
3450     }
3452     vfp_store_reg32(vd, a->vd);
3453     tcg_temp_free_i32(vd);
3454     tcg_temp_free_i32(shift);
3455     tcg_temp_free_ptr(fpst);
3456     return true;
3459 static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
3461     TCGv_i64 vd;
3462     TCGv_i32 shift;
3463     TCGv_ptr fpst;
3464     int frac_bits;
3466     if (!dc_isar_feature(aa32_fpdp_v3, s)) {
3467         return false;
3468     }
3470     /* UNDEF accesses to D16-D31 if they don't exist. */
3471     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
3472         return false;
3473     }
3475     if (!vfp_access_check(s)) {
3476         return true;
3477     }
3479     frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
3481     vd = tcg_temp_new_i64();
3482     vfp_load_reg64(vd, a->vd);
3484     fpst = fpstatus_ptr(FPST_FPCR);
3485     shift = tcg_const_i32(frac_bits);
3487     /* Switch on op:U:sx bits */
3488     switch (a->opc) {
3489     case 0:
3490         gen_helper_vfp_shtod_round_to_nearest(vd, vd, shift, fpst);
3491         break;
3492     case 1:
3493         gen_helper_vfp_sltod_round_to_nearest(vd, vd, shift, fpst);
3494         break;
3495     case 2:
3496         gen_helper_vfp_uhtod_round_to_nearest(vd, vd, shift, fpst);
3497         break;
3498     case 3:
3499         gen_helper_vfp_ultod_round_to_nearest(vd, vd, shift, fpst);
3500         break;
3501     case 4:
3502         gen_helper_vfp_toshd_round_to_zero(vd, vd, shift, fpst);
3503         break;
3504     case 5:
3505         gen_helper_vfp_tosld_round_to_zero(vd, vd, shift, fpst);
3506         break;
3507     case 6:
3508         gen_helper_vfp_touhd_round_to_zero(vd, vd, shift, fpst);
3509         break;
3510     case 7:
3511         gen_helper_vfp_tould_round_to_zero(vd, vd, shift, fpst);
3512         break;
3513     default:
3514         g_assert_not_reached();
3515     }
3517     vfp_store_reg64(vd, a->vd);
3518     tcg_temp_free_i64(vd);
3519     tcg_temp_free_i32(shift);
3520     tcg_temp_free_ptr(fpst);
3521     return true;
3524 static bool trans_VCVT_hp_int(DisasContext *s, arg_VCVT_sp_int *a)
3526     TCGv_i32 vm;
3527     TCGv_ptr fpst;
3529     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3530         return false;
3531     }
3533     if (!vfp_access_check(s)) {
3534         return true;
3535     }
3537     fpst = fpstatus_ptr(FPST_FPCR_F16);
3538     vm = tcg_temp_new_i32();
3539     vfp_load_reg32(vm, a->vm);
3541     if (a->s) {
3542         if (a->rz) {
3543             gen_helper_vfp_tosizh(vm, vm, fpst);
3544         } else {
3545             gen_helper_vfp_tosih(vm, vm, fpst);
3546         }
3547     } else {
3548         if (a->rz) {
3549             gen_helper_vfp_touizh(vm, vm, fpst);
3550         } else {
3551             gen_helper_vfp_touih(vm, vm, fpst);
3552         }
3553     }
3554     vfp_store_reg32(vm, a->vd);
3555     tcg_temp_free_i32(vm);
3556     tcg_temp_free_ptr(fpst);
3557     return true;
3560 static bool trans_VCVT_sp_int(DisasContext *s, arg_VCVT_sp_int *a)
3562     TCGv_i32 vm;
3563     TCGv_ptr fpst;
3565     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
3566         return false;
3567     }
3569     if (!vfp_access_check(s)) {
3570         return true;
3571     }
3573     fpst = fpstatus_ptr(FPST_FPCR);
3574     vm = tcg_temp_new_i32();
3575     vfp_load_reg32(vm, a->vm);
3577     if (a->s) {
3578         if (a->rz) {
3579             gen_helper_vfp_tosizs(vm, vm, fpst);
3580         } else {
3581             gen_helper_vfp_tosis(vm, vm, fpst);
3582         }
3583     } else {
3584         if (a->rz) {
3585             gen_helper_vfp_touizs(vm, vm, fpst);
3586         } else {
3587             gen_helper_vfp_touis(vm, vm, fpst);
3588         }
3589     }
3590     vfp_store_reg32(vm, a->vd);
3591     tcg_temp_free_i32(vm);
3592     tcg_temp_free_ptr(fpst);
3593     return true;
3596 static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
3598     TCGv_i32 vd;
3599     TCGv_i64 vm;
3600     TCGv_ptr fpst;
3602     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3603         return false;
3604     }
3606     /* UNDEF accesses to D16-D31 if they don't exist. */
3607     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
3608         return false;
3609     }
3611     if (!vfp_access_check(s)) {
3612         return true;
3613     }
3615     fpst = fpstatus_ptr(FPST_FPCR);
3616     vm = tcg_temp_new_i64();
3617     vd = tcg_temp_new_i32();
3618     vfp_load_reg64(vm, a->vm);
3620     if (a->s) {
3621         if (a->rz) {
3622             gen_helper_vfp_tosizd(vd, vm, fpst);
3623         } else {
3624             gen_helper_vfp_tosid(vd, vm, fpst);
3625         }
3626     } else {
3627         if (a->rz) {
3628             gen_helper_vfp_touizd(vd, vm, fpst);
3629         } else {
3630             gen_helper_vfp_touid(vd, vm, fpst);
3631         }
3632     }
3633     vfp_store_reg32(vd, a->vd);
3634     tcg_temp_free_i32(vd);
3635     tcg_temp_free_i64(vm);
3636     tcg_temp_free_ptr(fpst);
3637     return true;
3641  * Decode VLLDM and VLSTM are nonstandard because:
3642  *  * if there is no FPU then these insns must NOP in
3643  *    Secure state and UNDEF in Nonsecure state
3644  *  * if there is an FPU then these insns do not have
3645  *    the usual behaviour that vfp_access_check() provides of
3646  *    being controlled by CPACR/NSACR enable bits or the
3647  *    lazy-stacking logic.
3648  */
3649 static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
3651     TCGv_i32 fptr;
3653     if (!arm_dc_feature(s, ARM_FEATURE_M) ||
3654         !arm_dc_feature(s, ARM_FEATURE_V8)) {
3655         return false;
3656     }
3657     /*
3658      * If not secure, UNDEF. We must emit code for this
3659      * rather than returning false so that this takes
3660      * precedence over the m-nocp.decode NOCP fallback.
3661      */
3662     if (!s->v8m_secure) {
3663         unallocated_encoding(s);
3664         return true;
3665     }
3666     /* If no fpu, NOP. */
3667     if (!dc_isar_feature(aa32_vfp, s)) {
3668         return true;
3669     }
3671     fptr = load_reg(s, a->rn);
3672     if (a->l) {
3673         gen_helper_v7m_vlldm(cpu_env, fptr);
3674     } else {
3675         gen_helper_v7m_vlstm(cpu_env, fptr);
3676     }
3677     tcg_temp_free_i32(fptr);
3679     /* End the TB, because we have updated FP control bits */
3680     s->base.is_jmp = DISAS_UPDATE_EXIT;
3681     return true;
3684 static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a)
3686     int btmreg, topreg;
3687     TCGv_i64 zero;
3688     TCGv_i32 aspen, sfpa;
3690     if (!dc_isar_feature(aa32_m_sec_state, s)) {
3691         /* Before v8.1M, fall through in decode to NOCP check */
3692         return false;
3693     }
3695     /* Explicitly UNDEF because this takes precedence over NOCP */
3696     if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) {
3697         unallocated_encoding(s);
3698         return true;
3699     }
3701     if (!dc_isar_feature(aa32_vfp_simd, s)) {
3702         /* NOP if we have neither FP nor MVE */
3703         return true;
3704     }
3706     /*
3707      * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no
3708      * active floating point context so we must NOP (without doing
3709      * any lazy state preservation or the NOCP check).
3710      */
3711     aspen = load_cpu_field(v7m.fpccr[M_REG_S]);
3712     sfpa = load_cpu_field(v7m.control[M_REG_S]);
3713     tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
3714     tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
3715     tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK);
3716     tcg_gen_or_i32(sfpa, sfpa, aspen);
3717     arm_gen_condlabel(s);
3718     tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel);
3720     if (s->fp_excp_el != 0) {
3721         gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
3722                            syn_uncategorized(), s->fp_excp_el);
3723         return true;
3724     }
3726     topreg = a->vd + a->imm - 1;
3727     btmreg = a->vd;
3729     /* Convert to Sreg numbers if the insn specified in Dregs */
3730     if (a->size == 3) {
3731         topreg = topreg * 2 + 1;
3732         btmreg *= 2;
3733     }
3735     if (topreg > 63 || (topreg > 31 && !(topreg & 1))) {
3736         /* UNPREDICTABLE: we choose to undef */
3737         unallocated_encoding(s);
3738         return true;
3739     }
3741     /* Silently ignore requests to clear D16-D31 if they don't exist */
3742     if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) {
3743         topreg = 31;
3744     }
3746     if (!vfp_access_check(s)) {
3747         return true;
3748     }
3750     /* Zero the Sregs from btmreg to topreg inclusive. */
3751     zero = tcg_const_i64(0);
3752     if (btmreg & 1) {
3753         write_neon_element64(zero, btmreg >> 1, 1, MO_32);
3754         btmreg++;
3755     }
3756     for (; btmreg + 1 <= topreg; btmreg += 2) {
3757         write_neon_element64(zero, btmreg >> 1, 0, MO_64);
3758     }
3759     if (btmreg == topreg) {
3760         write_neon_element64(zero, btmreg >> 1, 0, MO_32);
3761         btmreg++;
3762     }
3763     assert(btmreg == topreg + 1);
3764     /* TODO: when MVE is implemented, zero VPR here */
3765     return true;
3768 static bool trans_NOCP(DisasContext *s, arg_nocp *a)
3770     /*
3771      * Handle M-profile early check for disabled coprocessor:
3772      * all we need to do here is emit the NOCP exception if
3773      * the coprocessor is disabled. Otherwise we return false
3774      * and the real VFP/etc decode will handle the insn.
3775      */
3776     assert(arm_dc_feature(s, ARM_FEATURE_M));
3778     if (a->cp == 11) {
3779         a->cp = 10;
3780     }
3781     if (arm_dc_feature(s, ARM_FEATURE_V8_1M) &&
3782         (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) {
3783         /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
3784         a->cp = 10;
3785     }
3787     if (a->cp != 10) {
3788         gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
3789                            syn_uncategorized(), default_exception_el(s));
3790         return true;
3791     }
3793     if (s->fp_excp_el != 0) {
3794         gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
3795                            syn_uncategorized(), s->fp_excp_el);
3796         return true;
3797     }
3799     return false;
3802 static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a)
3804     /* This range needs a coprocessor check for v8.1M and later only */
3805     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
3806         return false;
3807     }
3808     return trans_NOCP(s, a);
3811 static bool trans_VINS(DisasContext *s, arg_VINS *a)
3813     TCGv_i32 rd, rm;
3815     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3816         return false;
3817     }
3819     if (s->vec_len != 0 || s->vec_stride != 0) {
3820         return false;
3821     }
3823     if (!vfp_access_check(s)) {
3824         return true;
3825     }
3827     /* Insert low half of Vm into high half of Vd */
3828     rm = tcg_temp_new_i32();
3829     rd = tcg_temp_new_i32();
3830     vfp_load_reg32(rm, a->vm);
3831     vfp_load_reg32(rd, a->vd);
3832     tcg_gen_deposit_i32(rd, rd, rm, 16, 16);
3833     vfp_store_reg32(rd, a->vd);
3834     tcg_temp_free_i32(rm);
3835     tcg_temp_free_i32(rd);
3836     return true;
3839 static bool trans_VMOVX(DisasContext *s, arg_VINS *a)
3841     TCGv_i32 rm;
3843     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3844         return false;
3845     }
3847     if (s->vec_len != 0 || s->vec_stride != 0) {
3848         return false;
3849     }
3851     if (!vfp_access_check(s)) {
3852         return true;
3853     }
3855     /* Set Vd to high half of Vm */
3856     rm = tcg_temp_new_i32();
3857     vfp_load_reg32(rm, a->vm);
3858     tcg_gen_shri_i32(rm, rm, 16);
3859     vfp_store_reg32(rm, a->vd);
3860     tcg_temp_free_i32(rm);
3861     return true;