arm tcg cpus: Fix Lesser GPL version number
[qemu.git] / target / arm / translate-vfp.c.inc
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  */
22
23 /*
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  */
28
29 /* Include the generated VFP decoder */
30 #include "decode-vfp.c.inc"
31 #include "decode-vfp-uncond.c.inc"
32
33 /*
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)
39 {
40     uint64_t imm;
41
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;
64 }
65
66 /*
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)
72 {
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;
84 }
85
86 /*
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)
96 {
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     }
105
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     }
111
112     if (arm_dc_feature(s, ARM_FEATURE_M)) {
113         /* Handle M-profile lazy FP state mechanics */
114
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         }
134
135         /* Update ownership of FP context: set FPCCR.S to match current state */
136         if (s->v8m_fpccr_s_wrong) {
137             TCGv_i32 tmp;
138
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         }
149
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;
157
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              */
166
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     }
177
178     return true;
179 }
180
181 /*
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)
186 {
187     return full_vfp_access_check(s, false);
188 }
189
190 static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
191 {
192     uint32_t rd, rn, rm;
193     int sz = a->sz;
194
195     if (!dc_isar_feature(aa32_vsel, s)) {
196         return false;
197     }
198
199     if (sz == 3 && !dc_isar_feature(aa32_fpdp_v2, s)) {
200         return false;
201     }
202
203     if (sz == 1 && !dc_isar_feature(aa32_fp16_arith, s)) {
204         return false;
205     }
206
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     }
212
213     rd = a->vd;
214     rn = a->vn;
215     rm = a->vm;
216
217     if (!vfp_access_check(s)) {
218         return true;
219     }
220
221     if (sz == 3) {
222         TCGv_i64 frn, frm, dest;
223         TCGv_i64 tmp, zero, zf, nf, vf;
224
225         zero = tcg_const_i64(0);
226
227         frn = tcg_temp_new_i64();
228         frm = tcg_temp_new_i64();
229         dest = tcg_temp_new_i64();
230
231         zf = tcg_temp_new_i64();
232         nf = tcg_temp_new_i64();
233         vf = tcg_temp_new_i64();
234
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);
238
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);
271
272         tcg_temp_free_i64(zf);
273         tcg_temp_free_i64(nf);
274         tcg_temp_free_i64(vf);
275
276         tcg_temp_free_i64(zero);
277     } else {
278         TCGv_i32 frn, frm, dest;
279         TCGv_i32 tmp, zero;
280
281         zero = tcg_const_i32(0);
282
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);
322
323         tcg_temp_free_i32(zero);
324     }
325
326     return true;
327 }
328
329 /*
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,
339 };
340
341 static bool trans_VRINT(DisasContext *s, arg_VRINT *a)
342 {
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];
348
349     if (!dc_isar_feature(aa32_vrint, s)) {
350         return false;
351     }
352
353     if (sz == 3 && !dc_isar_feature(aa32_fpdp_v2, s)) {
354         return false;
355     }
356
357     if (sz == 1 && !dc_isar_feature(aa32_fp16_arith, s)) {
358         return false;
359     }
360
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     }
366
367     rd = a->vd;
368     rm = a->vm;
369
370     if (!vfp_access_check(s)) {
371         return true;
372     }
373
374     if (sz == 1) {
375         fpst = fpstatus_ptr(FPST_FPCR_F16);
376     } else {
377         fpst = fpstatus_ptr(FPST_FPCR);
378     }
379
380     tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding));
381     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
382
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     }
408
409     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
410     tcg_temp_free_i32(tcg_rmode);
411
412     tcg_temp_free_ptr(fpst);
413     return true;
414 }
415
416 static bool trans_VCVT(DisasContext *s, arg_VCVT *a)
417 {
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;
424
425     if (!dc_isar_feature(aa32_vcvt_dr, s)) {
426         return false;
427     }
428
429     if (sz == 3 && !dc_isar_feature(aa32_fpdp_v2, s)) {
430         return false;
431     }
432
433     if (sz == 1 && !dc_isar_feature(aa32_fp16_arith, s)) {
434         return false;
435     }
436
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     }
441
442     rd = a->vd;
443     rm = a->vm;
444
445     if (!vfp_access_check(s)) {
446         return true;
447     }
448
449     if (sz == 1) {
450         fpst = fpstatus_ptr(FPST_FPCR_F16);
451     } else {
452         fpst = fpstatus_ptr(FPST_FPCR);
453     }
454
455     tcg_shift = tcg_const_i32(0);
456
457     tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding));
458     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
459
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     }
499
500     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
501     tcg_temp_free_i32(tcg_rmode);
502
503     tcg_temp_free_i32(tcg_shift);
504
505     tcg_temp_free_ptr(fpst);
506
507     return true;
508 }
509
510 static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a)
511 {
512     /* VMOV scalar to general purpose register */
513     TCGv_i32 tmp;
514
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     }
521
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     }
526
527     if (!vfp_access_check(s)) {
528         return true;
529     }
530
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);
534
535     return true;
536 }
537
538 static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a)
539 {
540     /* VMOV general purpose register to scalar */
541     TCGv_i32 tmp;
542
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     }
549
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     }
554
555     if (!vfp_access_check(s)) {
556         return true;
557     }
558
559     tmp = load_reg(s, a->rt);
560     write_neon_element32(tmp, a->vn, a->index, a->size);
561     tcg_temp_free_i32(tmp);
562
563     return true;
564 }
565
566 static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
567 {
568     /* VDUP (general purpose register) */
569     TCGv_i32 tmp;
570     int size, vec_size;
571
572     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
573         return false;
574     }
575
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     }
580
581     if (a->b && a->e) {
582         return false;
583     }
584
585     if (a->q && (a->vn & 1)) {
586         return false;
587     }
588
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     }
597
598     if (!vfp_access_check(s)) {
599         return true;
600     }
601
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);
606
607     return true;
608 }
609
610 static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
611 {
612     TCGv_i32 tmp;
613     bool ignore_vfp_enabled = false;
614
615     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
616         return false;
617     }
618
619     if (arm_dc_feature(s, ARM_FEATURE_M)) {
620         /*
621          * The only M-profile VFP vmrs/vmsr sysreg is FPSCR.
622          * Accesses to R15 are UNPREDICTABLE; we choose to undef.
623          * (FPSCR -> r15 is a special case which writes to the PSR flags.)
624          */
625         if (a->rt == 15 && (!a->l || a->reg != ARM_VFP_FPSCR)) {
626             return false;
627         }
628     }
629
630     switch (a->reg) {
631     case ARM_VFP_FPSID:
632         /*
633          * VFPv2 allows access to FPSID from userspace; VFPv3 restricts
634          * all ID registers to privileged access only.
635          */
636         if (IS_USER(s) && dc_isar_feature(aa32_fpsp_v3, s)) {
637             return false;
638         }
639         ignore_vfp_enabled = true;
640         break;
641     case ARM_VFP_MVFR0:
642     case ARM_VFP_MVFR1:
643         if (IS_USER(s) || !arm_dc_feature(s, ARM_FEATURE_MVFR)) {
644             return false;
645         }
646         ignore_vfp_enabled = true;
647         break;
648     case ARM_VFP_MVFR2:
649         if (IS_USER(s) || !arm_dc_feature(s, ARM_FEATURE_V8)) {
650             return false;
651         }
652         ignore_vfp_enabled = true;
653         break;
654     case ARM_VFP_FPSCR:
655         break;
656     case ARM_VFP_FPEXC:
657         if (IS_USER(s)) {
658             return false;
659         }
660         ignore_vfp_enabled = true;
661         break;
662     case ARM_VFP_FPINST:
663     case ARM_VFP_FPINST2:
664         /* Not present in VFPv3 */
665         if (IS_USER(s) || dc_isar_feature(aa32_fpsp_v3, s)) {
666             return false;
667         }
668         break;
669     default:
670         return false;
671     }
672
673     if (!full_vfp_access_check(s, ignore_vfp_enabled)) {
674         return true;
675     }
676
677     if (a->l) {
678         /* VMRS, move VFP special register to gp register */
679         switch (a->reg) {
680         case ARM_VFP_MVFR0:
681         case ARM_VFP_MVFR1:
682         case ARM_VFP_MVFR2:
683         case ARM_VFP_FPSID:
684             if (s->current_el == 1) {
685                 TCGv_i32 tcg_reg, tcg_rt;
686
687                 gen_set_condexec(s);
688                 gen_set_pc_im(s, s->pc_curr);
689                 tcg_reg = tcg_const_i32(a->reg);
690                 tcg_rt = tcg_const_i32(a->rt);
691                 gen_helper_check_hcr_el2_trap(cpu_env, tcg_rt, tcg_reg);
692                 tcg_temp_free_i32(tcg_reg);
693                 tcg_temp_free_i32(tcg_rt);
694             }
695             /* fall through */
696         case ARM_VFP_FPEXC:
697         case ARM_VFP_FPINST:
698         case ARM_VFP_FPINST2:
699             tmp = load_cpu_field(vfp.xregs[a->reg]);
700             break;
701         case ARM_VFP_FPSCR:
702             if (a->rt == 15) {
703                 tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
704                 tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
705             } else {
706                 tmp = tcg_temp_new_i32();
707                 gen_helper_vfp_get_fpscr(tmp, cpu_env);
708             }
709             break;
710         default:
711             g_assert_not_reached();
712         }
713
714         if (a->rt == 15) {
715             /* Set the 4 flag bits in the CPSR.  */
716             gen_set_nzcv(tmp);
717             tcg_temp_free_i32(tmp);
718         } else {
719             store_reg(s, a->rt, tmp);
720         }
721     } else {
722         /* VMSR, move gp register to VFP special register */
723         switch (a->reg) {
724         case ARM_VFP_FPSID:
725         case ARM_VFP_MVFR0:
726         case ARM_VFP_MVFR1:
727         case ARM_VFP_MVFR2:
728             /* Writes are ignored.  */
729             break;
730         case ARM_VFP_FPSCR:
731             tmp = load_reg(s, a->rt);
732             gen_helper_vfp_set_fpscr(cpu_env, tmp);
733             tcg_temp_free_i32(tmp);
734             gen_lookup_tb(s);
735             break;
736         case ARM_VFP_FPEXC:
737             /*
738              * TODO: VFP subarchitecture support.
739              * For now, keep the EN bit only
740              */
741             tmp = load_reg(s, a->rt);
742             tcg_gen_andi_i32(tmp, tmp, 1 << 30);
743             store_cpu_field(tmp, vfp.xregs[a->reg]);
744             gen_lookup_tb(s);
745             break;
746         case ARM_VFP_FPINST:
747         case ARM_VFP_FPINST2:
748             tmp = load_reg(s, a->rt);
749             store_cpu_field(tmp, vfp.xregs[a->reg]);
750             break;
751         default:
752             g_assert_not_reached();
753         }
754     }
755
756     return true;
757 }
758
759 static bool trans_VMOV_half(DisasContext *s, arg_VMOV_single *a)
760 {
761     TCGv_i32 tmp;
762
763     if (!dc_isar_feature(aa32_fp16_arith, s)) {
764         return false;
765     }
766
767     if (a->rt == 15) {
768         /* UNPREDICTABLE; we choose to UNDEF */
769         return false;
770     }
771
772     if (!vfp_access_check(s)) {
773         return true;
774     }
775
776     if (a->l) {
777         /* VFP to general purpose register */
778         tmp = tcg_temp_new_i32();
779         vfp_load_reg32(tmp, a->vn);
780         tcg_gen_andi_i32(tmp, tmp, 0xffff);
781         store_reg(s, a->rt, tmp);
782     } else {
783         /* general purpose register to VFP */
784         tmp = load_reg(s, a->rt);
785         tcg_gen_andi_i32(tmp, tmp, 0xffff);
786         vfp_store_reg32(tmp, a->vn);
787         tcg_temp_free_i32(tmp);
788     }
789
790     return true;
791 }
792
793 static bool trans_VMOV_single(DisasContext *s, arg_VMOV_single *a)
794 {
795     TCGv_i32 tmp;
796
797     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
798         return false;
799     }
800
801     if (!vfp_access_check(s)) {
802         return true;
803     }
804
805     if (a->l) {
806         /* VFP to general purpose register */
807         tmp = tcg_temp_new_i32();
808         vfp_load_reg32(tmp, a->vn);
809         if (a->rt == 15) {
810             /* Set the 4 flag bits in the CPSR.  */
811             gen_set_nzcv(tmp);
812             tcg_temp_free_i32(tmp);
813         } else {
814             store_reg(s, a->rt, tmp);
815         }
816     } else {
817         /* general purpose register to VFP */
818         tmp = load_reg(s, a->rt);
819         vfp_store_reg32(tmp, a->vn);
820         tcg_temp_free_i32(tmp);
821     }
822
823     return true;
824 }
825
826 static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a)
827 {
828     TCGv_i32 tmp;
829
830     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
831         return false;
832     }
833
834     /*
835      * VMOV between two general-purpose registers and two single precision
836      * floating point registers
837      */
838     if (!vfp_access_check(s)) {
839         return true;
840     }
841
842     if (a->op) {
843         /* fpreg to gpreg */
844         tmp = tcg_temp_new_i32();
845         vfp_load_reg32(tmp, a->vm);
846         store_reg(s, a->rt, tmp);
847         tmp = tcg_temp_new_i32();
848         vfp_load_reg32(tmp, a->vm + 1);
849         store_reg(s, a->rt2, tmp);
850     } else {
851         /* gpreg to fpreg */
852         tmp = load_reg(s, a->rt);
853         vfp_store_reg32(tmp, a->vm);
854         tcg_temp_free_i32(tmp);
855         tmp = load_reg(s, a->rt2);
856         vfp_store_reg32(tmp, a->vm + 1);
857         tcg_temp_free_i32(tmp);
858     }
859
860     return true;
861 }
862
863 static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_dp *a)
864 {
865     TCGv_i32 tmp;
866
867     /*
868      * VMOV between two general-purpose registers and one double precision
869      * floating point register.  Note that this does not require support
870      * for double precision arithmetic.
871      */
872     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
873         return false;
874     }
875
876     /* UNDEF accesses to D16-D31 if they don't exist */
877     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
878         return false;
879     }
880
881     if (!vfp_access_check(s)) {
882         return true;
883     }
884
885     if (a->op) {
886         /* fpreg to gpreg */
887         tmp = tcg_temp_new_i32();
888         vfp_load_reg32(tmp, a->vm * 2);
889         store_reg(s, a->rt, tmp);
890         tmp = tcg_temp_new_i32();
891         vfp_load_reg32(tmp, a->vm * 2 + 1);
892         store_reg(s, a->rt2, tmp);
893     } else {
894         /* gpreg to fpreg */
895         tmp = load_reg(s, a->rt);
896         vfp_store_reg32(tmp, a->vm * 2);
897         tcg_temp_free_i32(tmp);
898         tmp = load_reg(s, a->rt2);
899         vfp_store_reg32(tmp, a->vm * 2 + 1);
900         tcg_temp_free_i32(tmp);
901     }
902
903     return true;
904 }
905
906 static bool trans_VLDR_VSTR_hp(DisasContext *s, arg_VLDR_VSTR_sp *a)
907 {
908     uint32_t offset;
909     TCGv_i32 addr, tmp;
910
911     if (!dc_isar_feature(aa32_fp16_arith, s)) {
912         return false;
913     }
914
915     if (!vfp_access_check(s)) {
916         return true;
917     }
918
919     /* imm8 field is offset/2 for fp16, unlike fp32 and fp64 */
920     offset = a->imm << 1;
921     if (!a->u) {
922         offset = -offset;
923     }
924
925     /* For thumb, use of PC is UNPREDICTABLE.  */
926     addr = add_reg_for_lit(s, a->rn, offset);
927     tmp = tcg_temp_new_i32();
928     if (a->l) {
929         gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
930         vfp_store_reg32(tmp, a->vd);
931     } else {
932         vfp_load_reg32(tmp, a->vd);
933         gen_aa32_st16(s, tmp, addr, get_mem_index(s));
934     }
935     tcg_temp_free_i32(tmp);
936     tcg_temp_free_i32(addr);
937
938     return true;
939 }
940
941 static bool trans_VLDR_VSTR_sp(DisasContext *s, arg_VLDR_VSTR_sp *a)
942 {
943     uint32_t offset;
944     TCGv_i32 addr, tmp;
945
946     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
947         return false;
948     }
949
950     if (!vfp_access_check(s)) {
951         return true;
952     }
953
954     offset = a->imm << 2;
955     if (!a->u) {
956         offset = -offset;
957     }
958
959     /* For thumb, use of PC is UNPREDICTABLE.  */
960     addr = add_reg_for_lit(s, a->rn, offset);
961     tmp = tcg_temp_new_i32();
962     if (a->l) {
963         gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
964         vfp_store_reg32(tmp, a->vd);
965     } else {
966         vfp_load_reg32(tmp, a->vd);
967         gen_aa32_st32(s, tmp, addr, get_mem_index(s));
968     }
969     tcg_temp_free_i32(tmp);
970     tcg_temp_free_i32(addr);
971
972     return true;
973 }
974
975 static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a)
976 {
977     uint32_t offset;
978     TCGv_i32 addr;
979     TCGv_i64 tmp;
980
981     /* Note that this does not require support for double arithmetic.  */
982     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
983         return false;
984     }
985
986     /* UNDEF accesses to D16-D31 if they don't exist */
987     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
988         return false;
989     }
990
991     if (!vfp_access_check(s)) {
992         return true;
993     }
994
995     offset = a->imm << 2;
996     if (!a->u) {
997         offset = -offset;
998     }
999
1000     /* For thumb, use of PC is UNPREDICTABLE.  */
1001     addr = add_reg_for_lit(s, a->rn, offset);
1002     tmp = tcg_temp_new_i64();
1003     if (a->l) {
1004         gen_aa32_ld64(s, tmp, addr, get_mem_index(s));
1005         vfp_store_reg64(tmp, a->vd);
1006     } else {
1007         vfp_load_reg64(tmp, a->vd);
1008         gen_aa32_st64(s, tmp, addr, get_mem_index(s));
1009     }
1010     tcg_temp_free_i64(tmp);
1011     tcg_temp_free_i32(addr);
1012
1013     return true;
1014 }
1015
1016 static bool trans_VLDM_VSTM_sp(DisasContext *s, arg_VLDM_VSTM_sp *a)
1017 {
1018     uint32_t offset;
1019     TCGv_i32 addr, tmp;
1020     int i, n;
1021
1022     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1023         return false;
1024     }
1025
1026     n = a->imm;
1027
1028     if (n == 0 || (a->vd + n) > 32) {
1029         /*
1030          * UNPREDICTABLE cases for bad immediates: we choose to
1031          * UNDEF to avoid generating huge numbers of TCG ops
1032          */
1033         return false;
1034     }
1035     if (a->rn == 15 && a->w) {
1036         /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1037         return false;
1038     }
1039
1040     if (!vfp_access_check(s)) {
1041         return true;
1042     }
1043
1044     /* For thumb, use of PC is UNPREDICTABLE.  */
1045     addr = add_reg_for_lit(s, a->rn, 0);
1046     if (a->p) {
1047         /* pre-decrement */
1048         tcg_gen_addi_i32(addr, addr, -(a->imm << 2));
1049     }
1050
1051     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
1052         /*
1053          * Here 'addr' is the lowest address we will store to,
1054          * and is either the old SP (if post-increment) or
1055          * the new SP (if pre-decrement). For post-increment
1056          * where the old value is below the limit and the new
1057          * value is above, it is UNKNOWN whether the limit check
1058          * triggers; we choose to trigger.
1059          */
1060         gen_helper_v8m_stackcheck(cpu_env, addr);
1061     }
1062
1063     offset = 4;
1064     tmp = tcg_temp_new_i32();
1065     for (i = 0; i < n; i++) {
1066         if (a->l) {
1067             /* load */
1068             gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
1069             vfp_store_reg32(tmp, a->vd + i);
1070         } else {
1071             /* store */
1072             vfp_load_reg32(tmp, a->vd + i);
1073             gen_aa32_st32(s, tmp, addr, get_mem_index(s));
1074         }
1075         tcg_gen_addi_i32(addr, addr, offset);
1076     }
1077     tcg_temp_free_i32(tmp);
1078     if (a->w) {
1079         /* writeback */
1080         if (a->p) {
1081             offset = -offset * n;
1082             tcg_gen_addi_i32(addr, addr, offset);
1083         }
1084         store_reg(s, a->rn, addr);
1085     } else {
1086         tcg_temp_free_i32(addr);
1087     }
1088
1089     return true;
1090 }
1091
1092 static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a)
1093 {
1094     uint32_t offset;
1095     TCGv_i32 addr;
1096     TCGv_i64 tmp;
1097     int i, n;
1098
1099     /* Note that this does not require support for double arithmetic.  */
1100     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1101         return false;
1102     }
1103
1104     n = a->imm >> 1;
1105
1106     if (n == 0 || (a->vd + n) > 32 || n > 16) {
1107         /*
1108          * UNPREDICTABLE cases for bad immediates: we choose to
1109          * UNDEF to avoid generating huge numbers of TCG ops
1110          */
1111         return false;
1112     }
1113     if (a->rn == 15 && a->w) {
1114         /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1115         return false;
1116     }
1117
1118     /* UNDEF accesses to D16-D31 if they don't exist */
1119     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd + n) > 16) {
1120         return false;
1121     }
1122
1123     if (!vfp_access_check(s)) {
1124         return true;
1125     }
1126
1127     /* For thumb, use of PC is UNPREDICTABLE.  */
1128     addr = add_reg_for_lit(s, a->rn, 0);
1129     if (a->p) {
1130         /* pre-decrement */
1131         tcg_gen_addi_i32(addr, addr, -(a->imm << 2));
1132     }
1133
1134     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
1135         /*
1136          * Here 'addr' is the lowest address we will store to,
1137          * and is either the old SP (if post-increment) or
1138          * the new SP (if pre-decrement). For post-increment
1139          * where the old value is below the limit and the new
1140          * value is above, it is UNKNOWN whether the limit check
1141          * triggers; we choose to trigger.
1142          */
1143         gen_helper_v8m_stackcheck(cpu_env, addr);
1144     }
1145
1146     offset = 8;
1147     tmp = tcg_temp_new_i64();
1148     for (i = 0; i < n; i++) {
1149         if (a->l) {
1150             /* load */
1151             gen_aa32_ld64(s, tmp, addr, get_mem_index(s));
1152             vfp_store_reg64(tmp, a->vd + i);
1153         } else {
1154             /* store */
1155             vfp_load_reg64(tmp, a->vd + i);
1156             gen_aa32_st64(s, tmp, addr, get_mem_index(s));
1157         }
1158         tcg_gen_addi_i32(addr, addr, offset);
1159     }
1160     tcg_temp_free_i64(tmp);
1161     if (a->w) {
1162         /* writeback */
1163         if (a->p) {
1164             offset = -offset * n;
1165         } else if (a->imm & 1) {
1166             offset = 4;
1167         } else {
1168             offset = 0;
1169         }
1170
1171         if (offset != 0) {
1172             tcg_gen_addi_i32(addr, addr, offset);
1173         }
1174         store_reg(s, a->rn, addr);
1175     } else {
1176         tcg_temp_free_i32(addr);
1177     }
1178
1179     return true;
1180 }
1181
1182 /*
1183  * Types for callbacks for do_vfp_3op_sp() and do_vfp_3op_dp().
1184  * The callback should emit code to write a value to vd. If
1185  * do_vfp_3op_{sp,dp}() was passed reads_vd then the TCGv vd
1186  * will contain the old value of the relevant VFP register;
1187  * otherwise it must be written to only.
1188  */
1189 typedef void VFPGen3OpSPFn(TCGv_i32 vd,
1190                            TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst);
1191 typedef void VFPGen3OpDPFn(TCGv_i64 vd,
1192                            TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst);
1193
1194 /*
1195  * Types for callbacks for do_vfp_2op_sp() and do_vfp_2op_dp().
1196  * The callback should emit code to write a value to vd (which
1197  * should be written to only).
1198  */
1199 typedef void VFPGen2OpSPFn(TCGv_i32 vd, TCGv_i32 vm);
1200 typedef void VFPGen2OpDPFn(TCGv_i64 vd, TCGv_i64 vm);
1201
1202 /*
1203  * Return true if the specified S reg is in a scalar bank
1204  * (ie if it is s0..s7)
1205  */
1206 static inline bool vfp_sreg_is_scalar(int reg)
1207 {
1208     return (reg & 0x18) == 0;
1209 }
1210
1211 /*
1212  * Return true if the specified D reg is in a scalar bank
1213  * (ie if it is d0..d3 or d16..d19)
1214  */
1215 static inline bool vfp_dreg_is_scalar(int reg)
1216 {
1217     return (reg & 0xc) == 0;
1218 }
1219
1220 /*
1221  * Advance the S reg number forwards by delta within its bank
1222  * (ie increment the low 3 bits but leave the rest the same)
1223  */
1224 static inline int vfp_advance_sreg(int reg, int delta)
1225 {
1226     return ((reg + delta) & 0x7) | (reg & ~0x7);
1227 }
1228
1229 /*
1230  * Advance the D reg number forwards by delta within its bank
1231  * (ie increment the low 2 bits but leave the rest the same)
1232  */
1233 static inline int vfp_advance_dreg(int reg, int delta)
1234 {
1235     return ((reg + delta) & 0x3) | (reg & ~0x3);
1236 }
1237
1238 /*
1239  * Perform a 3-operand VFP data processing instruction. fn is the
1240  * callback to do the actual operation; this function deals with the
1241  * code to handle looping around for VFP vector processing.
1242  */
1243 static bool do_vfp_3op_sp(DisasContext *s, VFPGen3OpSPFn *fn,
1244                           int vd, int vn, int vm, bool reads_vd)
1245 {
1246     uint32_t delta_m = 0;
1247     uint32_t delta_d = 0;
1248     int veclen = s->vec_len;
1249     TCGv_i32 f0, f1, fd;
1250     TCGv_ptr fpst;
1251
1252     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1253         return false;
1254     }
1255
1256     if (!dc_isar_feature(aa32_fpshvec, s) &&
1257         (veclen != 0 || s->vec_stride != 0)) {
1258         return false;
1259     }
1260
1261     if (!vfp_access_check(s)) {
1262         return true;
1263     }
1264
1265     if (veclen > 0) {
1266         /* Figure out what type of vector operation this is.  */
1267         if (vfp_sreg_is_scalar(vd)) {
1268             /* scalar */
1269             veclen = 0;
1270         } else {
1271             delta_d = s->vec_stride + 1;
1272
1273             if (vfp_sreg_is_scalar(vm)) {
1274                 /* mixed scalar/vector */
1275                 delta_m = 0;
1276             } else {
1277                 /* vector */
1278                 delta_m = delta_d;
1279             }
1280         }
1281     }
1282
1283     f0 = tcg_temp_new_i32();
1284     f1 = tcg_temp_new_i32();
1285     fd = tcg_temp_new_i32();
1286     fpst = fpstatus_ptr(FPST_FPCR);
1287
1288     vfp_load_reg32(f0, vn);
1289     vfp_load_reg32(f1, vm);
1290
1291     for (;;) {
1292         if (reads_vd) {
1293             vfp_load_reg32(fd, vd);
1294         }
1295         fn(fd, f0, f1, fpst);
1296         vfp_store_reg32(fd, vd);
1297
1298         if (veclen == 0) {
1299             break;
1300         }
1301
1302         /* Set up the operands for the next iteration */
1303         veclen--;
1304         vd = vfp_advance_sreg(vd, delta_d);
1305         vn = vfp_advance_sreg(vn, delta_d);
1306         vfp_load_reg32(f0, vn);
1307         if (delta_m) {
1308             vm = vfp_advance_sreg(vm, delta_m);
1309             vfp_load_reg32(f1, vm);
1310         }
1311     }
1312
1313     tcg_temp_free_i32(f0);
1314     tcg_temp_free_i32(f1);
1315     tcg_temp_free_i32(fd);
1316     tcg_temp_free_ptr(fpst);
1317
1318     return true;
1319 }
1320
1321 static bool do_vfp_3op_hp(DisasContext *s, VFPGen3OpSPFn *fn,
1322                           int vd, int vn, int vm, bool reads_vd)
1323 {
1324     /*
1325      * Do a half-precision operation. Functionally this is
1326      * the same as do_vfp_3op_sp(), except:
1327      *  - it uses the FPST_FPCR_F16
1328      *  - it doesn't need the VFP vector handling (fp16 is a
1329      *    v8 feature, and in v8 VFP vectors don't exist)
1330      *  - it does the aa32_fp16_arith feature test
1331      */
1332     TCGv_i32 f0, f1, fd;
1333     TCGv_ptr fpst;
1334
1335     if (!dc_isar_feature(aa32_fp16_arith, s)) {
1336         return false;
1337     }
1338
1339     if (s->vec_len != 0 || s->vec_stride != 0) {
1340         return false;
1341     }
1342
1343     if (!vfp_access_check(s)) {
1344         return true;
1345     }
1346
1347     f0 = tcg_temp_new_i32();
1348     f1 = tcg_temp_new_i32();
1349     fd = tcg_temp_new_i32();
1350     fpst = fpstatus_ptr(FPST_FPCR_F16);
1351
1352     vfp_load_reg32(f0, vn);
1353     vfp_load_reg32(f1, vm);
1354
1355     if (reads_vd) {
1356         vfp_load_reg32(fd, vd);
1357     }
1358     fn(fd, f0, f1, fpst);
1359     vfp_store_reg32(fd, vd);
1360
1361     tcg_temp_free_i32(f0);
1362     tcg_temp_free_i32(f1);
1363     tcg_temp_free_i32(fd);
1364     tcg_temp_free_ptr(fpst);
1365
1366     return true;
1367 }
1368
1369 static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn,
1370                           int vd, int vn, int vm, bool reads_vd)
1371 {
1372     uint32_t delta_m = 0;
1373     uint32_t delta_d = 0;
1374     int veclen = s->vec_len;
1375     TCGv_i64 f0, f1, fd;
1376     TCGv_ptr fpst;
1377
1378     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
1379         return false;
1380     }
1381
1382     /* UNDEF accesses to D16-D31 if they don't exist */
1383     if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) {
1384         return false;
1385     }
1386
1387     if (!dc_isar_feature(aa32_fpshvec, s) &&
1388         (veclen != 0 || s->vec_stride != 0)) {
1389         return false;
1390     }
1391
1392     if (!vfp_access_check(s)) {
1393         return true;
1394     }
1395
1396     if (veclen > 0) {
1397         /* Figure out what type of vector operation this is.  */
1398         if (vfp_dreg_is_scalar(vd)) {
1399             /* scalar */
1400             veclen = 0;
1401         } else {
1402             delta_d = (s->vec_stride >> 1) + 1;
1403
1404             if (vfp_dreg_is_scalar(vm)) {
1405                 /* mixed scalar/vector */
1406                 delta_m = 0;
1407             } else {
1408                 /* vector */
1409                 delta_m = delta_d;
1410             }
1411         }
1412     }
1413
1414     f0 = tcg_temp_new_i64();
1415     f1 = tcg_temp_new_i64();
1416     fd = tcg_temp_new_i64();
1417     fpst = fpstatus_ptr(FPST_FPCR);
1418
1419     vfp_load_reg64(f0, vn);
1420     vfp_load_reg64(f1, vm);
1421
1422     for (;;) {
1423         if (reads_vd) {
1424             vfp_load_reg64(fd, vd);
1425         }
1426         fn(fd, f0, f1, fpst);
1427         vfp_store_reg64(fd, vd);
1428
1429         if (veclen == 0) {
1430             break;
1431         }
1432         /* Set up the operands for the next iteration */
1433         veclen--;
1434         vd = vfp_advance_dreg(vd, delta_d);
1435         vn = vfp_advance_dreg(vn, delta_d);
1436         vfp_load_reg64(f0, vn);
1437         if (delta_m) {
1438             vm = vfp_advance_dreg(vm, delta_m);
1439             vfp_load_reg64(f1, vm);
1440         }
1441     }
1442
1443     tcg_temp_free_i64(f0);
1444     tcg_temp_free_i64(f1);
1445     tcg_temp_free_i64(fd);
1446     tcg_temp_free_ptr(fpst);
1447
1448     return true;
1449 }
1450
1451 static bool do_vfp_2op_sp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
1452 {
1453     uint32_t delta_m = 0;
1454     uint32_t delta_d = 0;
1455     int veclen = s->vec_len;
1456     TCGv_i32 f0, fd;
1457
1458     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1459         return false;
1460     }
1461
1462     if (!dc_isar_feature(aa32_fpshvec, s) &&
1463         (veclen != 0 || s->vec_stride != 0)) {
1464         return false;
1465     }
1466
1467     if (!vfp_access_check(s)) {
1468         return true;
1469     }
1470
1471     if (veclen > 0) {
1472         /* Figure out what type of vector operation this is.  */
1473         if (vfp_sreg_is_scalar(vd)) {
1474             /* scalar */
1475             veclen = 0;
1476         } else {
1477             delta_d = s->vec_stride + 1;
1478
1479             if (vfp_sreg_is_scalar(vm)) {
1480                 /* mixed scalar/vector */
1481                 delta_m = 0;
1482             } else {
1483                 /* vector */
1484                 delta_m = delta_d;
1485             }
1486         }
1487     }
1488
1489     f0 = tcg_temp_new_i32();
1490     fd = tcg_temp_new_i32();
1491
1492     vfp_load_reg32(f0, vm);
1493
1494     for (;;) {
1495         fn(fd, f0);
1496         vfp_store_reg32(fd, vd);
1497
1498         if (veclen == 0) {
1499             break;
1500         }
1501
1502         if (delta_m == 0) {
1503             /* single source one-many */
1504             while (veclen--) {
1505                 vd = vfp_advance_sreg(vd, delta_d);
1506                 vfp_store_reg32(fd, vd);
1507             }
1508             break;
1509         }
1510
1511         /* Set up the operands for the next iteration */
1512         veclen--;
1513         vd = vfp_advance_sreg(vd, delta_d);
1514         vm = vfp_advance_sreg(vm, delta_m);
1515         vfp_load_reg32(f0, vm);
1516     }
1517
1518     tcg_temp_free_i32(f0);
1519     tcg_temp_free_i32(fd);
1520
1521     return true;
1522 }
1523
1524 static bool do_vfp_2op_hp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
1525 {
1526     /*
1527      * Do a half-precision operation. Functionally this is
1528      * the same as do_vfp_2op_sp(), except:
1529      *  - it doesn't need the VFP vector handling (fp16 is a
1530      *    v8 feature, and in v8 VFP vectors don't exist)
1531      *  - it does the aa32_fp16_arith feature test
1532      */
1533     TCGv_i32 f0;
1534
1535     if (!dc_isar_feature(aa32_fp16_arith, s)) {
1536         return false;
1537     }
1538
1539     if (s->vec_len != 0 || s->vec_stride != 0) {
1540         return false;
1541     }
1542
1543     if (!vfp_access_check(s)) {
1544         return true;
1545     }
1546
1547     f0 = tcg_temp_new_i32();
1548     vfp_load_reg32(f0, vm);
1549     fn(f0, f0);
1550     vfp_store_reg32(f0, vd);
1551     tcg_temp_free_i32(f0);
1552
1553     return true;
1554 }
1555
1556 static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm)
1557 {
1558     uint32_t delta_m = 0;
1559     uint32_t delta_d = 0;
1560     int veclen = s->vec_len;
1561     TCGv_i64 f0, fd;
1562
1563     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
1564         return false;
1565     }
1566
1567     /* UNDEF accesses to D16-D31 if they don't exist */
1568     if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) {
1569         return false;
1570     }
1571
1572     if (!dc_isar_feature(aa32_fpshvec, s) &&
1573         (veclen != 0 || s->vec_stride != 0)) {
1574         return false;
1575     }
1576
1577     if (!vfp_access_check(s)) {
1578         return true;
1579     }
1580
1581     if (veclen > 0) {
1582         /* Figure out what type of vector operation this is.  */
1583         if (vfp_dreg_is_scalar(vd)) {
1584             /* scalar */
1585             veclen = 0;
1586         } else {
1587             delta_d = (s->vec_stride >> 1) + 1;
1588
1589             if (vfp_dreg_is_scalar(vm)) {
1590                 /* mixed scalar/vector */
1591                 delta_m = 0;
1592             } else {
1593                 /* vector */
1594                 delta_m = delta_d;
1595             }
1596         }
1597     }
1598
1599     f0 = tcg_temp_new_i64();
1600     fd = tcg_temp_new_i64();
1601
1602     vfp_load_reg64(f0, vm);
1603
1604     for (;;) {
1605         fn(fd, f0);
1606         vfp_store_reg64(fd, vd);
1607
1608         if (veclen == 0) {
1609             break;
1610         }
1611
1612         if (delta_m == 0) {
1613             /* single source one-many */
1614             while (veclen--) {
1615                 vd = vfp_advance_dreg(vd, delta_d);
1616                 vfp_store_reg64(fd, vd);
1617             }
1618             break;
1619         }
1620
1621         /* Set up the operands for the next iteration */
1622         veclen--;
1623         vd = vfp_advance_dreg(vd, delta_d);
1624         vd = vfp_advance_dreg(vm, delta_m);
1625         vfp_load_reg64(f0, vm);
1626     }
1627
1628     tcg_temp_free_i64(f0);
1629     tcg_temp_free_i64(fd);
1630
1631     return true;
1632 }
1633
1634 static void gen_VMLA_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1635 {
1636     /* Note that order of inputs to the add matters for NaNs */
1637     TCGv_i32 tmp = tcg_temp_new_i32();
1638
1639     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1640     gen_helper_vfp_addh(vd, vd, tmp, fpst);
1641     tcg_temp_free_i32(tmp);
1642 }
1643
1644 static bool trans_VMLA_hp(DisasContext *s, arg_VMLA_sp *a)
1645 {
1646     return do_vfp_3op_hp(s, gen_VMLA_hp, a->vd, a->vn, a->vm, true);
1647 }
1648
1649 static void gen_VMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1650 {
1651     /* Note that order of inputs to the add matters for NaNs */
1652     TCGv_i32 tmp = tcg_temp_new_i32();
1653
1654     gen_helper_vfp_muls(tmp, vn, vm, fpst);
1655     gen_helper_vfp_adds(vd, vd, tmp, fpst);
1656     tcg_temp_free_i32(tmp);
1657 }
1658
1659 static bool trans_VMLA_sp(DisasContext *s, arg_VMLA_sp *a)
1660 {
1661     return do_vfp_3op_sp(s, gen_VMLA_sp, a->vd, a->vn, a->vm, true);
1662 }
1663
1664 static void gen_VMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1665 {
1666     /* Note that order of inputs to the add matters for NaNs */
1667     TCGv_i64 tmp = tcg_temp_new_i64();
1668
1669     gen_helper_vfp_muld(tmp, vn, vm, fpst);
1670     gen_helper_vfp_addd(vd, vd, tmp, fpst);
1671     tcg_temp_free_i64(tmp);
1672 }
1673
1674 static bool trans_VMLA_dp(DisasContext *s, arg_VMLA_dp *a)
1675 {
1676     return do_vfp_3op_dp(s, gen_VMLA_dp, a->vd, a->vn, a->vm, true);
1677 }
1678
1679 static void gen_VMLS_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1680 {
1681     /*
1682      * VMLS: vd = vd + -(vn * vm)
1683      * Note that order of inputs to the add matters for NaNs.
1684      */
1685     TCGv_i32 tmp = tcg_temp_new_i32();
1686
1687     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1688     gen_helper_vfp_negh(tmp, tmp);
1689     gen_helper_vfp_addh(vd, vd, tmp, fpst);
1690     tcg_temp_free_i32(tmp);
1691 }
1692
1693 static bool trans_VMLS_hp(DisasContext *s, arg_VMLS_sp *a)
1694 {
1695     return do_vfp_3op_hp(s, gen_VMLS_hp, a->vd, a->vn, a->vm, true);
1696 }
1697
1698 static void gen_VMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1699 {
1700     /*
1701      * VMLS: vd = vd + -(vn * vm)
1702      * Note that order of inputs to the add matters for NaNs.
1703      */
1704     TCGv_i32 tmp = tcg_temp_new_i32();
1705
1706     gen_helper_vfp_muls(tmp, vn, vm, fpst);
1707     gen_helper_vfp_negs(tmp, tmp);
1708     gen_helper_vfp_adds(vd, vd, tmp, fpst);
1709     tcg_temp_free_i32(tmp);
1710 }
1711
1712 static bool trans_VMLS_sp(DisasContext *s, arg_VMLS_sp *a)
1713 {
1714     return do_vfp_3op_sp(s, gen_VMLS_sp, a->vd, a->vn, a->vm, true);
1715 }
1716
1717 static void gen_VMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1718 {
1719     /*
1720      * VMLS: vd = vd + -(vn * vm)
1721      * Note that order of inputs to the add matters for NaNs.
1722      */
1723     TCGv_i64 tmp = tcg_temp_new_i64();
1724
1725     gen_helper_vfp_muld(tmp, vn, vm, fpst);
1726     gen_helper_vfp_negd(tmp, tmp);
1727     gen_helper_vfp_addd(vd, vd, tmp, fpst);
1728     tcg_temp_free_i64(tmp);
1729 }
1730
1731 static bool trans_VMLS_dp(DisasContext *s, arg_VMLS_dp *a)
1732 {
1733     return do_vfp_3op_dp(s, gen_VMLS_dp, a->vd, a->vn, a->vm, true);
1734 }
1735
1736 static void gen_VNMLS_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1737 {
1738     /*
1739      * VNMLS: -fd + (fn * fm)
1740      * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1741      * plausible looking simplifications because this will give wrong results
1742      * for NaNs.
1743      */
1744     TCGv_i32 tmp = tcg_temp_new_i32();
1745
1746     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1747     gen_helper_vfp_negh(vd, vd);
1748     gen_helper_vfp_addh(vd, vd, tmp, fpst);
1749     tcg_temp_free_i32(tmp);
1750 }
1751
1752 static bool trans_VNMLS_hp(DisasContext *s, arg_VNMLS_sp *a)
1753 {
1754     return do_vfp_3op_hp(s, gen_VNMLS_hp, a->vd, a->vn, a->vm, true);
1755 }
1756
1757 static void gen_VNMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1758 {
1759     /*
1760      * VNMLS: -fd + (fn * fm)
1761      * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1762      * plausible looking simplifications because this will give wrong results
1763      * for NaNs.
1764      */
1765     TCGv_i32 tmp = tcg_temp_new_i32();
1766
1767     gen_helper_vfp_muls(tmp, vn, vm, fpst);
1768     gen_helper_vfp_negs(vd, vd);
1769     gen_helper_vfp_adds(vd, vd, tmp, fpst);
1770     tcg_temp_free_i32(tmp);
1771 }
1772
1773 static bool trans_VNMLS_sp(DisasContext *s, arg_VNMLS_sp *a)
1774 {
1775     return do_vfp_3op_sp(s, gen_VNMLS_sp, a->vd, a->vn, a->vm, true);
1776 }
1777
1778 static void gen_VNMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1779 {
1780     /*
1781      * VNMLS: -fd + (fn * fm)
1782      * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1783      * plausible looking simplifications because this will give wrong results
1784      * for NaNs.
1785      */
1786     TCGv_i64 tmp = tcg_temp_new_i64();
1787
1788     gen_helper_vfp_muld(tmp, vn, vm, fpst);
1789     gen_helper_vfp_negd(vd, vd);
1790     gen_helper_vfp_addd(vd, vd, tmp, fpst);
1791     tcg_temp_free_i64(tmp);
1792 }
1793
1794 static bool trans_VNMLS_dp(DisasContext *s, arg_VNMLS_dp *a)
1795 {
1796     return do_vfp_3op_dp(s, gen_VNMLS_dp, a->vd, a->vn, a->vm, true);
1797 }
1798
1799 static void gen_VNMLA_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1800 {
1801     /* VNMLA: -fd + -(fn * fm) */
1802     TCGv_i32 tmp = tcg_temp_new_i32();
1803
1804     gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1805     gen_helper_vfp_negh(tmp, tmp);
1806     gen_helper_vfp_negh(vd, vd);
1807     gen_helper_vfp_addh(vd, vd, tmp, fpst);
1808     tcg_temp_free_i32(tmp);
1809 }
1810
1811 static bool trans_VNMLA_hp(DisasContext *s, arg_VNMLA_sp *a)
1812 {
1813     return do_vfp_3op_hp(s, gen_VNMLA_hp, a->vd, a->vn, a->vm, true);
1814 }
1815
1816 static void gen_VNMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1817 {
1818     /* VNMLA: -fd + -(fn * fm) */
1819     TCGv_i32 tmp = tcg_temp_new_i32();
1820
1821     gen_helper_vfp_muls(tmp, vn, vm, fpst);
1822     gen_helper_vfp_negs(tmp, tmp);
1823     gen_helper_vfp_negs(vd, vd);
1824     gen_helper_vfp_adds(vd, vd, tmp, fpst);
1825     tcg_temp_free_i32(tmp);
1826 }
1827
1828 static bool trans_VNMLA_sp(DisasContext *s, arg_VNMLA_sp *a)
1829 {
1830     return do_vfp_3op_sp(s, gen_VNMLA_sp, a->vd, a->vn, a->vm, true);
1831 }
1832
1833 static void gen_VNMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1834 {
1835     /* VNMLA: -fd + (fn * fm) */
1836     TCGv_i64 tmp = tcg_temp_new_i64();
1837
1838     gen_helper_vfp_muld(tmp, vn, vm, fpst);
1839     gen_helper_vfp_negd(tmp, tmp);
1840     gen_helper_vfp_negd(vd, vd);
1841     gen_helper_vfp_addd(vd, vd, tmp, fpst);
1842     tcg_temp_free_i64(tmp);
1843 }
1844
1845 static bool trans_VNMLA_dp(DisasContext *s, arg_VNMLA_dp *a)
1846 {
1847     return do_vfp_3op_dp(s, gen_VNMLA_dp, a->vd, a->vn, a->vm, true);
1848 }
1849
1850 static bool trans_VMUL_hp(DisasContext *s, arg_VMUL_sp *a)
1851 {
1852     return do_vfp_3op_hp(s, gen_helper_vfp_mulh, a->vd, a->vn, a->vm, false);
1853 }
1854
1855 static bool trans_VMUL_sp(DisasContext *s, arg_VMUL_sp *a)
1856 {
1857     return do_vfp_3op_sp(s, gen_helper_vfp_muls, a->vd, a->vn, a->vm, false);
1858 }
1859
1860 static bool trans_VMUL_dp(DisasContext *s, arg_VMUL_dp *a)
1861 {
1862     return do_vfp_3op_dp(s, gen_helper_vfp_muld, a->vd, a->vn, a->vm, false);
1863 }
1864
1865 static void gen_VNMUL_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1866 {
1867     /* VNMUL: -(fn * fm) */
1868     gen_helper_vfp_mulh(vd, vn, vm, fpst);
1869     gen_helper_vfp_negh(vd, vd);
1870 }
1871
1872 static bool trans_VNMUL_hp(DisasContext *s, arg_VNMUL_sp *a)
1873 {
1874     return do_vfp_3op_hp(s, gen_VNMUL_hp, a->vd, a->vn, a->vm, false);
1875 }
1876
1877 static void gen_VNMUL_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1878 {
1879     /* VNMUL: -(fn * fm) */
1880     gen_helper_vfp_muls(vd, vn, vm, fpst);
1881     gen_helper_vfp_negs(vd, vd);
1882 }
1883
1884 static bool trans_VNMUL_sp(DisasContext *s, arg_VNMUL_sp *a)
1885 {
1886     return do_vfp_3op_sp(s, gen_VNMUL_sp, a->vd, a->vn, a->vm, false);
1887 }
1888
1889 static void gen_VNMUL_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1890 {
1891     /* VNMUL: -(fn * fm) */
1892     gen_helper_vfp_muld(vd, vn, vm, fpst);
1893     gen_helper_vfp_negd(vd, vd);
1894 }
1895
1896 static bool trans_VNMUL_dp(DisasContext *s, arg_VNMUL_dp *a)
1897 {
1898     return do_vfp_3op_dp(s, gen_VNMUL_dp, a->vd, a->vn, a->vm, false);
1899 }
1900
1901 static bool trans_VADD_hp(DisasContext *s, arg_VADD_sp *a)
1902 {
1903     return do_vfp_3op_hp(s, gen_helper_vfp_addh, a->vd, a->vn, a->vm, false);
1904 }
1905
1906 static bool trans_VADD_sp(DisasContext *s, arg_VADD_sp *a)
1907 {
1908     return do_vfp_3op_sp(s, gen_helper_vfp_adds, a->vd, a->vn, a->vm, false);
1909 }
1910
1911 static bool trans_VADD_dp(DisasContext *s, arg_VADD_dp *a)
1912 {
1913     return do_vfp_3op_dp(s, gen_helper_vfp_addd, a->vd, a->vn, a->vm, false);
1914 }
1915
1916 static bool trans_VSUB_hp(DisasContext *s, arg_VSUB_sp *a)
1917 {
1918     return do_vfp_3op_hp(s, gen_helper_vfp_subh, a->vd, a->vn, a->vm, false);
1919 }
1920
1921 static bool trans_VSUB_sp(DisasContext *s, arg_VSUB_sp *a)
1922 {
1923     return do_vfp_3op_sp(s, gen_helper_vfp_subs, a->vd, a->vn, a->vm, false);
1924 }
1925
1926 static bool trans_VSUB_dp(DisasContext *s, arg_VSUB_dp *a)
1927 {
1928     return do_vfp_3op_dp(s, gen_helper_vfp_subd, a->vd, a->vn, a->vm, false);
1929 }
1930
1931 static bool trans_VDIV_hp(DisasContext *s, arg_VDIV_sp *a)
1932 {
1933     return do_vfp_3op_hp(s, gen_helper_vfp_divh, a->vd, a->vn, a->vm, false);
1934 }
1935
1936 static bool trans_VDIV_sp(DisasContext *s, arg_VDIV_sp *a)
1937 {
1938     return do_vfp_3op_sp(s, gen_helper_vfp_divs, a->vd, a->vn, a->vm, false);
1939 }
1940
1941 static bool trans_VDIV_dp(DisasContext *s, arg_VDIV_dp *a)
1942 {
1943     return do_vfp_3op_dp(s, gen_helper_vfp_divd, a->vd, a->vn, a->vm, false);
1944 }
1945
1946 static bool trans_VMINNM_hp(DisasContext *s, arg_VMINNM_sp *a)
1947 {
1948     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1949         return false;
1950     }
1951     return do_vfp_3op_hp(s, gen_helper_vfp_minnumh,
1952                          a->vd, a->vn, a->vm, false);
1953 }
1954
1955 static bool trans_VMAXNM_hp(DisasContext *s, arg_VMAXNM_sp *a)
1956 {
1957     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1958         return false;
1959     }
1960     return do_vfp_3op_hp(s, gen_helper_vfp_maxnumh,
1961                          a->vd, a->vn, a->vm, false);
1962 }
1963
1964 static bool trans_VMINNM_sp(DisasContext *s, arg_VMINNM_sp *a)
1965 {
1966     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1967         return false;
1968     }
1969     return do_vfp_3op_sp(s, gen_helper_vfp_minnums,
1970                          a->vd, a->vn, a->vm, false);
1971 }
1972
1973 static bool trans_VMAXNM_sp(DisasContext *s, arg_VMAXNM_sp *a)
1974 {
1975     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1976         return false;
1977     }
1978     return do_vfp_3op_sp(s, gen_helper_vfp_maxnums,
1979                          a->vd, a->vn, a->vm, false);
1980 }
1981
1982 static bool trans_VMINNM_dp(DisasContext *s, arg_VMINNM_dp *a)
1983 {
1984     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1985         return false;
1986     }
1987     return do_vfp_3op_dp(s, gen_helper_vfp_minnumd,
1988                          a->vd, a->vn, a->vm, false);
1989 }
1990
1991 static bool trans_VMAXNM_dp(DisasContext *s, arg_VMAXNM_dp *a)
1992 {
1993     if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1994         return false;
1995     }
1996     return do_vfp_3op_dp(s, gen_helper_vfp_maxnumd,
1997                          a->vd, a->vn, a->vm, false);
1998 }
1999
2000 static bool do_vfm_hp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
2001 {
2002     /*
2003      * VFNMA : fd = muladd(-fd,  fn, fm)
2004      * VFNMS : fd = muladd(-fd, -fn, fm)
2005      * VFMA  : fd = muladd( fd,  fn, fm)
2006      * VFMS  : fd = muladd( fd, -fn, fm)
2007      *
2008      * These are fused multiply-add, and must be done as one floating
2009      * point operation with no rounding between the multiplication and
2010      * addition steps.  NB that doing the negations here as separate
2011      * steps is correct : an input NaN should come out with its sign
2012      * bit flipped if it is a negated-input.
2013      */
2014     TCGv_ptr fpst;
2015     TCGv_i32 vn, vm, vd;
2016
2017     /*
2018      * Present in VFPv4 only, and only with the FP16 extension.
2019      * Note that we can't rely on the SIMDFMAC check alone, because
2020      * in a Neon-no-VFP core that ID register field will be non-zero.
2021      */
2022     if (!dc_isar_feature(aa32_fp16_arith, s) ||
2023         !dc_isar_feature(aa32_simdfmac, s) ||
2024         !dc_isar_feature(aa32_fpsp_v2, s)) {
2025         return false;
2026     }
2027
2028     if (s->vec_len != 0 || s->vec_stride != 0) {
2029         return false;
2030     }
2031
2032     if (!vfp_access_check(s)) {
2033         return true;
2034     }
2035
2036     vn = tcg_temp_new_i32();
2037     vm = tcg_temp_new_i32();
2038     vd = tcg_temp_new_i32();
2039
2040     vfp_load_reg32(vn, a->vn);
2041     vfp_load_reg32(vm, a->vm);
2042     if (neg_n) {
2043         /* VFNMS, VFMS */
2044         gen_helper_vfp_negh(vn, vn);
2045     }
2046     vfp_load_reg32(vd, a->vd);
2047     if (neg_d) {
2048         /* VFNMA, VFNMS */
2049         gen_helper_vfp_negh(vd, vd);
2050     }
2051     fpst = fpstatus_ptr(FPST_FPCR_F16);
2052     gen_helper_vfp_muladdh(vd, vn, vm, vd, fpst);
2053     vfp_store_reg32(vd, a->vd);
2054
2055     tcg_temp_free_ptr(fpst);
2056     tcg_temp_free_i32(vn);
2057     tcg_temp_free_i32(vm);
2058     tcg_temp_free_i32(vd);
2059
2060     return true;
2061 }
2062
2063 static bool do_vfm_sp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
2064 {
2065     /*
2066      * VFNMA : fd = muladd(-fd,  fn, fm)
2067      * VFNMS : fd = muladd(-fd, -fn, fm)
2068      * VFMA  : fd = muladd( fd,  fn, fm)
2069      * VFMS  : fd = muladd( fd, -fn, fm)
2070      *
2071      * These are fused multiply-add, and must be done as one floating
2072      * point operation with no rounding between the multiplication and
2073      * addition steps.  NB that doing the negations here as separate
2074      * steps is correct : an input NaN should come out with its sign
2075      * bit flipped if it is a negated-input.
2076      */
2077     TCGv_ptr fpst;
2078     TCGv_i32 vn, vm, vd;
2079
2080     /*
2081      * Present in VFPv4 only.
2082      * Note that we can't rely on the SIMDFMAC check alone, because
2083      * in a Neon-no-VFP core that ID register field will be non-zero.
2084      */
2085     if (!dc_isar_feature(aa32_simdfmac, s) ||
2086         !dc_isar_feature(aa32_fpsp_v2, s)) {
2087         return false;
2088     }
2089     /*
2090      * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
2091      * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
2092      */
2093     if (s->vec_len != 0 || s->vec_stride != 0) {
2094         return false;
2095     }
2096
2097     if (!vfp_access_check(s)) {
2098         return true;
2099     }
2100
2101     vn = tcg_temp_new_i32();
2102     vm = tcg_temp_new_i32();
2103     vd = tcg_temp_new_i32();
2104
2105     vfp_load_reg32(vn, a->vn);
2106     vfp_load_reg32(vm, a->vm);
2107     if (neg_n) {
2108         /* VFNMS, VFMS */
2109         gen_helper_vfp_negs(vn, vn);
2110     }
2111     vfp_load_reg32(vd, a->vd);
2112     if (neg_d) {
2113         /* VFNMA, VFNMS */
2114         gen_helper_vfp_negs(vd, vd);
2115     }
2116     fpst = fpstatus_ptr(FPST_FPCR);
2117     gen_helper_vfp_muladds(vd, vn, vm, vd, fpst);
2118     vfp_store_reg32(vd, a->vd);
2119
2120     tcg_temp_free_ptr(fpst);
2121     tcg_temp_free_i32(vn);
2122     tcg_temp_free_i32(vm);
2123     tcg_temp_free_i32(vd);
2124
2125     return true;
2126 }
2127
2128 static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d)
2129 {
2130     /*
2131      * VFNMA : fd = muladd(-fd,  fn, fm)
2132      * VFNMS : fd = muladd(-fd, -fn, fm)
2133      * VFMA  : fd = muladd( fd,  fn, fm)
2134      * VFMS  : fd = muladd( fd, -fn, fm)
2135      *
2136      * These are fused multiply-add, and must be done as one floating
2137      * point operation with no rounding between the multiplication and
2138      * addition steps.  NB that doing the negations here as separate
2139      * steps is correct : an input NaN should come out with its sign
2140      * bit flipped if it is a negated-input.
2141      */
2142     TCGv_ptr fpst;
2143     TCGv_i64 vn, vm, vd;
2144
2145     /*
2146      * Present in VFPv4 only.
2147      * Note that we can't rely on the SIMDFMAC check alone, because
2148      * in a Neon-no-VFP core that ID register field will be non-zero.
2149      */
2150     if (!dc_isar_feature(aa32_simdfmac, s) ||
2151         !dc_isar_feature(aa32_fpdp_v2, s)) {
2152         return false;
2153     }
2154     /*
2155      * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
2156      * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
2157      */
2158     if (s->vec_len != 0 || s->vec_stride != 0) {
2159         return false;
2160     }
2161
2162     /* UNDEF accesses to D16-D31 if they don't exist. */
2163     if (!dc_isar_feature(aa32_simd_r32, s) &&
2164         ((a->vd | a->vn | a->vm) & 0x10)) {
2165         return false;
2166     }
2167
2168     if (!vfp_access_check(s)) {
2169         return true;
2170     }
2171
2172     vn = tcg_temp_new_i64();
2173     vm = tcg_temp_new_i64();
2174     vd = tcg_temp_new_i64();
2175
2176     vfp_load_reg64(vn, a->vn);
2177     vfp_load_reg64(vm, a->vm);
2178     if (neg_n) {
2179         /* VFNMS, VFMS */
2180         gen_helper_vfp_negd(vn, vn);
2181     }
2182     vfp_load_reg64(vd, a->vd);
2183     if (neg_d) {
2184         /* VFNMA, VFNMS */
2185         gen_helper_vfp_negd(vd, vd);
2186     }
2187     fpst = fpstatus_ptr(FPST_FPCR);
2188     gen_helper_vfp_muladdd(vd, vn, vm, vd, fpst);
2189     vfp_store_reg64(vd, a->vd);
2190
2191     tcg_temp_free_ptr(fpst);
2192     tcg_temp_free_i64(vn);
2193     tcg_temp_free_i64(vm);
2194     tcg_temp_free_i64(vd);
2195
2196     return true;
2197 }
2198
2199 #define MAKE_ONE_VFM_TRANS_FN(INSN, PREC, NEGN, NEGD)                   \
2200     static bool trans_##INSN##_##PREC(DisasContext *s,                  \
2201                                       arg_##INSN##_##PREC *a)           \
2202     {                                                                   \
2203         return do_vfm_##PREC(s, a, NEGN, NEGD);                         \
2204     }
2205
2206 #define MAKE_VFM_TRANS_FNS(PREC) \
2207     MAKE_ONE_VFM_TRANS_FN(VFMA, PREC, false, false) \
2208     MAKE_ONE_VFM_TRANS_FN(VFMS, PREC, true, false) \
2209     MAKE_ONE_VFM_TRANS_FN(VFNMA, PREC, false, true) \
2210     MAKE_ONE_VFM_TRANS_FN(VFNMS, PREC, true, true)
2211
2212 MAKE_VFM_TRANS_FNS(hp)
2213 MAKE_VFM_TRANS_FNS(sp)
2214 MAKE_VFM_TRANS_FNS(dp)
2215
2216 static bool trans_VMOV_imm_hp(DisasContext *s, arg_VMOV_imm_sp *a)
2217 {
2218     TCGv_i32 fd;
2219
2220     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2221         return false;
2222     }
2223
2224     if (s->vec_len != 0 || s->vec_stride != 0) {
2225         return false;
2226     }
2227
2228     if (!vfp_access_check(s)) {
2229         return true;
2230     }
2231
2232     fd = tcg_const_i32(vfp_expand_imm(MO_16, a->imm));
2233     vfp_store_reg32(fd, a->vd);
2234     tcg_temp_free_i32(fd);
2235     return true;
2236 }
2237
2238 static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
2239 {
2240     uint32_t delta_d = 0;
2241     int veclen = s->vec_len;
2242     TCGv_i32 fd;
2243     uint32_t vd;
2244
2245     vd = a->vd;
2246
2247     if (!dc_isar_feature(aa32_fpsp_v3, s)) {
2248         return false;
2249     }
2250
2251     if (!dc_isar_feature(aa32_fpshvec, s) &&
2252         (veclen != 0 || s->vec_stride != 0)) {
2253         return false;
2254     }
2255
2256     if (!vfp_access_check(s)) {
2257         return true;
2258     }
2259
2260     if (veclen > 0) {
2261         /* Figure out what type of vector operation this is.  */
2262         if (vfp_sreg_is_scalar(vd)) {
2263             /* scalar */
2264             veclen = 0;
2265         } else {
2266             delta_d = s->vec_stride + 1;
2267         }
2268     }
2269
2270     fd = tcg_const_i32(vfp_expand_imm(MO_32, a->imm));
2271
2272     for (;;) {
2273         vfp_store_reg32(fd, vd);
2274
2275         if (veclen == 0) {
2276             break;
2277         }
2278
2279         /* Set up the operands for the next iteration */
2280         veclen--;
2281         vd = vfp_advance_sreg(vd, delta_d);
2282     }
2283
2284     tcg_temp_free_i32(fd);
2285     return true;
2286 }
2287
2288 static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
2289 {
2290     uint32_t delta_d = 0;
2291     int veclen = s->vec_len;
2292     TCGv_i64 fd;
2293     uint32_t vd;
2294
2295     vd = a->vd;
2296
2297     if (!dc_isar_feature(aa32_fpdp_v3, s)) {
2298         return false;
2299     }
2300
2301     /* UNDEF accesses to D16-D31 if they don't exist. */
2302     if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) {
2303         return false;
2304     }
2305
2306     if (!dc_isar_feature(aa32_fpshvec, s) &&
2307         (veclen != 0 || s->vec_stride != 0)) {
2308         return false;
2309     }
2310
2311     if (!vfp_access_check(s)) {
2312         return true;
2313     }
2314
2315     if (veclen > 0) {
2316         /* Figure out what type of vector operation this is.  */
2317         if (vfp_dreg_is_scalar(vd)) {
2318             /* scalar */
2319             veclen = 0;
2320         } else {
2321             delta_d = (s->vec_stride >> 1) + 1;
2322         }
2323     }
2324
2325     fd = tcg_const_i64(vfp_expand_imm(MO_64, a->imm));
2326
2327     for (;;) {
2328         vfp_store_reg64(fd, vd);
2329
2330         if (veclen == 0) {
2331             break;
2332         }
2333
2334         /* Set up the operands for the next iteration */
2335         veclen--;
2336         vd = vfp_advance_dreg(vd, delta_d);
2337     }
2338
2339     tcg_temp_free_i64(fd);
2340     return true;
2341 }
2342
2343 #define DO_VFP_2OP(INSN, PREC, FN)                              \
2344     static bool trans_##INSN##_##PREC(DisasContext *s,          \
2345                                       arg_##INSN##_##PREC *a)   \
2346     {                                                           \
2347         return do_vfp_2op_##PREC(s, FN, a->vd, a->vm);          \
2348     }
2349
2350 DO_VFP_2OP(VMOV_reg, sp, tcg_gen_mov_i32)
2351 DO_VFP_2OP(VMOV_reg, dp, tcg_gen_mov_i64)
2352
2353 DO_VFP_2OP(VABS, hp, gen_helper_vfp_absh)
2354 DO_VFP_2OP(VABS, sp, gen_helper_vfp_abss)
2355 DO_VFP_2OP(VABS, dp, gen_helper_vfp_absd)
2356
2357 DO_VFP_2OP(VNEG, hp, gen_helper_vfp_negh)
2358 DO_VFP_2OP(VNEG, sp, gen_helper_vfp_negs)
2359 DO_VFP_2OP(VNEG, dp, gen_helper_vfp_negd)
2360
2361 static void gen_VSQRT_hp(TCGv_i32 vd, TCGv_i32 vm)
2362 {
2363     gen_helper_vfp_sqrth(vd, vm, cpu_env);
2364 }
2365
2366 static void gen_VSQRT_sp(TCGv_i32 vd, TCGv_i32 vm)
2367 {
2368     gen_helper_vfp_sqrts(vd, vm, cpu_env);
2369 }
2370
2371 static void gen_VSQRT_dp(TCGv_i64 vd, TCGv_i64 vm)
2372 {
2373     gen_helper_vfp_sqrtd(vd, vm, cpu_env);
2374 }
2375
2376 DO_VFP_2OP(VSQRT, hp, gen_VSQRT_hp)
2377 DO_VFP_2OP(VSQRT, sp, gen_VSQRT_sp)
2378 DO_VFP_2OP(VSQRT, dp, gen_VSQRT_dp)
2379
2380 static bool trans_VCMP_hp(DisasContext *s, arg_VCMP_sp *a)
2381 {
2382     TCGv_i32 vd, vm;
2383
2384     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2385         return false;
2386     }
2387
2388     /* Vm/M bits must be zero for the Z variant */
2389     if (a->z && a->vm != 0) {
2390         return false;
2391     }
2392
2393     if (!vfp_access_check(s)) {
2394         return true;
2395     }
2396
2397     vd = tcg_temp_new_i32();
2398     vm = tcg_temp_new_i32();
2399
2400     vfp_load_reg32(vd, a->vd);
2401     if (a->z) {
2402         tcg_gen_movi_i32(vm, 0);
2403     } else {
2404         vfp_load_reg32(vm, a->vm);
2405     }
2406
2407     if (a->e) {
2408         gen_helper_vfp_cmpeh(vd, vm, cpu_env);
2409     } else {
2410         gen_helper_vfp_cmph(vd, vm, cpu_env);
2411     }
2412
2413     tcg_temp_free_i32(vd);
2414     tcg_temp_free_i32(vm);
2415
2416     return true;
2417 }
2418
2419 static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a)
2420 {
2421     TCGv_i32 vd, vm;
2422
2423     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2424         return false;
2425     }
2426
2427     /* Vm/M bits must be zero for the Z variant */
2428     if (a->z && a->vm != 0) {
2429         return false;
2430     }
2431
2432     if (!vfp_access_check(s)) {
2433         return true;
2434     }
2435
2436     vd = tcg_temp_new_i32();
2437     vm = tcg_temp_new_i32();
2438
2439     vfp_load_reg32(vd, a->vd);
2440     if (a->z) {
2441         tcg_gen_movi_i32(vm, 0);
2442     } else {
2443         vfp_load_reg32(vm, a->vm);
2444     }
2445
2446     if (a->e) {
2447         gen_helper_vfp_cmpes(vd, vm, cpu_env);
2448     } else {
2449         gen_helper_vfp_cmps(vd, vm, cpu_env);
2450     }
2451
2452     tcg_temp_free_i32(vd);
2453     tcg_temp_free_i32(vm);
2454
2455     return true;
2456 }
2457
2458 static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a)
2459 {
2460     TCGv_i64 vd, vm;
2461
2462     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2463         return false;
2464     }
2465
2466     /* Vm/M bits must be zero for the Z variant */
2467     if (a->z && a->vm != 0) {
2468         return false;
2469     }
2470
2471     /* UNDEF accesses to D16-D31 if they don't exist. */
2472     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
2473         return false;
2474     }
2475
2476     if (!vfp_access_check(s)) {
2477         return true;
2478     }
2479
2480     vd = tcg_temp_new_i64();
2481     vm = tcg_temp_new_i64();
2482
2483     vfp_load_reg64(vd, a->vd);
2484     if (a->z) {
2485         tcg_gen_movi_i64(vm, 0);
2486     } else {
2487         vfp_load_reg64(vm, a->vm);
2488     }
2489
2490     if (a->e) {
2491         gen_helper_vfp_cmped(vd, vm, cpu_env);
2492     } else {
2493         gen_helper_vfp_cmpd(vd, vm, cpu_env);
2494     }
2495
2496     tcg_temp_free_i64(vd);
2497     tcg_temp_free_i64(vm);
2498
2499     return true;
2500 }
2501
2502 static bool trans_VCVT_f32_f16(DisasContext *s, arg_VCVT_f32_f16 *a)
2503 {
2504     TCGv_ptr fpst;
2505     TCGv_i32 ahp_mode;
2506     TCGv_i32 tmp;
2507
2508     if (!dc_isar_feature(aa32_fp16_spconv, s)) {
2509         return false;
2510     }
2511
2512     if (!vfp_access_check(s)) {
2513         return true;
2514     }
2515
2516     fpst = fpstatus_ptr(FPST_FPCR);
2517     ahp_mode = get_ahp_flag();
2518     tmp = tcg_temp_new_i32();
2519     /* The T bit tells us if we want the low or high 16 bits of Vm */
2520     tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t));
2521     gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp_mode);
2522     vfp_store_reg32(tmp, a->vd);
2523     tcg_temp_free_i32(ahp_mode);
2524     tcg_temp_free_ptr(fpst);
2525     tcg_temp_free_i32(tmp);
2526     return true;
2527 }
2528
2529 static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a)
2530 {
2531     TCGv_ptr fpst;
2532     TCGv_i32 ahp_mode;
2533     TCGv_i32 tmp;
2534     TCGv_i64 vd;
2535
2536     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2537         return false;
2538     }
2539
2540     if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
2541         return false;
2542     }
2543
2544     /* UNDEF accesses to D16-D31 if they don't exist. */
2545     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd  & 0x10)) {
2546         return false;
2547     }
2548
2549     if (!vfp_access_check(s)) {
2550         return true;
2551     }
2552
2553     fpst = fpstatus_ptr(FPST_FPCR);
2554     ahp_mode = get_ahp_flag();
2555     tmp = tcg_temp_new_i32();
2556     /* The T bit tells us if we want the low or high 16 bits of Vm */
2557     tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t));
2558     vd = tcg_temp_new_i64();
2559     gen_helper_vfp_fcvt_f16_to_f64(vd, tmp, fpst, ahp_mode);
2560     vfp_store_reg64(vd, a->vd);
2561     tcg_temp_free_i32(ahp_mode);
2562     tcg_temp_free_ptr(fpst);
2563     tcg_temp_free_i32(tmp);
2564     tcg_temp_free_i64(vd);
2565     return true;
2566 }
2567
2568 static bool trans_VCVT_f16_f32(DisasContext *s, arg_VCVT_f16_f32 *a)
2569 {
2570     TCGv_ptr fpst;
2571     TCGv_i32 ahp_mode;
2572     TCGv_i32 tmp;
2573
2574     if (!dc_isar_feature(aa32_fp16_spconv, s)) {
2575         return false;
2576     }
2577
2578     if (!vfp_access_check(s)) {
2579         return true;
2580     }
2581
2582     fpst = fpstatus_ptr(FPST_FPCR);
2583     ahp_mode = get_ahp_flag();
2584     tmp = tcg_temp_new_i32();
2585
2586     vfp_load_reg32(tmp, a->vm);
2587     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp_mode);
2588     tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t));
2589     tcg_temp_free_i32(ahp_mode);
2590     tcg_temp_free_ptr(fpst);
2591     tcg_temp_free_i32(tmp);
2592     return true;
2593 }
2594
2595 static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a)
2596 {
2597     TCGv_ptr fpst;
2598     TCGv_i32 ahp_mode;
2599     TCGv_i32 tmp;
2600     TCGv_i64 vm;
2601
2602     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2603         return false;
2604     }
2605
2606     if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
2607         return false;
2608     }
2609
2610     /* UNDEF accesses to D16-D31 if they don't exist. */
2611     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm  & 0x10)) {
2612         return false;
2613     }
2614
2615     if (!vfp_access_check(s)) {
2616         return true;
2617     }
2618
2619     fpst = fpstatus_ptr(FPST_FPCR);
2620     ahp_mode = get_ahp_flag();
2621     tmp = tcg_temp_new_i32();
2622     vm = tcg_temp_new_i64();
2623
2624     vfp_load_reg64(vm, a->vm);
2625     gen_helper_vfp_fcvt_f64_to_f16(tmp, vm, fpst, ahp_mode);
2626     tcg_temp_free_i64(vm);
2627     tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t));
2628     tcg_temp_free_i32(ahp_mode);
2629     tcg_temp_free_ptr(fpst);
2630     tcg_temp_free_i32(tmp);
2631     return true;
2632 }
2633
2634 static bool trans_VRINTR_hp(DisasContext *s, arg_VRINTR_sp *a)
2635 {
2636     TCGv_ptr fpst;
2637     TCGv_i32 tmp;
2638
2639     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2640         return false;
2641     }
2642
2643     if (!vfp_access_check(s)) {
2644         return true;
2645     }
2646
2647     tmp = tcg_temp_new_i32();
2648     vfp_load_reg32(tmp, a->vm);
2649     fpst = fpstatus_ptr(FPST_FPCR_F16);
2650     gen_helper_rinth(tmp, tmp, fpst);
2651     vfp_store_reg32(tmp, a->vd);
2652     tcg_temp_free_ptr(fpst);
2653     tcg_temp_free_i32(tmp);
2654     return true;
2655 }
2656
2657 static bool trans_VRINTR_sp(DisasContext *s, arg_VRINTR_sp *a)
2658 {
2659     TCGv_ptr fpst;
2660     TCGv_i32 tmp;
2661
2662     if (!dc_isar_feature(aa32_vrint, s)) {
2663         return false;
2664     }
2665
2666     if (!vfp_access_check(s)) {
2667         return true;
2668     }
2669
2670     tmp = tcg_temp_new_i32();
2671     vfp_load_reg32(tmp, a->vm);
2672     fpst = fpstatus_ptr(FPST_FPCR);
2673     gen_helper_rints(tmp, tmp, fpst);
2674     vfp_store_reg32(tmp, a->vd);
2675     tcg_temp_free_ptr(fpst);
2676     tcg_temp_free_i32(tmp);
2677     return true;
2678 }
2679
2680 static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a)
2681 {
2682     TCGv_ptr fpst;
2683     TCGv_i64 tmp;
2684
2685     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2686         return false;
2687     }
2688
2689     if (!dc_isar_feature(aa32_vrint, s)) {
2690         return false;
2691     }
2692
2693     /* UNDEF accesses to D16-D31 if they don't exist. */
2694     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
2695         return false;
2696     }
2697
2698     if (!vfp_access_check(s)) {
2699         return true;
2700     }
2701
2702     tmp = tcg_temp_new_i64();
2703     vfp_load_reg64(tmp, a->vm);
2704     fpst = fpstatus_ptr(FPST_FPCR);
2705     gen_helper_rintd(tmp, tmp, fpst);
2706     vfp_store_reg64(tmp, a->vd);
2707     tcg_temp_free_ptr(fpst);
2708     tcg_temp_free_i64(tmp);
2709     return true;
2710 }
2711
2712 static bool trans_VRINTZ_hp(DisasContext *s, arg_VRINTZ_sp *a)
2713 {
2714     TCGv_ptr fpst;
2715     TCGv_i32 tmp;
2716     TCGv_i32 tcg_rmode;
2717
2718     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2719         return false;
2720     }
2721
2722     if (!vfp_access_check(s)) {
2723         return true;
2724     }
2725
2726     tmp = tcg_temp_new_i32();
2727     vfp_load_reg32(tmp, a->vm);
2728     fpst = fpstatus_ptr(FPST_FPCR_F16);
2729     tcg_rmode = tcg_const_i32(float_round_to_zero);
2730     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2731     gen_helper_rinth(tmp, tmp, fpst);
2732     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2733     vfp_store_reg32(tmp, a->vd);
2734     tcg_temp_free_ptr(fpst);
2735     tcg_temp_free_i32(tcg_rmode);
2736     tcg_temp_free_i32(tmp);
2737     return true;
2738 }
2739
2740 static bool trans_VRINTZ_sp(DisasContext *s, arg_VRINTZ_sp *a)
2741 {
2742     TCGv_ptr fpst;
2743     TCGv_i32 tmp;
2744     TCGv_i32 tcg_rmode;
2745
2746     if (!dc_isar_feature(aa32_vrint, s)) {
2747         return false;
2748     }
2749
2750     if (!vfp_access_check(s)) {
2751         return true;
2752     }
2753
2754     tmp = tcg_temp_new_i32();
2755     vfp_load_reg32(tmp, a->vm);
2756     fpst = fpstatus_ptr(FPST_FPCR);
2757     tcg_rmode = tcg_const_i32(float_round_to_zero);
2758     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2759     gen_helper_rints(tmp, tmp, fpst);
2760     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2761     vfp_store_reg32(tmp, a->vd);
2762     tcg_temp_free_ptr(fpst);
2763     tcg_temp_free_i32(tcg_rmode);
2764     tcg_temp_free_i32(tmp);
2765     return true;
2766 }
2767
2768 static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a)
2769 {
2770     TCGv_ptr fpst;
2771     TCGv_i64 tmp;
2772     TCGv_i32 tcg_rmode;
2773
2774     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2775         return false;
2776     }
2777
2778     if (!dc_isar_feature(aa32_vrint, s)) {
2779         return false;
2780     }
2781
2782     /* UNDEF accesses to D16-D31 if they don't exist. */
2783     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
2784         return false;
2785     }
2786
2787     if (!vfp_access_check(s)) {
2788         return true;
2789     }
2790
2791     tmp = tcg_temp_new_i64();
2792     vfp_load_reg64(tmp, a->vm);
2793     fpst = fpstatus_ptr(FPST_FPCR);
2794     tcg_rmode = tcg_const_i32(float_round_to_zero);
2795     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2796     gen_helper_rintd(tmp, tmp, fpst);
2797     gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2798     vfp_store_reg64(tmp, a->vd);
2799     tcg_temp_free_ptr(fpst);
2800     tcg_temp_free_i64(tmp);
2801     tcg_temp_free_i32(tcg_rmode);
2802     return true;
2803 }
2804
2805 static bool trans_VRINTX_hp(DisasContext *s, arg_VRINTX_sp *a)
2806 {
2807     TCGv_ptr fpst;
2808     TCGv_i32 tmp;
2809
2810     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2811         return false;
2812     }
2813
2814     if (!vfp_access_check(s)) {
2815         return true;
2816     }
2817
2818     tmp = tcg_temp_new_i32();
2819     vfp_load_reg32(tmp, a->vm);
2820     fpst = fpstatus_ptr(FPST_FPCR_F16);
2821     gen_helper_rinth_exact(tmp, tmp, fpst);
2822     vfp_store_reg32(tmp, a->vd);
2823     tcg_temp_free_ptr(fpst);
2824     tcg_temp_free_i32(tmp);
2825     return true;
2826 }
2827
2828 static bool trans_VRINTX_sp(DisasContext *s, arg_VRINTX_sp *a)
2829 {
2830     TCGv_ptr fpst;
2831     TCGv_i32 tmp;
2832
2833     if (!dc_isar_feature(aa32_vrint, s)) {
2834         return false;
2835     }
2836
2837     if (!vfp_access_check(s)) {
2838         return true;
2839     }
2840
2841     tmp = tcg_temp_new_i32();
2842     vfp_load_reg32(tmp, a->vm);
2843     fpst = fpstatus_ptr(FPST_FPCR);
2844     gen_helper_rints_exact(tmp, tmp, fpst);
2845     vfp_store_reg32(tmp, a->vd);
2846     tcg_temp_free_ptr(fpst);
2847     tcg_temp_free_i32(tmp);
2848     return true;
2849 }
2850
2851 static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a)
2852 {
2853     TCGv_ptr fpst;
2854     TCGv_i64 tmp;
2855
2856     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2857         return false;
2858     }
2859
2860     if (!dc_isar_feature(aa32_vrint, s)) {
2861         return false;
2862     }
2863
2864     /* UNDEF accesses to D16-D31 if they don't exist. */
2865     if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
2866         return false;
2867     }
2868
2869     if (!vfp_access_check(s)) {
2870         return true;
2871     }
2872
2873     tmp = tcg_temp_new_i64();
2874     vfp_load_reg64(tmp, a->vm);
2875     fpst = fpstatus_ptr(FPST_FPCR);
2876     gen_helper_rintd_exact(tmp, tmp, fpst);
2877     vfp_store_reg64(tmp, a->vd);
2878     tcg_temp_free_ptr(fpst);
2879     tcg_temp_free_i64(tmp);
2880     return true;
2881 }
2882
2883 static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a)
2884 {
2885     TCGv_i64 vd;
2886     TCGv_i32 vm;
2887
2888     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2889         return false;
2890     }
2891
2892     /* UNDEF accesses to D16-D31 if they don't exist. */
2893     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
2894         return false;
2895     }
2896
2897     if (!vfp_access_check(s)) {
2898         return true;
2899     }
2900
2901     vm = tcg_temp_new_i32();
2902     vd = tcg_temp_new_i64();
2903     vfp_load_reg32(vm, a->vm);
2904     gen_helper_vfp_fcvtds(vd, vm, cpu_env);
2905     vfp_store_reg64(vd, a->vd);
2906     tcg_temp_free_i32(vm);
2907     tcg_temp_free_i64(vd);
2908     return true;
2909 }
2910
2911 static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a)
2912 {
2913     TCGv_i64 vm;
2914     TCGv_i32 vd;
2915
2916     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2917         return false;
2918     }
2919
2920     /* UNDEF accesses to D16-D31 if they don't exist. */
2921     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
2922         return false;
2923     }
2924
2925     if (!vfp_access_check(s)) {
2926         return true;
2927     }
2928
2929     vd = tcg_temp_new_i32();
2930     vm = tcg_temp_new_i64();
2931     vfp_load_reg64(vm, a->vm);
2932     gen_helper_vfp_fcvtsd(vd, vm, cpu_env);
2933     vfp_store_reg32(vd, a->vd);
2934     tcg_temp_free_i32(vd);
2935     tcg_temp_free_i64(vm);
2936     return true;
2937 }
2938
2939 static bool trans_VCVT_int_hp(DisasContext *s, arg_VCVT_int_sp *a)
2940 {
2941     TCGv_i32 vm;
2942     TCGv_ptr fpst;
2943
2944     if (!dc_isar_feature(aa32_fp16_arith, s)) {
2945         return false;
2946     }
2947
2948     if (!vfp_access_check(s)) {
2949         return true;
2950     }
2951
2952     vm = tcg_temp_new_i32();
2953     vfp_load_reg32(vm, a->vm);
2954     fpst = fpstatus_ptr(FPST_FPCR_F16);
2955     if (a->s) {
2956         /* i32 -> f16 */
2957         gen_helper_vfp_sitoh(vm, vm, fpst);
2958     } else {
2959         /* u32 -> f16 */
2960         gen_helper_vfp_uitoh(vm, vm, fpst);
2961     }
2962     vfp_store_reg32(vm, a->vd);
2963     tcg_temp_free_i32(vm);
2964     tcg_temp_free_ptr(fpst);
2965     return true;
2966 }
2967
2968 static bool trans_VCVT_int_sp(DisasContext *s, arg_VCVT_int_sp *a)
2969 {
2970     TCGv_i32 vm;
2971     TCGv_ptr fpst;
2972
2973     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2974         return false;
2975     }
2976
2977     if (!vfp_access_check(s)) {
2978         return true;
2979     }
2980
2981     vm = tcg_temp_new_i32();
2982     vfp_load_reg32(vm, a->vm);
2983     fpst = fpstatus_ptr(FPST_FPCR);
2984     if (a->s) {
2985         /* i32 -> f32 */
2986         gen_helper_vfp_sitos(vm, vm, fpst);
2987     } else {
2988         /* u32 -> f32 */
2989         gen_helper_vfp_uitos(vm, vm, fpst);
2990     }
2991     vfp_store_reg32(vm, a->vd);
2992     tcg_temp_free_i32(vm);
2993     tcg_temp_free_ptr(fpst);
2994     return true;
2995 }
2996
2997 static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a)
2998 {
2999     TCGv_i32 vm;
3000     TCGv_i64 vd;
3001     TCGv_ptr fpst;
3002
3003     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3004         return false;
3005     }
3006
3007     /* UNDEF accesses to D16-D31 if they don't exist. */
3008     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
3009         return false;
3010     }
3011
3012     if (!vfp_access_check(s)) {
3013         return true;
3014     }
3015
3016     vm = tcg_temp_new_i32();
3017     vd = tcg_temp_new_i64();
3018     vfp_load_reg32(vm, a->vm);
3019     fpst = fpstatus_ptr(FPST_FPCR);
3020     if (a->s) {
3021         /* i32 -> f64 */
3022         gen_helper_vfp_sitod(vd, vm, fpst);
3023     } else {
3024         /* u32 -> f64 */
3025         gen_helper_vfp_uitod(vd, vm, fpst);
3026     }
3027     vfp_store_reg64(vd, a->vd);
3028     tcg_temp_free_i32(vm);
3029     tcg_temp_free_i64(vd);
3030     tcg_temp_free_ptr(fpst);
3031     return true;
3032 }
3033
3034 static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a)
3035 {
3036     TCGv_i32 vd;
3037     TCGv_i64 vm;
3038
3039     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3040         return false;
3041     }
3042
3043     if (!dc_isar_feature(aa32_jscvt, s)) {
3044         return false;
3045     }
3046
3047     /* UNDEF accesses to D16-D31 if they don't exist. */
3048     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
3049         return false;
3050     }
3051
3052     if (!vfp_access_check(s)) {
3053         return true;
3054     }
3055
3056     vm = tcg_temp_new_i64();
3057     vd = tcg_temp_new_i32();
3058     vfp_load_reg64(vm, a->vm);
3059     gen_helper_vjcvt(vd, vm, cpu_env);
3060     vfp_store_reg32(vd, a->vd);
3061     tcg_temp_free_i64(vm);
3062     tcg_temp_free_i32(vd);
3063     return true;
3064 }
3065
3066 static bool trans_VCVT_fix_hp(DisasContext *s, arg_VCVT_fix_sp *a)
3067 {
3068     TCGv_i32 vd, shift;
3069     TCGv_ptr fpst;
3070     int frac_bits;
3071
3072     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3073         return false;
3074     }
3075
3076     if (!vfp_access_check(s)) {
3077         return true;
3078     }
3079
3080     frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
3081
3082     vd = tcg_temp_new_i32();
3083     vfp_load_reg32(vd, a->vd);
3084
3085     fpst = fpstatus_ptr(FPST_FPCR_F16);
3086     shift = tcg_const_i32(frac_bits);
3087
3088     /* Switch on op:U:sx bits */
3089     switch (a->opc) {
3090     case 0:
3091         gen_helper_vfp_shtoh_round_to_nearest(vd, vd, shift, fpst);
3092         break;
3093     case 1:
3094         gen_helper_vfp_sltoh_round_to_nearest(vd, vd, shift, fpst);
3095         break;
3096     case 2:
3097         gen_helper_vfp_uhtoh_round_to_nearest(vd, vd, shift, fpst);
3098         break;
3099     case 3:
3100         gen_helper_vfp_ultoh_round_to_nearest(vd, vd, shift, fpst);
3101         break;
3102     case 4:
3103         gen_helper_vfp_toshh_round_to_zero(vd, vd, shift, fpst);
3104         break;
3105     case 5:
3106         gen_helper_vfp_toslh_round_to_zero(vd, vd, shift, fpst);
3107         break;
3108     case 6:
3109         gen_helper_vfp_touhh_round_to_zero(vd, vd, shift, fpst);
3110         break;
3111     case 7:
3112         gen_helper_vfp_toulh_round_to_zero(vd, vd, shift, fpst);
3113         break;
3114     default:
3115         g_assert_not_reached();
3116     }
3117
3118     vfp_store_reg32(vd, a->vd);
3119     tcg_temp_free_i32(vd);
3120     tcg_temp_free_i32(shift);
3121     tcg_temp_free_ptr(fpst);
3122     return true;
3123 }
3124
3125 static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a)
3126 {
3127     TCGv_i32 vd, shift;
3128     TCGv_ptr fpst;
3129     int frac_bits;
3130
3131     if (!dc_isar_feature(aa32_fpsp_v3, s)) {
3132         return false;
3133     }
3134
3135     if (!vfp_access_check(s)) {
3136         return true;
3137     }
3138
3139     frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
3140
3141     vd = tcg_temp_new_i32();
3142     vfp_load_reg32(vd, a->vd);
3143
3144     fpst = fpstatus_ptr(FPST_FPCR);
3145     shift = tcg_const_i32(frac_bits);
3146
3147     /* Switch on op:U:sx bits */
3148     switch (a->opc) {
3149     case 0:
3150         gen_helper_vfp_shtos_round_to_nearest(vd, vd, shift, fpst);
3151         break;
3152     case 1:
3153         gen_helper_vfp_sltos_round_to_nearest(vd, vd, shift, fpst);
3154         break;
3155     case 2:
3156         gen_helper_vfp_uhtos_round_to_nearest(vd, vd, shift, fpst);
3157         break;
3158     case 3:
3159         gen_helper_vfp_ultos_round_to_nearest(vd, vd, shift, fpst);
3160         break;
3161     case 4:
3162         gen_helper_vfp_toshs_round_to_zero(vd, vd, shift, fpst);
3163         break;
3164     case 5:
3165         gen_helper_vfp_tosls_round_to_zero(vd, vd, shift, fpst);
3166         break;
3167     case 6:
3168         gen_helper_vfp_touhs_round_to_zero(vd, vd, shift, fpst);
3169         break;
3170     case 7:
3171         gen_helper_vfp_touls_round_to_zero(vd, vd, shift, fpst);
3172         break;
3173     default:
3174         g_assert_not_reached();
3175     }
3176
3177     vfp_store_reg32(vd, a->vd);
3178     tcg_temp_free_i32(vd);
3179     tcg_temp_free_i32(shift);
3180     tcg_temp_free_ptr(fpst);
3181     return true;
3182 }
3183
3184 static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
3185 {
3186     TCGv_i64 vd;
3187     TCGv_i32 shift;
3188     TCGv_ptr fpst;
3189     int frac_bits;
3190
3191     if (!dc_isar_feature(aa32_fpdp_v3, s)) {
3192         return false;
3193     }
3194
3195     /* UNDEF accesses to D16-D31 if they don't exist. */
3196     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
3197         return false;
3198     }
3199
3200     if (!vfp_access_check(s)) {
3201         return true;
3202     }
3203
3204     frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
3205
3206     vd = tcg_temp_new_i64();
3207     vfp_load_reg64(vd, a->vd);
3208
3209     fpst = fpstatus_ptr(FPST_FPCR);
3210     shift = tcg_const_i32(frac_bits);
3211
3212     /* Switch on op:U:sx bits */
3213     switch (a->opc) {
3214     case 0:
3215         gen_helper_vfp_shtod_round_to_nearest(vd, vd, shift, fpst);
3216         break;
3217     case 1:
3218         gen_helper_vfp_sltod_round_to_nearest(vd, vd, shift, fpst);
3219         break;
3220     case 2:
3221         gen_helper_vfp_uhtod_round_to_nearest(vd, vd, shift, fpst);
3222         break;
3223     case 3:
3224         gen_helper_vfp_ultod_round_to_nearest(vd, vd, shift, fpst);
3225         break;
3226     case 4:
3227         gen_helper_vfp_toshd_round_to_zero(vd, vd, shift, fpst);
3228         break;
3229     case 5:
3230         gen_helper_vfp_tosld_round_to_zero(vd, vd, shift, fpst);
3231         break;
3232     case 6:
3233         gen_helper_vfp_touhd_round_to_zero(vd, vd, shift, fpst);
3234         break;
3235     case 7:
3236         gen_helper_vfp_tould_round_to_zero(vd, vd, shift, fpst);
3237         break;
3238     default:
3239         g_assert_not_reached();
3240     }
3241
3242     vfp_store_reg64(vd, a->vd);
3243     tcg_temp_free_i64(vd);
3244     tcg_temp_free_i32(shift);
3245     tcg_temp_free_ptr(fpst);
3246     return true;
3247 }
3248
3249 static bool trans_VCVT_hp_int(DisasContext *s, arg_VCVT_sp_int *a)
3250 {
3251     TCGv_i32 vm;
3252     TCGv_ptr fpst;
3253
3254     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3255         return false;
3256     }
3257
3258     if (!vfp_access_check(s)) {
3259         return true;
3260     }
3261
3262     fpst = fpstatus_ptr(FPST_FPCR_F16);
3263     vm = tcg_temp_new_i32();
3264     vfp_load_reg32(vm, a->vm);
3265
3266     if (a->s) {
3267         if (a->rz) {
3268             gen_helper_vfp_tosizh(vm, vm, fpst);
3269         } else {
3270             gen_helper_vfp_tosih(vm, vm, fpst);
3271         }
3272     } else {
3273         if (a->rz) {
3274             gen_helper_vfp_touizh(vm, vm, fpst);
3275         } else {
3276             gen_helper_vfp_touih(vm, vm, fpst);
3277         }
3278     }
3279     vfp_store_reg32(vm, a->vd);
3280     tcg_temp_free_i32(vm);
3281     tcg_temp_free_ptr(fpst);
3282     return true;
3283 }
3284
3285 static bool trans_VCVT_sp_int(DisasContext *s, arg_VCVT_sp_int *a)
3286 {
3287     TCGv_i32 vm;
3288     TCGv_ptr fpst;
3289
3290     if (!dc_isar_feature(aa32_fpsp_v2, s)) {
3291         return false;
3292     }
3293
3294     if (!vfp_access_check(s)) {
3295         return true;
3296     }
3297
3298     fpst = fpstatus_ptr(FPST_FPCR);
3299     vm = tcg_temp_new_i32();
3300     vfp_load_reg32(vm, a->vm);
3301
3302     if (a->s) {
3303         if (a->rz) {
3304             gen_helper_vfp_tosizs(vm, vm, fpst);
3305         } else {
3306             gen_helper_vfp_tosis(vm, vm, fpst);
3307         }
3308     } else {
3309         if (a->rz) {
3310             gen_helper_vfp_touizs(vm, vm, fpst);
3311         } else {
3312             gen_helper_vfp_touis(vm, vm, fpst);
3313         }
3314     }
3315     vfp_store_reg32(vm, a->vd);
3316     tcg_temp_free_i32(vm);
3317     tcg_temp_free_ptr(fpst);
3318     return true;
3319 }
3320
3321 static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
3322 {
3323     TCGv_i32 vd;
3324     TCGv_i64 vm;
3325     TCGv_ptr fpst;
3326
3327     if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3328         return false;
3329     }
3330
3331     /* UNDEF accesses to D16-D31 if they don't exist. */
3332     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
3333         return false;
3334     }
3335
3336     if (!vfp_access_check(s)) {
3337         return true;
3338     }
3339
3340     fpst = fpstatus_ptr(FPST_FPCR);
3341     vm = tcg_temp_new_i64();
3342     vd = tcg_temp_new_i32();
3343     vfp_load_reg64(vm, a->vm);
3344
3345     if (a->s) {
3346         if (a->rz) {
3347             gen_helper_vfp_tosizd(vd, vm, fpst);
3348         } else {
3349             gen_helper_vfp_tosid(vd, vm, fpst);
3350         }
3351     } else {
3352         if (a->rz) {
3353             gen_helper_vfp_touizd(vd, vm, fpst);
3354         } else {
3355             gen_helper_vfp_touid(vd, vm, fpst);
3356         }
3357     }
3358     vfp_store_reg32(vd, a->vd);
3359     tcg_temp_free_i32(vd);
3360     tcg_temp_free_i64(vm);
3361     tcg_temp_free_ptr(fpst);
3362     return true;
3363 }
3364
3365 /*
3366  * Decode VLLDM and VLSTM are nonstandard because:
3367  *  * if there is no FPU then these insns must NOP in
3368  *    Secure state and UNDEF in Nonsecure state
3369  *  * if there is an FPU then these insns do not have
3370  *    the usual behaviour that vfp_access_check() provides of
3371  *    being controlled by CPACR/NSACR enable bits or the
3372  *    lazy-stacking logic.
3373  */
3374 static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
3375 {
3376     TCGv_i32 fptr;
3377
3378     if (!arm_dc_feature(s, ARM_FEATURE_M) ||
3379         !arm_dc_feature(s, ARM_FEATURE_V8)) {
3380         return false;
3381     }
3382     /*
3383      * If not secure, UNDEF. We must emit code for this
3384      * rather than returning false so that this takes
3385      * precedence over the m-nocp.decode NOCP fallback.
3386      */
3387     if (!s->v8m_secure) {
3388         unallocated_encoding(s);
3389         return true;
3390     }
3391     /* If no fpu, NOP. */
3392     if (!dc_isar_feature(aa32_vfp, s)) {
3393         return true;
3394     }
3395
3396     fptr = load_reg(s, a->rn);
3397     if (a->l) {
3398         gen_helper_v7m_vlldm(cpu_env, fptr);
3399     } else {
3400         gen_helper_v7m_vlstm(cpu_env, fptr);
3401     }
3402     tcg_temp_free_i32(fptr);
3403
3404     /* End the TB, because we have updated FP control bits */
3405     s->base.is_jmp = DISAS_UPDATE_EXIT;
3406     return true;
3407 }
3408
3409 static bool trans_NOCP(DisasContext *s, arg_nocp *a)
3410 {
3411     /*
3412      * Handle M-profile early check for disabled coprocessor:
3413      * all we need to do here is emit the NOCP exception if
3414      * the coprocessor is disabled. Otherwise we return false
3415      * and the real VFP/etc decode will handle the insn.
3416      */
3417     assert(arm_dc_feature(s, ARM_FEATURE_M));
3418
3419     if (a->cp == 11) {
3420         a->cp = 10;
3421     }
3422     if (arm_dc_feature(s, ARM_FEATURE_V8_1M) &&
3423         (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) {
3424         /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
3425         a->cp = 10;
3426     }
3427
3428     if (a->cp != 10) {
3429         gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
3430                            syn_uncategorized(), default_exception_el(s));
3431         return true;
3432     }
3433
3434     if (s->fp_excp_el != 0) {
3435         gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
3436                            syn_uncategorized(), s->fp_excp_el);
3437         return true;
3438     }
3439
3440     return false;
3441 }
3442
3443 static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a)
3444 {
3445     /* This range needs a coprocessor check for v8.1M and later only */
3446     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
3447         return false;
3448     }
3449     return trans_NOCP(s, a);
3450 }
3451
3452 static bool trans_VINS(DisasContext *s, arg_VINS *a)
3453 {
3454     TCGv_i32 rd, rm;
3455
3456     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3457         return false;
3458     }
3459
3460     if (s->vec_len != 0 || s->vec_stride != 0) {
3461         return false;
3462     }
3463
3464     if (!vfp_access_check(s)) {
3465         return true;
3466     }
3467
3468     /* Insert low half of Vm into high half of Vd */
3469     rm = tcg_temp_new_i32();
3470     rd = tcg_temp_new_i32();
3471     vfp_load_reg32(rm, a->vm);
3472     vfp_load_reg32(rd, a->vd);
3473     tcg_gen_deposit_i32(rd, rd, rm, 16, 16);
3474     vfp_store_reg32(rd, a->vd);
3475     tcg_temp_free_i32(rm);
3476     tcg_temp_free_i32(rd);
3477     return true;
3478 }
3479
3480 static bool trans_VMOVX(DisasContext *s, arg_VINS *a)
3481 {
3482     TCGv_i32 rm;
3483
3484     if (!dc_isar_feature(aa32_fp16_arith, s)) {
3485         return false;
3486     }
3487
3488     if (s->vec_len != 0 || s->vec_stride != 0) {
3489         return false;
3490     }
3491
3492     if (!vfp_access_check(s)) {
3493         return true;
3494     }
3495
3496     /* Set Vd to high half of Vm */
3497     rm = tcg_temp_new_i32();
3498     vfp_load_reg32(rm, a->vm);
3499     tcg_gen_shri_i32(rm, rm, 16);
3500     vfp_store_reg32(rm, a->vd);
3501     tcg_temp_free_i32(rm);
3502     return true;
3503 }