]> git.proxmox.com Git - mirror_qemu.git/blame - target/arm/translate-vfp.c.inc
target/arm: Implement VFP fp16 VMLA, VMLS, VNMLS, VNMLA, VNMUL
[mirror_qemu.git] / target / arm / translate-vfp.c.inc
CommitLineData
78e138bc
PM
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 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 */
139c1837
PB
30#include "decode-vfp.c.inc"
31#include "decode-vfp-uncond.c.inc"
06db8196 32
d6a092d4
PM
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 */
38uint64_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
b623d803
PM
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 */
71static 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
06db8196
PM
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 */
95static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled)
96{
97 if (s->fp_excp_el) {
a3494d46
PM
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);
06db8196
PM
103 return false;
104 }
105
106 if (!s->vfp_enabled && !ignore_vfp_enabled) {
107 assert(!arm_dc_feature(s, ARM_FEATURE_M));
1ce21ba1 108 unallocated_encoding(s);
06db8196
PM
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,
55c812b7
PM
119 * so we must mark it as an IO operation for icount (and cause
120 * this to be the last insn in the TB).
06db8196
PM
121 */
122 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
14407ec2 123 s->base.is_jmp = DISAS_UPDATE_EXIT;
06db8196
PM
124 gen_io_start();
125 }
126 gen_helper_v7m_preserve_fp_state(cpu_env);
06db8196
PM
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}
b3ff4b87
PM
180
181/*
182 * The most usual kind of VFP access check, for everything except
183 * FMXR/FMRX to the always-available special registers.
184 */
185static bool vfp_access_check(DisasContext *s)
186{
187 return full_vfp_access_check(s, false);
188}
f7bbb8f3
PM
189
190static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
191{
192 uint32_t rd, rn, rm;
193 bool dp = a->dp;
194
195 if (!dc_isar_feature(aa32_vsel, s)) {
196 return false;
197 }
198
799449ab 199 if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) {
f7bbb8f3
PM
200 return false;
201 }
1120827f 202
799449ab
RH
203 /* UNDEF accesses to D16-D31 if they don't exist */
204 if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
205 ((a->vm | a->vn | a->vd) & 0x10)) {
1120827f
PM
206 return false;
207 }
208
f7bbb8f3
PM
209 rd = a->vd;
210 rn = a->vn;
211 rm = a->vm;
212
213 if (!vfp_access_check(s)) {
214 return true;
215 }
216
217 if (dp) {
218 TCGv_i64 frn, frm, dest;
219 TCGv_i64 tmp, zero, zf, nf, vf;
220
221 zero = tcg_const_i64(0);
222
223 frn = tcg_temp_new_i64();
224 frm = tcg_temp_new_i64();
225 dest = tcg_temp_new_i64();
226
227 zf = tcg_temp_new_i64();
228 nf = tcg_temp_new_i64();
229 vf = tcg_temp_new_i64();
230
231 tcg_gen_extu_i32_i64(zf, cpu_ZF);
232 tcg_gen_ext_i32_i64(nf, cpu_NF);
233 tcg_gen_ext_i32_i64(vf, cpu_VF);
234
160f3b64
PM
235 neon_load_reg64(frn, rn);
236 neon_load_reg64(frm, rm);
f7bbb8f3
PM
237 switch (a->cc) {
238 case 0: /* eq: Z */
239 tcg_gen_movcond_i64(TCG_COND_EQ, dest, zf, zero,
240 frn, frm);
241 break;
242 case 1: /* vs: V */
243 tcg_gen_movcond_i64(TCG_COND_LT, dest, vf, zero,
244 frn, frm);
245 break;
246 case 2: /* ge: N == V -> N ^ V == 0 */
247 tmp = tcg_temp_new_i64();
248 tcg_gen_xor_i64(tmp, vf, nf);
249 tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero,
250 frn, frm);
251 tcg_temp_free_i64(tmp);
252 break;
253 case 3: /* gt: !Z && N == V */
254 tcg_gen_movcond_i64(TCG_COND_NE, dest, zf, zero,
255 frn, frm);
256 tmp = tcg_temp_new_i64();
257 tcg_gen_xor_i64(tmp, vf, nf);
258 tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero,
259 dest, frm);
260 tcg_temp_free_i64(tmp);
261 break;
262 }
160f3b64 263 neon_store_reg64(dest, rd);
f7bbb8f3
PM
264 tcg_temp_free_i64(frn);
265 tcg_temp_free_i64(frm);
266 tcg_temp_free_i64(dest);
267
268 tcg_temp_free_i64(zf);
269 tcg_temp_free_i64(nf);
270 tcg_temp_free_i64(vf);
271
272 tcg_temp_free_i64(zero);
273 } else {
274 TCGv_i32 frn, frm, dest;
275 TCGv_i32 tmp, zero;
276
277 zero = tcg_const_i32(0);
278
279 frn = tcg_temp_new_i32();
280 frm = tcg_temp_new_i32();
281 dest = tcg_temp_new_i32();
160f3b64
PM
282 neon_load_reg32(frn, rn);
283 neon_load_reg32(frm, rm);
f7bbb8f3
PM
284 switch (a->cc) {
285 case 0: /* eq: Z */
286 tcg_gen_movcond_i32(TCG_COND_EQ, dest, cpu_ZF, zero,
287 frn, frm);
288 break;
289 case 1: /* vs: V */
290 tcg_gen_movcond_i32(TCG_COND_LT, dest, cpu_VF, zero,
291 frn, frm);
292 break;
293 case 2: /* ge: N == V -> N ^ V == 0 */
294 tmp = tcg_temp_new_i32();
295 tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
296 tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero,
297 frn, frm);
298 tcg_temp_free_i32(tmp);
299 break;
300 case 3: /* gt: !Z && N == V */
301 tcg_gen_movcond_i32(TCG_COND_NE, dest, cpu_ZF, zero,
302 frn, frm);
303 tmp = tcg_temp_new_i32();
304 tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
305 tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero,
306 dest, frm);
307 tcg_temp_free_i32(tmp);
308 break;
309 }
160f3b64 310 neon_store_reg32(dest, rd);
f7bbb8f3
PM
311 tcg_temp_free_i32(frn);
312 tcg_temp_free_i32(frm);
313 tcg_temp_free_i32(dest);
314
315 tcg_temp_free_i32(zero);
316 }
317
318 return true;
319}
320
f7bbb8f3
PM
321/*
322 * Table for converting the most common AArch32 encoding of
323 * rounding mode to arm_fprounding order (which matches the
324 * common AArch64 order); see ARM ARM pseudocode FPDecodeRM().
325 */
326static const uint8_t fp_decode_rm[] = {
327 FPROUNDING_TIEAWAY,
328 FPROUNDING_TIEEVEN,
329 FPROUNDING_POSINF,
330 FPROUNDING_NEGINF,
331};
332
333static bool trans_VRINT(DisasContext *s, arg_VRINT *a)
334{
335 uint32_t rd, rm;
336 bool dp = a->dp;
337 TCGv_ptr fpst;
338 TCGv_i32 tcg_rmode;
339 int rounding = fp_decode_rm[a->rm];
340
341 if (!dc_isar_feature(aa32_vrint, s)) {
342 return false;
343 }
344
799449ab 345 if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) {
f7bbb8f3
PM
346 return false;
347 }
1120827f 348
799449ab
RH
349 /* UNDEF accesses to D16-D31 if they don't exist */
350 if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
351 ((a->vm | a->vd) & 0x10)) {
1120827f
PM
352 return false;
353 }
354
f7bbb8f3
PM
355 rd = a->vd;
356 rm = a->vm;
357
358 if (!vfp_access_check(s)) {
359 return true;
360 }
361
a84d1d13 362 fpst = fpstatus_ptr(FPST_FPCR);
f7bbb8f3
PM
363
364 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding));
365 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
366
367 if (dp) {
368 TCGv_i64 tcg_op;
369 TCGv_i64 tcg_res;
370 tcg_op = tcg_temp_new_i64();
371 tcg_res = tcg_temp_new_i64();
160f3b64 372 neon_load_reg64(tcg_op, rm);
f7bbb8f3 373 gen_helper_rintd(tcg_res, tcg_op, fpst);
160f3b64 374 neon_store_reg64(tcg_res, rd);
f7bbb8f3
PM
375 tcg_temp_free_i64(tcg_op);
376 tcg_temp_free_i64(tcg_res);
377 } else {
378 TCGv_i32 tcg_op;
379 TCGv_i32 tcg_res;
380 tcg_op = tcg_temp_new_i32();
381 tcg_res = tcg_temp_new_i32();
160f3b64 382 neon_load_reg32(tcg_op, rm);
f7bbb8f3 383 gen_helper_rints(tcg_res, tcg_op, fpst);
160f3b64 384 neon_store_reg32(tcg_res, rd);
f7bbb8f3
PM
385 tcg_temp_free_i32(tcg_op);
386 tcg_temp_free_i32(tcg_res);
387 }
388
389 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
390 tcg_temp_free_i32(tcg_rmode);
391
392 tcg_temp_free_ptr(fpst);
393 return true;
394}
395
396static bool trans_VCVT(DisasContext *s, arg_VCVT *a)
397{
398 uint32_t rd, rm;
399 bool dp = a->dp;
400 TCGv_ptr fpst;
401 TCGv_i32 tcg_rmode, tcg_shift;
402 int rounding = fp_decode_rm[a->rm];
403 bool is_signed = a->op;
404
405 if (!dc_isar_feature(aa32_vcvt_dr, s)) {
406 return false;
407 }
408
799449ab 409 if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) {
f7bbb8f3
PM
410 return false;
411 }
1120827f 412
799449ab
RH
413 /* UNDEF accesses to D16-D31 if they don't exist */
414 if (dp && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
1120827f
PM
415 return false;
416 }
417
f7bbb8f3
PM
418 rd = a->vd;
419 rm = a->vm;
420
421 if (!vfp_access_check(s)) {
422 return true;
423 }
424
a84d1d13 425 fpst = fpstatus_ptr(FPST_FPCR);
f7bbb8f3
PM
426
427 tcg_shift = tcg_const_i32(0);
428
429 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding));
430 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
431
432 if (dp) {
433 TCGv_i64 tcg_double, tcg_res;
434 TCGv_i32 tcg_tmp;
435 tcg_double = tcg_temp_new_i64();
436 tcg_res = tcg_temp_new_i64();
437 tcg_tmp = tcg_temp_new_i32();
160f3b64 438 neon_load_reg64(tcg_double, rm);
f7bbb8f3
PM
439 if (is_signed) {
440 gen_helper_vfp_tosld(tcg_res, tcg_double, tcg_shift, fpst);
441 } else {
442 gen_helper_vfp_tould(tcg_res, tcg_double, tcg_shift, fpst);
443 }
444 tcg_gen_extrl_i64_i32(tcg_tmp, tcg_res);
160f3b64 445 neon_store_reg32(tcg_tmp, rd);
f7bbb8f3
PM
446 tcg_temp_free_i32(tcg_tmp);
447 tcg_temp_free_i64(tcg_res);
448 tcg_temp_free_i64(tcg_double);
449 } else {
450 TCGv_i32 tcg_single, tcg_res;
451 tcg_single = tcg_temp_new_i32();
452 tcg_res = tcg_temp_new_i32();
160f3b64 453 neon_load_reg32(tcg_single, rm);
f7bbb8f3
PM
454 if (is_signed) {
455 gen_helper_vfp_tosls(tcg_res, tcg_single, tcg_shift, fpst);
456 } else {
457 gen_helper_vfp_touls(tcg_res, tcg_single, tcg_shift, fpst);
458 }
160f3b64 459 neon_store_reg32(tcg_res, rd);
f7bbb8f3
PM
460 tcg_temp_free_i32(tcg_res);
461 tcg_temp_free_i32(tcg_single);
462 }
463
464 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
465 tcg_temp_free_i32(tcg_rmode);
466
467 tcg_temp_free_i32(tcg_shift);
468
469 tcg_temp_free_ptr(fpst);
470
471 return true;
472}
9851ed92
PM
473
474static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a)
475{
476 /* VMOV scalar to general purpose register */
477 TCGv_i32 tmp;
478 int pass;
479 uint32_t offset;
480
82f6abe1
RH
481 /* SIZE == 2 is a VFP instruction; otherwise NEON. */
482 if (a->size == 2
483 ? !dc_isar_feature(aa32_fpsp_v2, s)
484 : !arm_dc_feature(s, ARM_FEATURE_NEON)) {
485 return false;
486 }
487
9851ed92 488 /* UNDEF accesses to D16-D31 if they don't exist */
0e13ba78 489 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
9851ed92
PM
490 return false;
491 }
492
493 offset = a->index << a->size;
494 pass = extract32(offset, 2, 1);
495 offset = extract32(offset, 0, 2) * 8;
496
9851ed92
PM
497 if (!vfp_access_check(s)) {
498 return true;
499 }
500
501 tmp = neon_load_reg(a->vn, pass);
502 switch (a->size) {
503 case 0:
504 if (offset) {
505 tcg_gen_shri_i32(tmp, tmp, offset);
506 }
507 if (a->u) {
508 gen_uxtb(tmp);
509 } else {
510 gen_sxtb(tmp);
511 }
512 break;
513 case 1:
514 if (a->u) {
515 if (offset) {
516 tcg_gen_shri_i32(tmp, tmp, 16);
517 } else {
518 gen_uxth(tmp);
519 }
520 } else {
521 if (offset) {
522 tcg_gen_sari_i32(tmp, tmp, 16);
523 } else {
524 gen_sxth(tmp);
525 }
526 }
527 break;
528 case 2:
529 break;
530 }
531 store_reg(s, a->rt, tmp);
532
533 return true;
534}
535
536static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a)
537{
538 /* VMOV general purpose register to scalar */
539 TCGv_i32 tmp, tmp2;
540 int pass;
541 uint32_t offset;
542
82f6abe1
RH
543 /* SIZE == 2 is a VFP instruction; otherwise NEON. */
544 if (a->size == 2
545 ? !dc_isar_feature(aa32_fpsp_v2, s)
546 : !arm_dc_feature(s, ARM_FEATURE_NEON)) {
547 return false;
548 }
549
9851ed92 550 /* UNDEF accesses to D16-D31 if they don't exist */
0e13ba78 551 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
9851ed92
PM
552 return false;
553 }
554
555 offset = a->index << a->size;
556 pass = extract32(offset, 2, 1);
557 offset = extract32(offset, 0, 2) * 8;
558
9851ed92
PM
559 if (!vfp_access_check(s)) {
560 return true;
561 }
562
563 tmp = load_reg(s, a->rt);
564 switch (a->size) {
565 case 0:
566 tmp2 = neon_load_reg(a->vn, pass);
567 tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 8);
568 tcg_temp_free_i32(tmp2);
569 break;
570 case 1:
571 tmp2 = neon_load_reg(a->vn, pass);
572 tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 16);
573 tcg_temp_free_i32(tmp2);
574 break;
575 case 2:
576 break;
577 }
578 neon_store_reg(a->vn, pass, tmp);
579
580 return true;
581}
582
583static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
584{
585 /* VDUP (general purpose register) */
586 TCGv_i32 tmp;
587 int size, vec_size;
588
589 if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
590 return false;
591 }
592
593 /* UNDEF accesses to D16-D31 if they don't exist */
0e13ba78 594 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
9851ed92
PM
595 return false;
596 }
597
598 if (a->b && a->e) {
599 return false;
600 }
601
602 if (a->q && (a->vn & 1)) {
603 return false;
604 }
605
606 vec_size = a->q ? 16 : 8;
607 if (a->b) {
608 size = 0;
609 } else if (a->e) {
610 size = 1;
611 } else {
612 size = 2;
613 }
614
615 if (!vfp_access_check(s)) {
616 return true;
617 }
618
619 tmp = load_reg(s, a->rt);
620 tcg_gen_gvec_dup_i32(size, neon_reg_offset(a->vn, 0),
621 vec_size, vec_size, tmp);
622 tcg_temp_free_i32(tmp);
623
624 return true;
625}
a9ab5001
PM
626
627static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
628{
629 TCGv_i32 tmp;
630 bool ignore_vfp_enabled = false;
631
82f6abe1
RH
632 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
633 return false;
634 }
635
a9ab5001
PM
636 if (arm_dc_feature(s, ARM_FEATURE_M)) {
637 /*
638 * The only M-profile VFP vmrs/vmsr sysreg is FPSCR.
2529ab43
CL
639 * Accesses to R15 are UNPREDICTABLE; we choose to undef.
640 * (FPSCR -> r15 is a special case which writes to the PSR flags.)
a9ab5001 641 */
2529ab43 642 if (a->rt == 15 && (!a->l || a->reg != ARM_VFP_FPSCR)) {
a9ab5001
PM
643 return false;
644 }
645 }
646
647 switch (a->reg) {
648 case ARM_VFP_FPSID:
649 /*
650 * VFPv2 allows access to FPSID from userspace; VFPv3 restricts
651 * all ID registers to privileged access only.
652 */
84774cc3 653 if (IS_USER(s) && dc_isar_feature(aa32_fpsp_v3, s)) {
a9ab5001
PM
654 return false;
655 }
656 ignore_vfp_enabled = true;
657 break;
658 case ARM_VFP_MVFR0:
659 case ARM_VFP_MVFR1:
660 if (IS_USER(s) || !arm_dc_feature(s, ARM_FEATURE_MVFR)) {
661 return false;
662 }
663 ignore_vfp_enabled = true;
664 break;
665 case ARM_VFP_MVFR2:
666 if (IS_USER(s) || !arm_dc_feature(s, ARM_FEATURE_V8)) {
667 return false;
668 }
669 ignore_vfp_enabled = true;
670 break;
671 case ARM_VFP_FPSCR:
672 break;
673 case ARM_VFP_FPEXC:
674 if (IS_USER(s)) {
675 return false;
676 }
677 ignore_vfp_enabled = true;
678 break;
679 case ARM_VFP_FPINST:
680 case ARM_VFP_FPINST2:
681 /* Not present in VFPv3 */
84774cc3 682 if (IS_USER(s) || dc_isar_feature(aa32_fpsp_v3, s)) {
a9ab5001
PM
683 return false;
684 }
685 break;
686 default:
687 return false;
688 }
689
690 if (!full_vfp_access_check(s, ignore_vfp_enabled)) {
691 return true;
692 }
693
694 if (a->l) {
695 /* VMRS, move VFP special register to gp register */
696 switch (a->reg) {
9ca1d776
MZ
697 case ARM_VFP_MVFR0:
698 case ARM_VFP_MVFR1:
699 case ARM_VFP_MVFR2:
a9ab5001 700 case ARM_VFP_FPSID:
9ca1d776
MZ
701 if (s->current_el == 1) {
702 TCGv_i32 tcg_reg, tcg_rt;
703
704 gen_set_condexec(s);
705 gen_set_pc_im(s, s->pc_curr);
706 tcg_reg = tcg_const_i32(a->reg);
707 tcg_rt = tcg_const_i32(a->rt);
708 gen_helper_check_hcr_el2_trap(cpu_env, tcg_rt, tcg_reg);
709 tcg_temp_free_i32(tcg_reg);
710 tcg_temp_free_i32(tcg_rt);
711 }
712 /* fall through */
a9ab5001
PM
713 case ARM_VFP_FPEXC:
714 case ARM_VFP_FPINST:
715 case ARM_VFP_FPINST2:
a9ab5001
PM
716 tmp = load_cpu_field(vfp.xregs[a->reg]);
717 break;
718 case ARM_VFP_FPSCR:
719 if (a->rt == 15) {
720 tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
721 tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
722 } else {
723 tmp = tcg_temp_new_i32();
724 gen_helper_vfp_get_fpscr(tmp, cpu_env);
725 }
726 break;
727 default:
728 g_assert_not_reached();
729 }
730
731 if (a->rt == 15) {
732 /* Set the 4 flag bits in the CPSR. */
733 gen_set_nzcv(tmp);
734 tcg_temp_free_i32(tmp);
735 } else {
736 store_reg(s, a->rt, tmp);
737 }
738 } else {
739 /* VMSR, move gp register to VFP special register */
740 switch (a->reg) {
741 case ARM_VFP_FPSID:
742 case ARM_VFP_MVFR0:
743 case ARM_VFP_MVFR1:
744 case ARM_VFP_MVFR2:
745 /* Writes are ignored. */
746 break;
747 case ARM_VFP_FPSCR:
748 tmp = load_reg(s, a->rt);
749 gen_helper_vfp_set_fpscr(cpu_env, tmp);
750 tcg_temp_free_i32(tmp);
751 gen_lookup_tb(s);
752 break;
753 case ARM_VFP_FPEXC:
754 /*
755 * TODO: VFP subarchitecture support.
756 * For now, keep the EN bit only
757 */
758 tmp = load_reg(s, a->rt);
759 tcg_gen_andi_i32(tmp, tmp, 1 << 30);
760 store_cpu_field(tmp, vfp.xregs[a->reg]);
761 gen_lookup_tb(s);
762 break;
763 case ARM_VFP_FPINST:
764 case ARM_VFP_FPINST2:
765 tmp = load_reg(s, a->rt);
766 store_cpu_field(tmp, vfp.xregs[a->reg]);
767 break;
768 default:
769 g_assert_not_reached();
770 }
771 }
772
773 return true;
774}
775
776static bool trans_VMOV_single(DisasContext *s, arg_VMOV_single *a)
777{
778 TCGv_i32 tmp;
779
82f6abe1
RH
780 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
781 return false;
782 }
783
a9ab5001
PM
784 if (!vfp_access_check(s)) {
785 return true;
786 }
787
788 if (a->l) {
789 /* VFP to general purpose register */
790 tmp = tcg_temp_new_i32();
791 neon_load_reg32(tmp, a->vn);
792 if (a->rt == 15) {
793 /* Set the 4 flag bits in the CPSR. */
794 gen_set_nzcv(tmp);
795 tcg_temp_free_i32(tmp);
796 } else {
797 store_reg(s, a->rt, tmp);
798 }
799 } else {
800 /* general purpose register to VFP */
801 tmp = load_reg(s, a->rt);
802 neon_store_reg32(tmp, a->vn);
803 tcg_temp_free_i32(tmp);
804 }
805
806 return true;
807}
81f68110
PM
808
809static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a)
810{
811 TCGv_i32 tmp;
812
82f6abe1
RH
813 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
814 return false;
815 }
816
81f68110
PM
817 /*
818 * VMOV between two general-purpose registers and two single precision
819 * floating point registers
820 */
821 if (!vfp_access_check(s)) {
822 return true;
823 }
824
825 if (a->op) {
826 /* fpreg to gpreg */
827 tmp = tcg_temp_new_i32();
828 neon_load_reg32(tmp, a->vm);
829 store_reg(s, a->rt, tmp);
830 tmp = tcg_temp_new_i32();
831 neon_load_reg32(tmp, a->vm + 1);
832 store_reg(s, a->rt2, tmp);
833 } else {
834 /* gpreg to fpreg */
835 tmp = load_reg(s, a->rt);
836 neon_store_reg32(tmp, a->vm);
342d2758 837 tcg_temp_free_i32(tmp);
81f68110
PM
838 tmp = load_reg(s, a->rt2);
839 neon_store_reg32(tmp, a->vm + 1);
342d2758 840 tcg_temp_free_i32(tmp);
81f68110
PM
841 }
842
843 return true;
844}
845
83655223 846static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_dp *a)
81f68110
PM
847{
848 TCGv_i32 tmp;
849
850 /*
851 * VMOV between two general-purpose registers and one double precision
82f6abe1
RH
852 * floating point register. Note that this does not require support
853 * for double precision arithmetic.
81f68110 854 */
82f6abe1
RH
855 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
856 return false;
857 }
81f68110
PM
858
859 /* UNDEF accesses to D16-D31 if they don't exist */
0e13ba78 860 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
81f68110
PM
861 return false;
862 }
863
864 if (!vfp_access_check(s)) {
865 return true;
866 }
867
868 if (a->op) {
869 /* fpreg to gpreg */
870 tmp = tcg_temp_new_i32();
871 neon_load_reg32(tmp, a->vm * 2);
872 store_reg(s, a->rt, tmp);
873 tmp = tcg_temp_new_i32();
874 neon_load_reg32(tmp, a->vm * 2 + 1);
875 store_reg(s, a->rt2, tmp);
876 } else {
877 /* gpreg to fpreg */
878 tmp = load_reg(s, a->rt);
879 neon_store_reg32(tmp, a->vm * 2);
880 tcg_temp_free_i32(tmp);
881 tmp = load_reg(s, a->rt2);
882 neon_store_reg32(tmp, a->vm * 2 + 1);
883 tcg_temp_free_i32(tmp);
884 }
885
886 return true;
887}
79b02a3b
PM
888
889static bool trans_VLDR_VSTR_sp(DisasContext *s, arg_VLDR_VSTR_sp *a)
890{
891 uint32_t offset;
3993d040 892 TCGv_i32 addr, tmp;
79b02a3b 893
82f6abe1
RH
894 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
895 return false;
896 }
897
79b02a3b
PM
898 if (!vfp_access_check(s)) {
899 return true;
900 }
901
902 offset = a->imm << 2;
903 if (!a->u) {
904 offset = -offset;
905 }
906
16e0d823
RH
907 /* For thumb, use of PC is UNPREDICTABLE. */
908 addr = add_reg_for_lit(s, a->rn, offset);
3993d040 909 tmp = tcg_temp_new_i32();
79b02a3b 910 if (a->l) {
3993d040
PM
911 gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
912 neon_store_reg32(tmp, a->vd);
79b02a3b 913 } else {
3993d040
PM
914 neon_load_reg32(tmp, a->vd);
915 gen_aa32_st32(s, tmp, addr, get_mem_index(s));
79b02a3b 916 }
3993d040 917 tcg_temp_free_i32(tmp);
79b02a3b
PM
918 tcg_temp_free_i32(addr);
919
920 return true;
921}
922
83655223 923static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a)
79b02a3b
PM
924{
925 uint32_t offset;
926 TCGv_i32 addr;
3993d040 927 TCGv_i64 tmp;
79b02a3b 928
82f6abe1
RH
929 /* Note that this does not require support for double arithmetic. */
930 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
931 return false;
932 }
933
79b02a3b 934 /* UNDEF accesses to D16-D31 if they don't exist */
0e13ba78 935 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
79b02a3b
PM
936 return false;
937 }
938
939 if (!vfp_access_check(s)) {
940 return true;
941 }
942
943 offset = a->imm << 2;
944 if (!a->u) {
945 offset = -offset;
946 }
947
16e0d823
RH
948 /* For thumb, use of PC is UNPREDICTABLE. */
949 addr = add_reg_for_lit(s, a->rn, offset);
3993d040 950 tmp = tcg_temp_new_i64();
79b02a3b 951 if (a->l) {
3993d040
PM
952 gen_aa32_ld64(s, tmp, addr, get_mem_index(s));
953 neon_store_reg64(tmp, a->vd);
79b02a3b 954 } else {
3993d040
PM
955 neon_load_reg64(tmp, a->vd);
956 gen_aa32_st64(s, tmp, addr, get_mem_index(s));
79b02a3b 957 }
3993d040 958 tcg_temp_free_i64(tmp);
79b02a3b
PM
959 tcg_temp_free_i32(addr);
960
961 return true;
962}
fa288de2
PM
963
964static bool trans_VLDM_VSTM_sp(DisasContext *s, arg_VLDM_VSTM_sp *a)
965{
966 uint32_t offset;
3993d040 967 TCGv_i32 addr, tmp;
fa288de2
PM
968 int i, n;
969
82f6abe1
RH
970 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
971 return false;
972 }
973
fa288de2
PM
974 n = a->imm;
975
976 if (n == 0 || (a->vd + n) > 32) {
977 /*
978 * UNPREDICTABLE cases for bad immediates: we choose to
979 * UNDEF to avoid generating huge numbers of TCG ops
980 */
981 return false;
982 }
983 if (a->rn == 15 && a->w) {
984 /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
985 return false;
986 }
987
988 if (!vfp_access_check(s)) {
989 return true;
990 }
991
16e0d823
RH
992 /* For thumb, use of PC is UNPREDICTABLE. */
993 addr = add_reg_for_lit(s, a->rn, 0);
fa288de2
PM
994 if (a->p) {
995 /* pre-decrement */
996 tcg_gen_addi_i32(addr, addr, -(a->imm << 2));
997 }
998
999 if (s->v8m_stackcheck && a->rn == 13 && a->w) {
1000 /*
1001 * Here 'addr' is the lowest address we will store to,
1002 * and is either the old SP (if post-increment) or
1003 * the new SP (if pre-decrement). For post-increment
1004 * where the old value is below the limit and the new
1005 * value is above, it is UNKNOWN whether the limit check
1006 * triggers; we choose to trigger.
1007 */
1008 gen_helper_v8m_stackcheck(cpu_env, addr);
1009 }
1010
1011 offset = 4;
3993d040 1012 tmp = tcg_temp_new_i32();
fa288de2
PM
1013 for (i = 0; i < n; i++) {
1014 if (a->l) {
1015 /* load */
3993d040
PM
1016 gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
1017 neon_store_reg32(tmp, a->vd + i);
fa288de2
PM
1018 } else {
1019 /* store */
3993d040
PM
1020 neon_load_reg32(tmp, a->vd + i);
1021 gen_aa32_st32(s, tmp, addr, get_mem_index(s));
fa288de2
PM
1022 }
1023 tcg_gen_addi_i32(addr, addr, offset);
1024 }
3993d040 1025 tcg_temp_free_i32(tmp);
fa288de2
PM
1026 if (a->w) {
1027 /* writeback */
1028 if (a->p) {
1029 offset = -offset * n;
1030 tcg_gen_addi_i32(addr, addr, offset);
1031 }
1032 store_reg(s, a->rn, addr);
1033 } else {
1034 tcg_temp_free_i32(addr);
1035 }
1036
1037 return true;
1038}
1039
1040static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a)
1041{
1042 uint32_t offset;
1043 TCGv_i32 addr;
3993d040 1044 TCGv_i64 tmp;
fa288de2
PM
1045 int i, n;
1046
82f6abe1
RH
1047 /* Note that this does not require support for double arithmetic. */
1048 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1049 return false;
1050 }
1051
fa288de2
PM
1052 n = a->imm >> 1;
1053
1054 if (n == 0 || (a->vd + n) > 32 || n > 16) {
1055 /*
1056 * UNPREDICTABLE cases for bad immediates: we choose to
1057 * UNDEF to avoid generating huge numbers of TCG ops
1058 */
1059 return false;
1060 }
1061 if (a->rn == 15 && a->w) {
1062 /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
1063 return false;
1064 }
1065
1066 /* UNDEF accesses to D16-D31 if they don't exist */
0e13ba78 1067 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd + n) > 16) {
fa288de2
PM
1068 return false;
1069 }
1070
1071 if (!vfp_access_check(s)) {
1072 return true;
1073 }
1074
16e0d823
RH
1075 /* For thumb, use of PC is UNPREDICTABLE. */
1076 addr = add_reg_for_lit(s, a->rn, 0);
fa288de2
PM
1077 if (a->p) {
1078 /* pre-decrement */
1079 tcg_gen_addi_i32(addr, addr, -(a->imm << 2));
1080 }
1081
1082 if (s->v8m_stackcheck && a->rn == 13 && a->w) {
1083 /*
1084 * Here 'addr' is the lowest address we will store to,
1085 * and is either the old SP (if post-increment) or
1086 * the new SP (if pre-decrement). For post-increment
1087 * where the old value is below the limit and the new
1088 * value is above, it is UNKNOWN whether the limit check
1089 * triggers; we choose to trigger.
1090 */
1091 gen_helper_v8m_stackcheck(cpu_env, addr);
1092 }
1093
1094 offset = 8;
3993d040 1095 tmp = tcg_temp_new_i64();
fa288de2
PM
1096 for (i = 0; i < n; i++) {
1097 if (a->l) {
1098 /* load */
3993d040
PM
1099 gen_aa32_ld64(s, tmp, addr, get_mem_index(s));
1100 neon_store_reg64(tmp, a->vd + i);
fa288de2
PM
1101 } else {
1102 /* store */
3993d040
PM
1103 neon_load_reg64(tmp, a->vd + i);
1104 gen_aa32_st64(s, tmp, addr, get_mem_index(s));
fa288de2
PM
1105 }
1106 tcg_gen_addi_i32(addr, addr, offset);
1107 }
3993d040 1108 tcg_temp_free_i64(tmp);
fa288de2
PM
1109 if (a->w) {
1110 /* writeback */
1111 if (a->p) {
1112 offset = -offset * n;
1113 } else if (a->imm & 1) {
1114 offset = 4;
1115 } else {
1116 offset = 0;
1117 }
1118
1119 if (offset != 0) {
1120 tcg_gen_addi_i32(addr, addr, offset);
1121 }
1122 store_reg(s, a->rn, addr);
1123 } else {
1124 tcg_temp_free_i32(addr);
1125 }
1126
1127 return true;
1128}
266bd25c
PM
1129
1130/*
1131 * Types for callbacks for do_vfp_3op_sp() and do_vfp_3op_dp().
1132 * The callback should emit code to write a value to vd. If
1133 * do_vfp_3op_{sp,dp}() was passed reads_vd then the TCGv vd
1134 * will contain the old value of the relevant VFP register;
1135 * otherwise it must be written to only.
1136 */
1137typedef void VFPGen3OpSPFn(TCGv_i32 vd,
1138 TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst);
1139typedef void VFPGen3OpDPFn(TCGv_i64 vd,
1140 TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst);
1141
90287e22
PM
1142/*
1143 * Types for callbacks for do_vfp_2op_sp() and do_vfp_2op_dp().
1144 * The callback should emit code to write a value to vd (which
1145 * should be written to only).
1146 */
1147typedef void VFPGen2OpSPFn(TCGv_i32 vd, TCGv_i32 vm);
1148typedef void VFPGen2OpDPFn(TCGv_i64 vd, TCGv_i64 vm);
1149
18cf951a
PM
1150/*
1151 * Return true if the specified S reg is in a scalar bank
1152 * (ie if it is s0..s7)
1153 */
1154static inline bool vfp_sreg_is_scalar(int reg)
1155{
1156 return (reg & 0x18) == 0;
1157}
1158
1159/*
1160 * Return true if the specified D reg is in a scalar bank
1161 * (ie if it is d0..d3 or d16..d19)
1162 */
1163static inline bool vfp_dreg_is_scalar(int reg)
1164{
1165 return (reg & 0xc) == 0;
1166}
1167
1168/*
1169 * Advance the S reg number forwards by delta within its bank
1170 * (ie increment the low 3 bits but leave the rest the same)
1171 */
1172static inline int vfp_advance_sreg(int reg, int delta)
1173{
1174 return ((reg + delta) & 0x7) | (reg & ~0x7);
1175}
1176
1177/*
1178 * Advance the D reg number forwards by delta within its bank
1179 * (ie increment the low 2 bits but leave the rest the same)
1180 */
1181static inline int vfp_advance_dreg(int reg, int delta)
1182{
1183 return ((reg + delta) & 0x3) | (reg & ~0x3);
1184}
1185
266bd25c
PM
1186/*
1187 * Perform a 3-operand VFP data processing instruction. fn is the
1188 * callback to do the actual operation; this function deals with the
1189 * code to handle looping around for VFP vector processing.
1190 */
1191static bool do_vfp_3op_sp(DisasContext *s, VFPGen3OpSPFn *fn,
1192 int vd, int vn, int vm, bool reads_vd)
1193{
1194 uint32_t delta_m = 0;
1195 uint32_t delta_d = 0;
266bd25c
PM
1196 int veclen = s->vec_len;
1197 TCGv_i32 f0, f1, fd;
1198 TCGv_ptr fpst;
1199
82f6abe1
RH
1200 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1201 return false;
1202 }
1203
266bd25c
PM
1204 if (!dc_isar_feature(aa32_fpshvec, s) &&
1205 (veclen != 0 || s->vec_stride != 0)) {
1206 return false;
1207 }
1208
1209 if (!vfp_access_check(s)) {
1210 return true;
1211 }
1212
1213 if (veclen > 0) {
266bd25c 1214 /* Figure out what type of vector operation this is. */
18cf951a 1215 if (vfp_sreg_is_scalar(vd)) {
266bd25c
PM
1216 /* scalar */
1217 veclen = 0;
1218 } else {
1219 delta_d = s->vec_stride + 1;
1220
18cf951a 1221 if (vfp_sreg_is_scalar(vm)) {
266bd25c
PM
1222 /* mixed scalar/vector */
1223 delta_m = 0;
1224 } else {
1225 /* vector */
1226 delta_m = delta_d;
1227 }
1228 }
1229 }
1230
1231 f0 = tcg_temp_new_i32();
1232 f1 = tcg_temp_new_i32();
1233 fd = tcg_temp_new_i32();
a84d1d13 1234 fpst = fpstatus_ptr(FPST_FPCR);
266bd25c
PM
1235
1236 neon_load_reg32(f0, vn);
1237 neon_load_reg32(f1, vm);
1238
1239 for (;;) {
1240 if (reads_vd) {
1241 neon_load_reg32(fd, vd);
1242 }
1243 fn(fd, f0, f1, fpst);
1244 neon_store_reg32(fd, vd);
1245
1246 if (veclen == 0) {
1247 break;
1248 }
1249
1250 /* Set up the operands for the next iteration */
1251 veclen--;
18cf951a
PM
1252 vd = vfp_advance_sreg(vd, delta_d);
1253 vn = vfp_advance_sreg(vn, delta_d);
266bd25c
PM
1254 neon_load_reg32(f0, vn);
1255 if (delta_m) {
18cf951a 1256 vm = vfp_advance_sreg(vm, delta_m);
266bd25c
PM
1257 neon_load_reg32(f1, vm);
1258 }
1259 }
1260
1261 tcg_temp_free_i32(f0);
1262 tcg_temp_free_i32(f1);
1263 tcg_temp_free_i32(fd);
1264 tcg_temp_free_ptr(fpst);
1265
1266 return true;
1267}
1268
120a0eb3
PM
1269static bool do_vfp_3op_hp(DisasContext *s, VFPGen3OpSPFn *fn,
1270 int vd, int vn, int vm, bool reads_vd)
1271{
1272 /*
1273 * Do a half-precision operation. Functionally this is
1274 * the same as do_vfp_3op_sp(), except:
1275 * - it uses the FPST_FPCR_F16
1276 * - it doesn't need the VFP vector handling (fp16 is a
1277 * v8 feature, and in v8 VFP vectors don't exist)
1278 * - it does the aa32_fp16_arith feature test
1279 */
1280 TCGv_i32 f0, f1, fd;
1281 TCGv_ptr fpst;
1282
1283 if (!dc_isar_feature(aa32_fp16_arith, s)) {
1284 return false;
1285 }
1286
1287 if (s->vec_len != 0 || s->vec_stride != 0) {
1288 return false;
1289 }
1290
1291 if (!vfp_access_check(s)) {
1292 return true;
1293 }
1294
1295 f0 = tcg_temp_new_i32();
1296 f1 = tcg_temp_new_i32();
1297 fd = tcg_temp_new_i32();
1298 fpst = fpstatus_ptr(FPST_FPCR_F16);
1299
1300 neon_load_reg32(f0, vn);
1301 neon_load_reg32(f1, vm);
1302
1303 if (reads_vd) {
1304 neon_load_reg32(fd, vd);
1305 }
1306 fn(fd, f0, f1, fpst);
1307 neon_store_reg32(fd, vd);
1308
1309 tcg_temp_free_i32(f0);
1310 tcg_temp_free_i32(f1);
1311 tcg_temp_free_i32(fd);
1312 tcg_temp_free_ptr(fpst);
1313
1314 return true;
1315}
1316
266bd25c
PM
1317static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn,
1318 int vd, int vn, int vm, bool reads_vd)
1319{
1320 uint32_t delta_m = 0;
1321 uint32_t delta_d = 0;
266bd25c
PM
1322 int veclen = s->vec_len;
1323 TCGv_i64 f0, f1, fd;
1324 TCGv_ptr fpst;
1325
799449ab 1326 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
266bd25c
PM
1327 return false;
1328 }
1329
799449ab
RH
1330 /* UNDEF accesses to D16-D31 if they don't exist */
1331 if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) {
1120827f
PM
1332 return false;
1333 }
1334
266bd25c
PM
1335 if (!dc_isar_feature(aa32_fpshvec, s) &&
1336 (veclen != 0 || s->vec_stride != 0)) {
1337 return false;
1338 }
1339
1340 if (!vfp_access_check(s)) {
1341 return true;
1342 }
1343
1344 if (veclen > 0) {
266bd25c 1345 /* Figure out what type of vector operation this is. */
18cf951a 1346 if (vfp_dreg_is_scalar(vd)) {
266bd25c
PM
1347 /* scalar */
1348 veclen = 0;
1349 } else {
1350 delta_d = (s->vec_stride >> 1) + 1;
1351
18cf951a 1352 if (vfp_dreg_is_scalar(vm)) {
266bd25c
PM
1353 /* mixed scalar/vector */
1354 delta_m = 0;
1355 } else {
1356 /* vector */
1357 delta_m = delta_d;
1358 }
1359 }
1360 }
1361
1362 f0 = tcg_temp_new_i64();
1363 f1 = tcg_temp_new_i64();
1364 fd = tcg_temp_new_i64();
a84d1d13 1365 fpst = fpstatus_ptr(FPST_FPCR);
266bd25c
PM
1366
1367 neon_load_reg64(f0, vn);
1368 neon_load_reg64(f1, vm);
1369
1370 for (;;) {
1371 if (reads_vd) {
1372 neon_load_reg64(fd, vd);
1373 }
1374 fn(fd, f0, f1, fpst);
1375 neon_store_reg64(fd, vd);
1376
1377 if (veclen == 0) {
1378 break;
1379 }
1380 /* Set up the operands for the next iteration */
1381 veclen--;
18cf951a
PM
1382 vd = vfp_advance_dreg(vd, delta_d);
1383 vn = vfp_advance_dreg(vn, delta_d);
266bd25c
PM
1384 neon_load_reg64(f0, vn);
1385 if (delta_m) {
18cf951a 1386 vm = vfp_advance_dreg(vm, delta_m);
266bd25c
PM
1387 neon_load_reg64(f1, vm);
1388 }
1389 }
1390
1391 tcg_temp_free_i64(f0);
1392 tcg_temp_free_i64(f1);
1393 tcg_temp_free_i64(fd);
1394 tcg_temp_free_ptr(fpst);
1395
1396 return true;
1397}
1398
90287e22
PM
1399static bool do_vfp_2op_sp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
1400{
1401 uint32_t delta_m = 0;
1402 uint32_t delta_d = 0;
90287e22
PM
1403 int veclen = s->vec_len;
1404 TCGv_i32 f0, fd;
1405
82f6abe1
RH
1406 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1407 return false;
1408 }
1409
90287e22
PM
1410 if (!dc_isar_feature(aa32_fpshvec, s) &&
1411 (veclen != 0 || s->vec_stride != 0)) {
1412 return false;
1413 }
1414
1415 if (!vfp_access_check(s)) {
1416 return true;
1417 }
1418
1419 if (veclen > 0) {
90287e22 1420 /* Figure out what type of vector operation this is. */
18cf951a 1421 if (vfp_sreg_is_scalar(vd)) {
90287e22
PM
1422 /* scalar */
1423 veclen = 0;
1424 } else {
1425 delta_d = s->vec_stride + 1;
1426
18cf951a 1427 if (vfp_sreg_is_scalar(vm)) {
90287e22
PM
1428 /* mixed scalar/vector */
1429 delta_m = 0;
1430 } else {
1431 /* vector */
1432 delta_m = delta_d;
1433 }
1434 }
1435 }
1436
1437 f0 = tcg_temp_new_i32();
1438 fd = tcg_temp_new_i32();
1439
1440 neon_load_reg32(f0, vm);
1441
1442 for (;;) {
1443 fn(fd, f0);
1444 neon_store_reg32(fd, vd);
1445
1446 if (veclen == 0) {
1447 break;
1448 }
1449
1450 if (delta_m == 0) {
1451 /* single source one-many */
1452 while (veclen--) {
18cf951a 1453 vd = vfp_advance_sreg(vd, delta_d);
90287e22
PM
1454 neon_store_reg32(fd, vd);
1455 }
1456 break;
1457 }
1458
1459 /* Set up the operands for the next iteration */
1460 veclen--;
18cf951a
PM
1461 vd = vfp_advance_sreg(vd, delta_d);
1462 vm = vfp_advance_sreg(vm, delta_m);
90287e22
PM
1463 neon_load_reg32(f0, vm);
1464 }
1465
1466 tcg_temp_free_i32(f0);
1467 tcg_temp_free_i32(fd);
1468
1469 return true;
1470}
1471
1472static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm)
1473{
1474 uint32_t delta_m = 0;
1475 uint32_t delta_d = 0;
90287e22
PM
1476 int veclen = s->vec_len;
1477 TCGv_i64 f0, fd;
1478
799449ab 1479 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
90287e22
PM
1480 return false;
1481 }
1482
799449ab
RH
1483 /* UNDEF accesses to D16-D31 if they don't exist */
1484 if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) {
1120827f
PM
1485 return false;
1486 }
1487
90287e22
PM
1488 if (!dc_isar_feature(aa32_fpshvec, s) &&
1489 (veclen != 0 || s->vec_stride != 0)) {
1490 return false;
1491 }
1492
1493 if (!vfp_access_check(s)) {
1494 return true;
1495 }
1496
1497 if (veclen > 0) {
90287e22 1498 /* Figure out what type of vector operation this is. */
18cf951a 1499 if (vfp_dreg_is_scalar(vd)) {
90287e22
PM
1500 /* scalar */
1501 veclen = 0;
1502 } else {
1503 delta_d = (s->vec_stride >> 1) + 1;
1504
18cf951a 1505 if (vfp_dreg_is_scalar(vm)) {
90287e22
PM
1506 /* mixed scalar/vector */
1507 delta_m = 0;
1508 } else {
1509 /* vector */
1510 delta_m = delta_d;
1511 }
1512 }
1513 }
1514
1515 f0 = tcg_temp_new_i64();
1516 fd = tcg_temp_new_i64();
1517
1518 neon_load_reg64(f0, vm);
1519
1520 for (;;) {
1521 fn(fd, f0);
1522 neon_store_reg64(fd, vd);
1523
1524 if (veclen == 0) {
1525 break;
1526 }
1527
1528 if (delta_m == 0) {
1529 /* single source one-many */
1530 while (veclen--) {
18cf951a 1531 vd = vfp_advance_dreg(vd, delta_d);
90287e22
PM
1532 neon_store_reg64(fd, vd);
1533 }
1534 break;
1535 }
1536
1537 /* Set up the operands for the next iteration */
1538 veclen--;
18cf951a
PM
1539 vd = vfp_advance_dreg(vd, delta_d);
1540 vd = vfp_advance_dreg(vm, delta_m);
90287e22
PM
1541 neon_load_reg64(f0, vm);
1542 }
1543
1544 tcg_temp_free_i64(f0);
1545 tcg_temp_free_i64(fd);
1546
1547 return true;
1548}
1549
e7cb0ded
PM
1550static void gen_VMLA_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1551{
1552 /* Note that order of inputs to the add matters for NaNs */
1553 TCGv_i32 tmp = tcg_temp_new_i32();
1554
1555 gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1556 gen_helper_vfp_addh(vd, vd, tmp, fpst);
1557 tcg_temp_free_i32(tmp);
1558}
1559
1560static bool trans_VMLA_hp(DisasContext *s, arg_VMLA_sp *a)
1561{
1562 return do_vfp_3op_hp(s, gen_VMLA_hp, a->vd, a->vn, a->vm, true);
1563}
1564
266bd25c
PM
1565static void gen_VMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1566{
1567 /* Note that order of inputs to the add matters for NaNs */
1568 TCGv_i32 tmp = tcg_temp_new_i32();
1569
1570 gen_helper_vfp_muls(tmp, vn, vm, fpst);
1571 gen_helper_vfp_adds(vd, vd, tmp, fpst);
1572 tcg_temp_free_i32(tmp);
1573}
1574
1575static bool trans_VMLA_sp(DisasContext *s, arg_VMLA_sp *a)
1576{
1577 return do_vfp_3op_sp(s, gen_VMLA_sp, a->vd, a->vn, a->vm, true);
1578}
1579
1580static void gen_VMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1581{
1582 /* Note that order of inputs to the add matters for NaNs */
1583 TCGv_i64 tmp = tcg_temp_new_i64();
1584
1585 gen_helper_vfp_muld(tmp, vn, vm, fpst);
1586 gen_helper_vfp_addd(vd, vd, tmp, fpst);
1587 tcg_temp_free_i64(tmp);
1588}
1589
83655223 1590static bool trans_VMLA_dp(DisasContext *s, arg_VMLA_dp *a)
266bd25c
PM
1591{
1592 return do_vfp_3op_dp(s, gen_VMLA_dp, a->vd, a->vn, a->vm, true);
1593}
e7258280 1594
e7cb0ded
PM
1595static void gen_VMLS_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1596{
1597 /*
1598 * VMLS: vd = vd + -(vn * vm)
1599 * Note that order of inputs to the add matters for NaNs.
1600 */
1601 TCGv_i32 tmp = tcg_temp_new_i32();
1602
1603 gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1604 gen_helper_vfp_negh(tmp, tmp);
1605 gen_helper_vfp_addh(vd, vd, tmp, fpst);
1606 tcg_temp_free_i32(tmp);
1607}
1608
1609static bool trans_VMLS_hp(DisasContext *s, arg_VMLS_sp *a)
1610{
1611 return do_vfp_3op_hp(s, gen_VMLS_hp, a->vd, a->vn, a->vm, true);
1612}
1613
e7258280
PM
1614static void gen_VMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1615{
1616 /*
1617 * VMLS: vd = vd + -(vn * vm)
1618 * Note that order of inputs to the add matters for NaNs.
1619 */
1620 TCGv_i32 tmp = tcg_temp_new_i32();
1621
1622 gen_helper_vfp_muls(tmp, vn, vm, fpst);
1623 gen_helper_vfp_negs(tmp, tmp);
1624 gen_helper_vfp_adds(vd, vd, tmp, fpst);
1625 tcg_temp_free_i32(tmp);
1626}
1627
1628static bool trans_VMLS_sp(DisasContext *s, arg_VMLS_sp *a)
1629{
1630 return do_vfp_3op_sp(s, gen_VMLS_sp, a->vd, a->vn, a->vm, true);
1631}
1632
1633static void gen_VMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1634{
1635 /*
1636 * VMLS: vd = vd + -(vn * vm)
1637 * Note that order of inputs to the add matters for NaNs.
1638 */
1639 TCGv_i64 tmp = tcg_temp_new_i64();
1640
1641 gen_helper_vfp_muld(tmp, vn, vm, fpst);
1642 gen_helper_vfp_negd(tmp, tmp);
1643 gen_helper_vfp_addd(vd, vd, tmp, fpst);
1644 tcg_temp_free_i64(tmp);
1645}
1646
83655223 1647static bool trans_VMLS_dp(DisasContext *s, arg_VMLS_dp *a)
e7258280
PM
1648{
1649 return do_vfp_3op_dp(s, gen_VMLS_dp, a->vd, a->vn, a->vm, true);
1650}
c54a416c 1651
e7cb0ded
PM
1652static void gen_VNMLS_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1653{
1654 /*
1655 * VNMLS: -fd + (fn * fm)
1656 * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1657 * plausible looking simplifications because this will give wrong results
1658 * for NaNs.
1659 */
1660 TCGv_i32 tmp = tcg_temp_new_i32();
1661
1662 gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1663 gen_helper_vfp_negh(vd, vd);
1664 gen_helper_vfp_addh(vd, vd, tmp, fpst);
1665 tcg_temp_free_i32(tmp);
1666}
1667
1668static bool trans_VNMLS_hp(DisasContext *s, arg_VNMLS_sp *a)
1669{
1670 return do_vfp_3op_hp(s, gen_VNMLS_hp, a->vd, a->vn, a->vm, true);
1671}
1672
c54a416c
PM
1673static void gen_VNMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1674{
1675 /*
1676 * VNMLS: -fd + (fn * fm)
1677 * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1678 * plausible looking simplifications because this will give wrong results
1679 * for NaNs.
1680 */
1681 TCGv_i32 tmp = tcg_temp_new_i32();
1682
1683 gen_helper_vfp_muls(tmp, vn, vm, fpst);
1684 gen_helper_vfp_negs(vd, vd);
1685 gen_helper_vfp_adds(vd, vd, tmp, fpst);
1686 tcg_temp_free_i32(tmp);
1687}
1688
1689static bool trans_VNMLS_sp(DisasContext *s, arg_VNMLS_sp *a)
1690{
1691 return do_vfp_3op_sp(s, gen_VNMLS_sp, a->vd, a->vn, a->vm, true);
1692}
1693
1694static void gen_VNMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1695{
1696 /*
1697 * VNMLS: -fd + (fn * fm)
1698 * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1699 * plausible looking simplifications because this will give wrong results
1700 * for NaNs.
1701 */
1702 TCGv_i64 tmp = tcg_temp_new_i64();
1703
1704 gen_helper_vfp_muld(tmp, vn, vm, fpst);
1705 gen_helper_vfp_negd(vd, vd);
1706 gen_helper_vfp_addd(vd, vd, tmp, fpst);
1707 tcg_temp_free_i64(tmp);
1708}
1709
83655223 1710static bool trans_VNMLS_dp(DisasContext *s, arg_VNMLS_dp *a)
c54a416c
PM
1711{
1712 return do_vfp_3op_dp(s, gen_VNMLS_dp, a->vd, a->vn, a->vm, true);
1713}
8a483533 1714
e7cb0ded
PM
1715static void gen_VNMLA_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1716{
1717 /* VNMLA: -fd + -(fn * fm) */
1718 TCGv_i32 tmp = tcg_temp_new_i32();
1719
1720 gen_helper_vfp_mulh(tmp, vn, vm, fpst);
1721 gen_helper_vfp_negh(tmp, tmp);
1722 gen_helper_vfp_negh(vd, vd);
1723 gen_helper_vfp_addh(vd, vd, tmp, fpst);
1724 tcg_temp_free_i32(tmp);
1725}
1726
1727static bool trans_VNMLA_hp(DisasContext *s, arg_VNMLA_sp *a)
1728{
1729 return do_vfp_3op_hp(s, gen_VNMLA_hp, a->vd, a->vn, a->vm, true);
1730}
1731
8a483533
PM
1732static void gen_VNMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1733{
1734 /* VNMLA: -fd + -(fn * fm) */
1735 TCGv_i32 tmp = tcg_temp_new_i32();
1736
1737 gen_helper_vfp_muls(tmp, vn, vm, fpst);
1738 gen_helper_vfp_negs(tmp, tmp);
1739 gen_helper_vfp_negs(vd, vd);
1740 gen_helper_vfp_adds(vd, vd, tmp, fpst);
1741 tcg_temp_free_i32(tmp);
1742}
1743
1744static bool trans_VNMLA_sp(DisasContext *s, arg_VNMLA_sp *a)
1745{
1746 return do_vfp_3op_sp(s, gen_VNMLA_sp, a->vd, a->vn, a->vm, true);
1747}
1748
1749static void gen_VNMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1750{
1751 /* VNMLA: -fd + (fn * fm) */
1752 TCGv_i64 tmp = tcg_temp_new_i64();
1753
1754 gen_helper_vfp_muld(tmp, vn, vm, fpst);
1755 gen_helper_vfp_negd(tmp, tmp);
1756 gen_helper_vfp_negd(vd, vd);
1757 gen_helper_vfp_addd(vd, vd, tmp, fpst);
1758 tcg_temp_free_i64(tmp);
1759}
1760
83655223 1761static bool trans_VNMLA_dp(DisasContext *s, arg_VNMLA_dp *a)
8a483533
PM
1762{
1763 return do_vfp_3op_dp(s, gen_VNMLA_dp, a->vd, a->vn, a->vm, true);
1764}
88c5188c 1765
120a0eb3
PM
1766static bool trans_VMUL_hp(DisasContext *s, arg_VMUL_sp *a)
1767{
1768 return do_vfp_3op_hp(s, gen_helper_vfp_mulh, a->vd, a->vn, a->vm, false);
1769}
1770
88c5188c
PM
1771static bool trans_VMUL_sp(DisasContext *s, arg_VMUL_sp *a)
1772{
1773 return do_vfp_3op_sp(s, gen_helper_vfp_muls, a->vd, a->vn, a->vm, false);
1774}
1775
83655223 1776static bool trans_VMUL_dp(DisasContext *s, arg_VMUL_dp *a)
88c5188c
PM
1777{
1778 return do_vfp_3op_dp(s, gen_helper_vfp_muld, a->vd, a->vn, a->vm, false);
1779}
43c4be12 1780
e7cb0ded
PM
1781static void gen_VNMUL_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1782{
1783 /* VNMUL: -(fn * fm) */
1784 gen_helper_vfp_mulh(vd, vn, vm, fpst);
1785 gen_helper_vfp_negh(vd, vd);
1786}
1787
1788static bool trans_VNMUL_hp(DisasContext *s, arg_VNMUL_sp *a)
1789{
1790 return do_vfp_3op_hp(s, gen_VNMUL_hp, a->vd, a->vn, a->vm, false);
1791}
1792
43c4be12
PM
1793static void gen_VNMUL_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1794{
1795 /* VNMUL: -(fn * fm) */
1796 gen_helper_vfp_muls(vd, vn, vm, fpst);
1797 gen_helper_vfp_negs(vd, vd);
1798}
1799
1800static bool trans_VNMUL_sp(DisasContext *s, arg_VNMUL_sp *a)
1801{
1802 return do_vfp_3op_sp(s, gen_VNMUL_sp, a->vd, a->vn, a->vm, false);
1803}
1804
1805static void gen_VNMUL_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1806{
1807 /* VNMUL: -(fn * fm) */
1808 gen_helper_vfp_muld(vd, vn, vm, fpst);
1809 gen_helper_vfp_negd(vd, vd);
1810}
1811
83655223 1812static bool trans_VNMUL_dp(DisasContext *s, arg_VNMUL_dp *a)
43c4be12
PM
1813{
1814 return do_vfp_3op_dp(s, gen_VNMUL_dp, a->vd, a->vn, a->vm, false);
1815}
ce28b303 1816
120a0eb3
PM
1817static bool trans_VADD_hp(DisasContext *s, arg_VADD_sp *a)
1818{
1819 return do_vfp_3op_hp(s, gen_helper_vfp_addh, a->vd, a->vn, a->vm, false);
1820}
1821
ce28b303
PM
1822static bool trans_VADD_sp(DisasContext *s, arg_VADD_sp *a)
1823{
1824 return do_vfp_3op_sp(s, gen_helper_vfp_adds, a->vd, a->vn, a->vm, false);
1825}
1826
83655223 1827static bool trans_VADD_dp(DisasContext *s, arg_VADD_dp *a)
ce28b303
PM
1828{
1829 return do_vfp_3op_dp(s, gen_helper_vfp_addd, a->vd, a->vn, a->vm, false);
1830}
8fec9a11 1831
120a0eb3
PM
1832static bool trans_VSUB_hp(DisasContext *s, arg_VSUB_sp *a)
1833{
1834 return do_vfp_3op_hp(s, gen_helper_vfp_subh, a->vd, a->vn, a->vm, false);
1835}
1836
8fec9a11
PM
1837static bool trans_VSUB_sp(DisasContext *s, arg_VSUB_sp *a)
1838{
1839 return do_vfp_3op_sp(s, gen_helper_vfp_subs, a->vd, a->vn, a->vm, false);
1840}
1841
83655223 1842static bool trans_VSUB_dp(DisasContext *s, arg_VSUB_dp *a)
8fec9a11
PM
1843{
1844 return do_vfp_3op_dp(s, gen_helper_vfp_subd, a->vd, a->vn, a->vm, false);
1845}
519ee7ae 1846
120a0eb3
PM
1847static bool trans_VDIV_hp(DisasContext *s, arg_VDIV_sp *a)
1848{
1849 return do_vfp_3op_hp(s, gen_helper_vfp_divh, a->vd, a->vn, a->vm, false);
1850}
1851
519ee7ae
PM
1852static bool trans_VDIV_sp(DisasContext *s, arg_VDIV_sp *a)
1853{
1854 return do_vfp_3op_sp(s, gen_helper_vfp_divs, a->vd, a->vn, a->vm, false);
1855}
1856
83655223 1857static bool trans_VDIV_dp(DisasContext *s, arg_VDIV_dp *a)
519ee7ae
PM
1858{
1859 return do_vfp_3op_dp(s, gen_helper_vfp_divd, a->vd, a->vn, a->vm, false);
1860}
d4893b01 1861
120a0eb3
PM
1862static bool trans_VMINNM_hp(DisasContext *s, arg_VMINNM_sp *a)
1863{
1864 if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1865 return false;
1866 }
1867 return do_vfp_3op_hp(s, gen_helper_vfp_minnumh,
1868 a->vd, a->vn, a->vm, false);
1869}
1870
1871static bool trans_VMAXNM_hp(DisasContext *s, arg_VMAXNM_sp *a)
1872{
1873 if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1874 return false;
1875 }
1876 return do_vfp_3op_hp(s, gen_helper_vfp_maxnumh,
1877 a->vd, a->vn, a->vm, false);
1878}
1879
f2eafb75
RH
1880static bool trans_VMINNM_sp(DisasContext *s, arg_VMINNM_sp *a)
1881{
1882 if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1883 return false;
1884 }
1885 return do_vfp_3op_sp(s, gen_helper_vfp_minnums,
1886 a->vd, a->vn, a->vm, false);
1887}
1888
1889static bool trans_VMAXNM_sp(DisasContext *s, arg_VMAXNM_sp *a)
1890{
1891 if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1892 return false;
1893 }
1894 return do_vfp_3op_sp(s, gen_helper_vfp_maxnums,
1895 a->vd, a->vn, a->vm, false);
1896}
1897
1898static bool trans_VMINNM_dp(DisasContext *s, arg_VMINNM_dp *a)
1899{
1900 if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1901 return false;
1902 }
1903 return do_vfp_3op_dp(s, gen_helper_vfp_minnumd,
1904 a->vd, a->vn, a->vm, false);
1905}
1906
1907static bool trans_VMAXNM_dp(DisasContext *s, arg_VMAXNM_dp *a)
1908{
1909 if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1910 return false;
1911 }
1912 return do_vfp_3op_dp(s, gen_helper_vfp_maxnumd,
1913 a->vd, a->vn, a->vm, false);
1914}
1915
d486f830 1916static bool do_vfm_sp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
d4893b01
PM
1917{
1918 /*
1919 * VFNMA : fd = muladd(-fd, fn, fm)
1920 * VFNMS : fd = muladd(-fd, -fn, fm)
1921 * VFMA : fd = muladd( fd, fn, fm)
1922 * VFMS : fd = muladd( fd, -fn, fm)
1923 *
1924 * These are fused multiply-add, and must be done as one floating
1925 * point operation with no rounding between the multiplication and
1926 * addition steps. NB that doing the negations here as separate
1927 * steps is correct : an input NaN should come out with its sign
1928 * bit flipped if it is a negated-input.
1929 */
1930 TCGv_ptr fpst;
1931 TCGv_i32 vn, vm, vd;
1932
1933 /*
1934 * Present in VFPv4 only.
c52881bb
RH
1935 * Note that we can't rely on the SIMDFMAC check alone, because
1936 * in a Neon-no-VFP core that ID register field will be non-zero.
1937 */
1938 if (!dc_isar_feature(aa32_simdfmac, s) ||
1939 !dc_isar_feature(aa32_fpsp_v2, s)) {
1940 return false;
1941 }
1942 /*
d4893b01
PM
1943 * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
1944 * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
1945 */
c52881bb 1946 if (s->vec_len != 0 || s->vec_stride != 0) {
d4893b01
PM
1947 return false;
1948 }
1949
1950 if (!vfp_access_check(s)) {
1951 return true;
1952 }
1953
1954 vn = tcg_temp_new_i32();
1955 vm = tcg_temp_new_i32();
1956 vd = tcg_temp_new_i32();
1957
1958 neon_load_reg32(vn, a->vn);
1959 neon_load_reg32(vm, a->vm);
d486f830 1960 if (neg_n) {
d4893b01
PM
1961 /* VFNMS, VFMS */
1962 gen_helper_vfp_negs(vn, vn);
1963 }
1964 neon_load_reg32(vd, a->vd);
d486f830 1965 if (neg_d) {
d4893b01
PM
1966 /* VFNMA, VFNMS */
1967 gen_helper_vfp_negs(vd, vd);
1968 }
a84d1d13 1969 fpst = fpstatus_ptr(FPST_FPCR);
d4893b01
PM
1970 gen_helper_vfp_muladds(vd, vn, vm, vd, fpst);
1971 neon_store_reg32(vd, a->vd);
1972
1973 tcg_temp_free_ptr(fpst);
1974 tcg_temp_free_i32(vn);
1975 tcg_temp_free_i32(vm);
1976 tcg_temp_free_i32(vd);
1977
1978 return true;
1979}
1980
d486f830
RH
1981static bool trans_VFMA_sp(DisasContext *s, arg_VFMA_sp *a)
1982{
1983 return do_vfm_sp(s, a, false, false);
1984}
1985
1986static bool trans_VFMS_sp(DisasContext *s, arg_VFMS_sp *a)
1987{
1988 return do_vfm_sp(s, a, true, false);
1989}
1990
1991static bool trans_VFNMA_sp(DisasContext *s, arg_VFNMA_sp *a)
1992{
1993 return do_vfm_sp(s, a, false, true);
1994}
1995
1996static bool trans_VFNMS_sp(DisasContext *s, arg_VFNMS_sp *a)
1997{
1998 return do_vfm_sp(s, a, true, true);
1999}
2000
2001static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d)
d4893b01
PM
2002{
2003 /*
2004 * VFNMA : fd = muladd(-fd, fn, fm)
2005 * VFNMS : fd = muladd(-fd, -fn, fm)
2006 * VFMA : fd = muladd( fd, fn, fm)
2007 * VFMS : fd = muladd( fd, -fn, fm)
2008 *
2009 * These are fused multiply-add, and must be done as one floating
2010 * point operation with no rounding between the multiplication and
2011 * addition steps. NB that doing the negations here as separate
2012 * steps is correct : an input NaN should come out with its sign
2013 * bit flipped if it is a negated-input.
2014 */
2015 TCGv_ptr fpst;
2016 TCGv_i64 vn, vm, vd;
2017
2018 /*
2019 * Present in VFPv4 only.
c52881bb
RH
2020 * Note that we can't rely on the SIMDFMAC check alone, because
2021 * in a Neon-no-VFP core that ID register field will be non-zero.
2022 */
2023 if (!dc_isar_feature(aa32_simdfmac, s) ||
2024 !dc_isar_feature(aa32_fpdp_v2, s)) {
2025 return false;
2026 }
2027 /*
d4893b01
PM
2028 * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
2029 * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
2030 */
c52881bb 2031 if (s->vec_len != 0 || s->vec_stride != 0) {
d4893b01
PM
2032 return false;
2033 }
2034
2035 /* UNDEF accesses to D16-D31 if they don't exist. */
0e13ba78
RH
2036 if (!dc_isar_feature(aa32_simd_r32, s) &&
2037 ((a->vd | a->vn | a->vm) & 0x10)) {
d4893b01
PM
2038 return false;
2039 }
2040
2041 if (!vfp_access_check(s)) {
2042 return true;
2043 }
2044
2045 vn = tcg_temp_new_i64();
2046 vm = tcg_temp_new_i64();
2047 vd = tcg_temp_new_i64();
2048
2049 neon_load_reg64(vn, a->vn);
2050 neon_load_reg64(vm, a->vm);
d486f830 2051 if (neg_n) {
d4893b01
PM
2052 /* VFNMS, VFMS */
2053 gen_helper_vfp_negd(vn, vn);
2054 }
2055 neon_load_reg64(vd, a->vd);
d486f830 2056 if (neg_d) {
d4893b01
PM
2057 /* VFNMA, VFNMS */
2058 gen_helper_vfp_negd(vd, vd);
2059 }
a84d1d13 2060 fpst = fpstatus_ptr(FPST_FPCR);
d4893b01
PM
2061 gen_helper_vfp_muladdd(vd, vn, vm, vd, fpst);
2062 neon_store_reg64(vd, a->vd);
2063
2064 tcg_temp_free_ptr(fpst);
2065 tcg_temp_free_i64(vn);
2066 tcg_temp_free_i64(vm);
2067 tcg_temp_free_i64(vd);
2068
2069 return true;
2070}
b518c753 2071
d486f830
RH
2072static bool trans_VFMA_dp(DisasContext *s, arg_VFMA_dp *a)
2073{
2074 return do_vfm_dp(s, a, false, false);
2075}
2076
2077static bool trans_VFMS_dp(DisasContext *s, arg_VFMS_dp *a)
2078{
2079 return do_vfm_dp(s, a, true, false);
2080}
2081
2082static bool trans_VFNMA_dp(DisasContext *s, arg_VFNMA_dp *a)
2083{
2084 return do_vfm_dp(s, a, false, true);
2085}
2086
2087static bool trans_VFNMS_dp(DisasContext *s, arg_VFNMS_dp *a)
2088{
2089 return do_vfm_dp(s, a, true, true);
2090}
2091
b518c753
PM
2092static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
2093{
2094 uint32_t delta_d = 0;
b518c753
PM
2095 int veclen = s->vec_len;
2096 TCGv_i32 fd;
9bee50b4 2097 uint32_t vd;
b518c753
PM
2098
2099 vd = a->vd;
2100
84774cc3 2101 if (!dc_isar_feature(aa32_fpsp_v3, s)) {
b518c753
PM
2102 return false;
2103 }
2104
84774cc3
RH
2105 if (!dc_isar_feature(aa32_fpshvec, s) &&
2106 (veclen != 0 || s->vec_stride != 0)) {
b518c753
PM
2107 return false;
2108 }
2109
2110 if (!vfp_access_check(s)) {
2111 return true;
2112 }
2113
2114 if (veclen > 0) {
b518c753 2115 /* Figure out what type of vector operation this is. */
18cf951a 2116 if (vfp_sreg_is_scalar(vd)) {
b518c753
PM
2117 /* scalar */
2118 veclen = 0;
2119 } else {
2120 delta_d = s->vec_stride + 1;
2121 }
2122 }
2123
9bee50b4 2124 fd = tcg_const_i32(vfp_expand_imm(MO_32, a->imm));
b518c753
PM
2125
2126 for (;;) {
2127 neon_store_reg32(fd, vd);
2128
2129 if (veclen == 0) {
2130 break;
2131 }
2132
2133 /* Set up the operands for the next iteration */
2134 veclen--;
18cf951a 2135 vd = vfp_advance_sreg(vd, delta_d);
b518c753
PM
2136 }
2137
2138 tcg_temp_free_i32(fd);
2139 return true;
2140}
2141
2142static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
2143{
2144 uint32_t delta_d = 0;
b518c753
PM
2145 int veclen = s->vec_len;
2146 TCGv_i64 fd;
9bee50b4 2147 uint32_t vd;
b518c753
PM
2148
2149 vd = a->vd;
2150
84774cc3 2151 if (!dc_isar_feature(aa32_fpdp_v3, s)) {
b518c753
PM
2152 return false;
2153 }
2154
799449ab
RH
2155 /* UNDEF accesses to D16-D31 if they don't exist. */
2156 if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) {
1120827f
PM
2157 return false;
2158 }
2159
b518c753
PM
2160 if (!dc_isar_feature(aa32_fpshvec, s) &&
2161 (veclen != 0 || s->vec_stride != 0)) {
2162 return false;
2163 }
2164
b518c753
PM
2165 if (!vfp_access_check(s)) {
2166 return true;
2167 }
2168
2169 if (veclen > 0) {
b518c753 2170 /* Figure out what type of vector operation this is. */
18cf951a 2171 if (vfp_dreg_is_scalar(vd)) {
b518c753
PM
2172 /* scalar */
2173 veclen = 0;
2174 } else {
2175 delta_d = (s->vec_stride >> 1) + 1;
2176 }
2177 }
2178
9bee50b4 2179 fd = tcg_const_i64(vfp_expand_imm(MO_64, a->imm));
b518c753
PM
2180
2181 for (;;) {
2182 neon_store_reg64(fd, vd);
2183
2184 if (veclen == 0) {
2185 break;
2186 }
2187
2188 /* Set up the operands for the next iteration */
2189 veclen--;
89a11ff7 2190 vd = vfp_advance_dreg(vd, delta_d);
b518c753
PM
2191 }
2192
2193 tcg_temp_free_i64(fd);
2194 return true;
2195}
90287e22 2196
17552b97
PM
2197static bool trans_VMOV_reg_sp(DisasContext *s, arg_VMOV_reg_sp *a)
2198{
2199 return do_vfp_2op_sp(s, tcg_gen_mov_i32, a->vd, a->vm);
2200}
2201
2202static bool trans_VMOV_reg_dp(DisasContext *s, arg_VMOV_reg_dp *a)
2203{
2204 return do_vfp_2op_dp(s, tcg_gen_mov_i64, a->vd, a->vm);
2205}
2206
90287e22
PM
2207static bool trans_VABS_sp(DisasContext *s, arg_VABS_sp *a)
2208{
2209 return do_vfp_2op_sp(s, gen_helper_vfp_abss, a->vd, a->vm);
2210}
2211
2212static bool trans_VABS_dp(DisasContext *s, arg_VABS_dp *a)
2213{
2214 return do_vfp_2op_dp(s, gen_helper_vfp_absd, a->vd, a->vm);
2215}
1882651a
PM
2216
2217static bool trans_VNEG_sp(DisasContext *s, arg_VNEG_sp *a)
2218{
2219 return do_vfp_2op_sp(s, gen_helper_vfp_negs, a->vd, a->vm);
2220}
2221
2222static bool trans_VNEG_dp(DisasContext *s, arg_VNEG_dp *a)
2223{
2224 return do_vfp_2op_dp(s, gen_helper_vfp_negd, a->vd, a->vm);
2225}
b8474540
PM
2226
2227static void gen_VSQRT_sp(TCGv_i32 vd, TCGv_i32 vm)
2228{
2229 gen_helper_vfp_sqrts(vd, vm, cpu_env);
2230}
2231
2232static bool trans_VSQRT_sp(DisasContext *s, arg_VSQRT_sp *a)
2233{
2234 return do_vfp_2op_sp(s, gen_VSQRT_sp, a->vd, a->vm);
2235}
2236
2237static void gen_VSQRT_dp(TCGv_i64 vd, TCGv_i64 vm)
2238{
2239 gen_helper_vfp_sqrtd(vd, vm, cpu_env);
2240}
2241
2242static bool trans_VSQRT_dp(DisasContext *s, arg_VSQRT_dp *a)
2243{
2244 return do_vfp_2op_dp(s, gen_VSQRT_dp, a->vd, a->vm);
2245}
386bba23
PM
2246
2247static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a)
2248{
2249 TCGv_i32 vd, vm;
2250
82f6abe1
RH
2251 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2252 return false;
2253 }
2254
386bba23
PM
2255 /* Vm/M bits must be zero for the Z variant */
2256 if (a->z && a->vm != 0) {
2257 return false;
2258 }
2259
2260 if (!vfp_access_check(s)) {
2261 return true;
2262 }
2263
2264 vd = tcg_temp_new_i32();
2265 vm = tcg_temp_new_i32();
2266
2267 neon_load_reg32(vd, a->vd);
2268 if (a->z) {
2269 tcg_gen_movi_i32(vm, 0);
2270 } else {
2271 neon_load_reg32(vm, a->vm);
2272 }
2273
2274 if (a->e) {
2275 gen_helper_vfp_cmpes(vd, vm, cpu_env);
2276 } else {
2277 gen_helper_vfp_cmps(vd, vm, cpu_env);
2278 }
2279
2280 tcg_temp_free_i32(vd);
2281 tcg_temp_free_i32(vm);
2282
2283 return true;
2284}
2285
2286static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a)
2287{
2288 TCGv_i64 vd, vm;
2289
799449ab
RH
2290 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2291 return false;
2292 }
2293
386bba23
PM
2294 /* Vm/M bits must be zero for the Z variant */
2295 if (a->z && a->vm != 0) {
2296 return false;
2297 }
2298
2299 /* UNDEF accesses to D16-D31 if they don't exist. */
0e13ba78 2300 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
386bba23
PM
2301 return false;
2302 }
2303
2304 if (!vfp_access_check(s)) {
2305 return true;
2306 }
2307
2308 vd = tcg_temp_new_i64();
2309 vm = tcg_temp_new_i64();
2310
2311 neon_load_reg64(vd, a->vd);
2312 if (a->z) {
2313 tcg_gen_movi_i64(vm, 0);
2314 } else {
2315 neon_load_reg64(vm, a->vm);
2316 }
2317
2318 if (a->e) {
2319 gen_helper_vfp_cmped(vd, vm, cpu_env);
2320 } else {
2321 gen_helper_vfp_cmpd(vd, vm, cpu_env);
2322 }
2323
2324 tcg_temp_free_i64(vd);
2325 tcg_temp_free_i64(vm);
2326
2327 return true;
2328}
b623d803
PM
2329
2330static bool trans_VCVT_f32_f16(DisasContext *s, arg_VCVT_f32_f16 *a)
2331{
2332 TCGv_ptr fpst;
2333 TCGv_i32 ahp_mode;
2334 TCGv_i32 tmp;
2335
2336 if (!dc_isar_feature(aa32_fp16_spconv, s)) {
2337 return false;
2338 }
2339
2340 if (!vfp_access_check(s)) {
2341 return true;
2342 }
2343
a84d1d13 2344 fpst = fpstatus_ptr(FPST_FPCR);
b623d803
PM
2345 ahp_mode = get_ahp_flag();
2346 tmp = tcg_temp_new_i32();
2347 /* The T bit tells us if we want the low or high 16 bits of Vm */
2348 tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t));
2349 gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp_mode);
2350 neon_store_reg32(tmp, a->vd);
2351 tcg_temp_free_i32(ahp_mode);
2352 tcg_temp_free_ptr(fpst);
2353 tcg_temp_free_i32(tmp);
2354 return true;
2355}
2356
2357static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a)
2358{
2359 TCGv_ptr fpst;
2360 TCGv_i32 ahp_mode;
2361 TCGv_i32 tmp;
2362 TCGv_i64 vd;
2363
799449ab 2364 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
b623d803
PM
2365 return false;
2366 }
2367
799449ab 2368 if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
b623d803
PM
2369 return false;
2370 }
2371
799449ab
RH
2372 /* UNDEF accesses to D16-D31 if they don't exist. */
2373 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
1120827f
PM
2374 return false;
2375 }
2376
b623d803
PM
2377 if (!vfp_access_check(s)) {
2378 return true;
2379 }
2380
a84d1d13 2381 fpst = fpstatus_ptr(FPST_FPCR);
b623d803
PM
2382 ahp_mode = get_ahp_flag();
2383 tmp = tcg_temp_new_i32();
2384 /* The T bit tells us if we want the low or high 16 bits of Vm */
2385 tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t));
2386 vd = tcg_temp_new_i64();
2387 gen_helper_vfp_fcvt_f16_to_f64(vd, tmp, fpst, ahp_mode);
2388 neon_store_reg64(vd, a->vd);
2389 tcg_temp_free_i32(ahp_mode);
2390 tcg_temp_free_ptr(fpst);
2391 tcg_temp_free_i32(tmp);
2392 tcg_temp_free_i64(vd);
2393 return true;
2394}
cdfd14e8
PM
2395
2396static bool trans_VCVT_f16_f32(DisasContext *s, arg_VCVT_f16_f32 *a)
2397{
2398 TCGv_ptr fpst;
2399 TCGv_i32 ahp_mode;
2400 TCGv_i32 tmp;
2401
2402 if (!dc_isar_feature(aa32_fp16_spconv, s)) {
2403 return false;
2404 }
2405
2406 if (!vfp_access_check(s)) {
2407 return true;
2408 }
2409
a84d1d13 2410 fpst = fpstatus_ptr(FPST_FPCR);
cdfd14e8
PM
2411 ahp_mode = get_ahp_flag();
2412 tmp = tcg_temp_new_i32();
2413
2414 neon_load_reg32(tmp, a->vm);
2415 gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp_mode);
2416 tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t));
2417 tcg_temp_free_i32(ahp_mode);
2418 tcg_temp_free_ptr(fpst);
2419 tcg_temp_free_i32(tmp);
2420 return true;
2421}
2422
2423static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a)
2424{
2425 TCGv_ptr fpst;
2426 TCGv_i32 ahp_mode;
2427 TCGv_i32 tmp;
2428 TCGv_i64 vm;
2429
799449ab 2430 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
cdfd14e8
PM
2431 return false;
2432 }
2433
799449ab 2434 if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
cdfd14e8
PM
2435 return false;
2436 }
2437
799449ab
RH
2438 /* UNDEF accesses to D16-D31 if they don't exist. */
2439 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
1120827f
PM
2440 return false;
2441 }
2442
cdfd14e8
PM
2443 if (!vfp_access_check(s)) {
2444 return true;
2445 }
2446
a84d1d13 2447 fpst = fpstatus_ptr(FPST_FPCR);
cdfd14e8
PM
2448 ahp_mode = get_ahp_flag();
2449 tmp = tcg_temp_new_i32();
2450 vm = tcg_temp_new_i64();
2451
2452 neon_load_reg64(vm, a->vm);
2453 gen_helper_vfp_fcvt_f64_to_f16(tmp, vm, fpst, ahp_mode);
2454 tcg_temp_free_i64(vm);
2455 tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t));
2456 tcg_temp_free_i32(ahp_mode);
2457 tcg_temp_free_ptr(fpst);
2458 tcg_temp_free_i32(tmp);
2459 return true;
2460}
e25155f5
PM
2461
2462static bool trans_VRINTR_sp(DisasContext *s, arg_VRINTR_sp *a)
2463{
2464 TCGv_ptr fpst;
2465 TCGv_i32 tmp;
2466
2467 if (!dc_isar_feature(aa32_vrint, s)) {
2468 return false;
2469 }
2470
2471 if (!vfp_access_check(s)) {
2472 return true;
2473 }
2474
2475 tmp = tcg_temp_new_i32();
2476 neon_load_reg32(tmp, a->vm);
a84d1d13 2477 fpst = fpstatus_ptr(FPST_FPCR);
e25155f5
PM
2478 gen_helper_rints(tmp, tmp, fpst);
2479 neon_store_reg32(tmp, a->vd);
2480 tcg_temp_free_ptr(fpst);
2481 tcg_temp_free_i32(tmp);
2482 return true;
2483}
2484
83655223 2485static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a)
e25155f5
PM
2486{
2487 TCGv_ptr fpst;
2488 TCGv_i64 tmp;
2489
799449ab 2490 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
e25155f5
PM
2491 return false;
2492 }
2493
799449ab 2494 if (!dc_isar_feature(aa32_vrint, s)) {
e25155f5
PM
2495 return false;
2496 }
2497
799449ab
RH
2498 /* UNDEF accesses to D16-D31 if they don't exist. */
2499 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
1120827f
PM
2500 return false;
2501 }
2502
e25155f5
PM
2503 if (!vfp_access_check(s)) {
2504 return true;
2505 }
2506
2507 tmp = tcg_temp_new_i64();
2508 neon_load_reg64(tmp, a->vm);
a84d1d13 2509 fpst = fpstatus_ptr(FPST_FPCR);
e25155f5
PM
2510 gen_helper_rintd(tmp, tmp, fpst);
2511 neon_store_reg64(tmp, a->vd);
2512 tcg_temp_free_ptr(fpst);
2513 tcg_temp_free_i64(tmp);
2514 return true;
2515}
2516
2517static bool trans_VRINTZ_sp(DisasContext *s, arg_VRINTZ_sp *a)
2518{
2519 TCGv_ptr fpst;
2520 TCGv_i32 tmp;
2521 TCGv_i32 tcg_rmode;
2522
2523 if (!dc_isar_feature(aa32_vrint, s)) {
2524 return false;
2525 }
2526
2527 if (!vfp_access_check(s)) {
2528 return true;
2529 }
2530
2531 tmp = tcg_temp_new_i32();
2532 neon_load_reg32(tmp, a->vm);
a84d1d13 2533 fpst = fpstatus_ptr(FPST_FPCR);
e25155f5
PM
2534 tcg_rmode = tcg_const_i32(float_round_to_zero);
2535 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2536 gen_helper_rints(tmp, tmp, fpst);
2537 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2538 neon_store_reg32(tmp, a->vd);
2539 tcg_temp_free_ptr(fpst);
2540 tcg_temp_free_i32(tcg_rmode);
2541 tcg_temp_free_i32(tmp);
2542 return true;
2543}
2544
83655223 2545static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a)
e25155f5
PM
2546{
2547 TCGv_ptr fpst;
2548 TCGv_i64 tmp;
2549 TCGv_i32 tcg_rmode;
2550
799449ab 2551 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
e25155f5
PM
2552 return false;
2553 }
2554
799449ab 2555 if (!dc_isar_feature(aa32_vrint, s)) {
e25155f5
PM
2556 return false;
2557 }
2558
799449ab
RH
2559 /* UNDEF accesses to D16-D31 if they don't exist. */
2560 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
1120827f
PM
2561 return false;
2562 }
2563
e25155f5
PM
2564 if (!vfp_access_check(s)) {
2565 return true;
2566 }
2567
2568 tmp = tcg_temp_new_i64();
2569 neon_load_reg64(tmp, a->vm);
a84d1d13 2570 fpst = fpstatus_ptr(FPST_FPCR);
e25155f5
PM
2571 tcg_rmode = tcg_const_i32(float_round_to_zero);
2572 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2573 gen_helper_rintd(tmp, tmp, fpst);
2574 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2575 neon_store_reg64(tmp, a->vd);
2576 tcg_temp_free_ptr(fpst);
2577 tcg_temp_free_i64(tmp);
2578 tcg_temp_free_i32(tcg_rmode);
2579 return true;
2580}
2581
2582static bool trans_VRINTX_sp(DisasContext *s, arg_VRINTX_sp *a)
2583{
2584 TCGv_ptr fpst;
2585 TCGv_i32 tmp;
2586
2587 if (!dc_isar_feature(aa32_vrint, s)) {
2588 return false;
2589 }
2590
2591 if (!vfp_access_check(s)) {
2592 return true;
2593 }
2594
2595 tmp = tcg_temp_new_i32();
2596 neon_load_reg32(tmp, a->vm);
a84d1d13 2597 fpst = fpstatus_ptr(FPST_FPCR);
e25155f5
PM
2598 gen_helper_rints_exact(tmp, tmp, fpst);
2599 neon_store_reg32(tmp, a->vd);
2600 tcg_temp_free_ptr(fpst);
2601 tcg_temp_free_i32(tmp);
2602 return true;
2603}
2604
2605static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a)
2606{
2607 TCGv_ptr fpst;
2608 TCGv_i64 tmp;
2609
799449ab 2610 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
e25155f5
PM
2611 return false;
2612 }
2613
799449ab 2614 if (!dc_isar_feature(aa32_vrint, s)) {
e25155f5
PM
2615 return false;
2616 }
2617
799449ab
RH
2618 /* UNDEF accesses to D16-D31 if they don't exist. */
2619 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
1120827f
PM
2620 return false;
2621 }
2622
e25155f5
PM
2623 if (!vfp_access_check(s)) {
2624 return true;
2625 }
2626
2627 tmp = tcg_temp_new_i64();
2628 neon_load_reg64(tmp, a->vm);
a84d1d13 2629 fpst = fpstatus_ptr(FPST_FPCR);
e25155f5
PM
2630 gen_helper_rintd_exact(tmp, tmp, fpst);
2631 neon_store_reg64(tmp, a->vd);
2632 tcg_temp_free_ptr(fpst);
2633 tcg_temp_free_i64(tmp);
2634 return true;
2635}
6ed7e49c
PM
2636
2637static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a)
2638{
2639 TCGv_i64 vd;
2640 TCGv_i32 vm;
2641
799449ab 2642 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
6ed7e49c
PM
2643 return false;
2644 }
2645
799449ab
RH
2646 /* UNDEF accesses to D16-D31 if they don't exist. */
2647 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
1120827f
PM
2648 return false;
2649 }
2650
6ed7e49c
PM
2651 if (!vfp_access_check(s)) {
2652 return true;
2653 }
2654
2655 vm = tcg_temp_new_i32();
2656 vd = tcg_temp_new_i64();
2657 neon_load_reg32(vm, a->vm);
2658 gen_helper_vfp_fcvtds(vd, vm, cpu_env);
2659 neon_store_reg64(vd, a->vd);
2660 tcg_temp_free_i32(vm);
2661 tcg_temp_free_i64(vd);
2662 return true;
2663}
2664
2665static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a)
2666{
2667 TCGv_i64 vm;
2668 TCGv_i32 vd;
2669
799449ab 2670 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
6ed7e49c
PM
2671 return false;
2672 }
2673
799449ab
RH
2674 /* UNDEF accesses to D16-D31 if they don't exist. */
2675 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
1120827f
PM
2676 return false;
2677 }
2678
6ed7e49c
PM
2679 if (!vfp_access_check(s)) {
2680 return true;
2681 }
2682
2683 vd = tcg_temp_new_i32();
2684 vm = tcg_temp_new_i64();
2685 neon_load_reg64(vm, a->vm);
2686 gen_helper_vfp_fcvtsd(vd, vm, cpu_env);
2687 neon_store_reg32(vd, a->vd);
2688 tcg_temp_free_i32(vd);
2689 tcg_temp_free_i64(vm);
2690 return true;
2691}
8fc9d891
PM
2692
2693static bool trans_VCVT_int_sp(DisasContext *s, arg_VCVT_int_sp *a)
2694{
2695 TCGv_i32 vm;
2696 TCGv_ptr fpst;
2697
82f6abe1
RH
2698 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2699 return false;
2700 }
2701
8fc9d891
PM
2702 if (!vfp_access_check(s)) {
2703 return true;
2704 }
2705
2706 vm = tcg_temp_new_i32();
2707 neon_load_reg32(vm, a->vm);
a84d1d13 2708 fpst = fpstatus_ptr(FPST_FPCR);
8fc9d891
PM
2709 if (a->s) {
2710 /* i32 -> f32 */
2711 gen_helper_vfp_sitos(vm, vm, fpst);
2712 } else {
2713 /* u32 -> f32 */
2714 gen_helper_vfp_uitos(vm, vm, fpst);
2715 }
2716 neon_store_reg32(vm, a->vd);
2717 tcg_temp_free_i32(vm);
2718 tcg_temp_free_ptr(fpst);
2719 return true;
2720}
2721
2722static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a)
2723{
2724 TCGv_i32 vm;
2725 TCGv_i64 vd;
2726 TCGv_ptr fpst;
2727
799449ab 2728 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
8fc9d891
PM
2729 return false;
2730 }
2731
799449ab
RH
2732 /* UNDEF accesses to D16-D31 if they don't exist. */
2733 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
1120827f
PM
2734 return false;
2735 }
2736
8fc9d891
PM
2737 if (!vfp_access_check(s)) {
2738 return true;
2739 }
2740
2741 vm = tcg_temp_new_i32();
2742 vd = tcg_temp_new_i64();
2743 neon_load_reg32(vm, a->vm);
a84d1d13 2744 fpst = fpstatus_ptr(FPST_FPCR);
8fc9d891
PM
2745 if (a->s) {
2746 /* i32 -> f64 */
2747 gen_helper_vfp_sitod(vd, vm, fpst);
2748 } else {
2749 /* u32 -> f64 */
2750 gen_helper_vfp_uitod(vd, vm, fpst);
2751 }
2752 neon_store_reg64(vd, a->vd);
2753 tcg_temp_free_i32(vm);
2754 tcg_temp_free_i64(vd);
2755 tcg_temp_free_ptr(fpst);
2756 return true;
2757}
92073e94
PM
2758
2759static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a)
2760{
2761 TCGv_i32 vd;
2762 TCGv_i64 vm;
2763
799449ab 2764 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
92073e94
PM
2765 return false;
2766 }
2767
799449ab 2768 if (!dc_isar_feature(aa32_jscvt, s)) {
92073e94
PM
2769 return false;
2770 }
2771
799449ab
RH
2772 /* UNDEF accesses to D16-D31 if they don't exist. */
2773 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
1120827f
PM
2774 return false;
2775 }
2776
92073e94
PM
2777 if (!vfp_access_check(s)) {
2778 return true;
2779 }
2780
2781 vm = tcg_temp_new_i64();
2782 vd = tcg_temp_new_i32();
2783 neon_load_reg64(vm, a->vm);
2784 gen_helper_vjcvt(vd, vm, cpu_env);
2785 neon_store_reg32(vd, a->vd);
2786 tcg_temp_free_i64(vm);
2787 tcg_temp_free_i32(vd);
2788 return true;
2789}
e3d6f429
PM
2790
2791static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a)
2792{
2793 TCGv_i32 vd, shift;
2794 TCGv_ptr fpst;
2795 int frac_bits;
2796
84774cc3 2797 if (!dc_isar_feature(aa32_fpsp_v3, s)) {
e3d6f429
PM
2798 return false;
2799 }
2800
2801 if (!vfp_access_check(s)) {
2802 return true;
2803 }
2804
2805 frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
2806
2807 vd = tcg_temp_new_i32();
2808 neon_load_reg32(vd, a->vd);
2809
a84d1d13 2810 fpst = fpstatus_ptr(FPST_FPCR);
e3d6f429
PM
2811 shift = tcg_const_i32(frac_bits);
2812
2813 /* Switch on op:U:sx bits */
2814 switch (a->opc) {
2815 case 0:
2816 gen_helper_vfp_shtos(vd, vd, shift, fpst);
2817 break;
2818 case 1:
2819 gen_helper_vfp_sltos(vd, vd, shift, fpst);
2820 break;
2821 case 2:
2822 gen_helper_vfp_uhtos(vd, vd, shift, fpst);
2823 break;
2824 case 3:
2825 gen_helper_vfp_ultos(vd, vd, shift, fpst);
2826 break;
2827 case 4:
2828 gen_helper_vfp_toshs_round_to_zero(vd, vd, shift, fpst);
2829 break;
2830 case 5:
2831 gen_helper_vfp_tosls_round_to_zero(vd, vd, shift, fpst);
2832 break;
2833 case 6:
2834 gen_helper_vfp_touhs_round_to_zero(vd, vd, shift, fpst);
2835 break;
2836 case 7:
2837 gen_helper_vfp_touls_round_to_zero(vd, vd, shift, fpst);
2838 break;
2839 default:
2840 g_assert_not_reached();
2841 }
2842
2843 neon_store_reg32(vd, a->vd);
2844 tcg_temp_free_i32(vd);
2845 tcg_temp_free_i32(shift);
2846 tcg_temp_free_ptr(fpst);
2847 return true;
2848}
2849
2850static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
2851{
2852 TCGv_i64 vd;
2853 TCGv_i32 shift;
2854 TCGv_ptr fpst;
2855 int frac_bits;
2856
84774cc3 2857 if (!dc_isar_feature(aa32_fpdp_v3, s)) {
e3d6f429
PM
2858 return false;
2859 }
2860
799449ab
RH
2861 /* UNDEF accesses to D16-D31 if they don't exist. */
2862 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
1120827f
PM
2863 return false;
2864 }
2865
e3d6f429
PM
2866 if (!vfp_access_check(s)) {
2867 return true;
2868 }
2869
2870 frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
2871
2872 vd = tcg_temp_new_i64();
2873 neon_load_reg64(vd, a->vd);
2874
a84d1d13 2875 fpst = fpstatus_ptr(FPST_FPCR);
e3d6f429
PM
2876 shift = tcg_const_i32(frac_bits);
2877
2878 /* Switch on op:U:sx bits */
2879 switch (a->opc) {
2880 case 0:
2881 gen_helper_vfp_shtod(vd, vd, shift, fpst);
2882 break;
2883 case 1:
2884 gen_helper_vfp_sltod(vd, vd, shift, fpst);
2885 break;
2886 case 2:
2887 gen_helper_vfp_uhtod(vd, vd, shift, fpst);
2888 break;
2889 case 3:
2890 gen_helper_vfp_ultod(vd, vd, shift, fpst);
2891 break;
2892 case 4:
2893 gen_helper_vfp_toshd_round_to_zero(vd, vd, shift, fpst);
2894 break;
2895 case 5:
2896 gen_helper_vfp_tosld_round_to_zero(vd, vd, shift, fpst);
2897 break;
2898 case 6:
2899 gen_helper_vfp_touhd_round_to_zero(vd, vd, shift, fpst);
2900 break;
2901 case 7:
2902 gen_helper_vfp_tould_round_to_zero(vd, vd, shift, fpst);
2903 break;
2904 default:
2905 g_assert_not_reached();
2906 }
2907
2908 neon_store_reg64(vd, a->vd);
2909 tcg_temp_free_i64(vd);
2910 tcg_temp_free_i32(shift);
2911 tcg_temp_free_ptr(fpst);
2912 return true;
2913}
3111bfc2
PM
2914
2915static bool trans_VCVT_sp_int(DisasContext *s, arg_VCVT_sp_int *a)
2916{
2917 TCGv_i32 vm;
2918 TCGv_ptr fpst;
2919
82f6abe1
RH
2920 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2921 return false;
2922 }
2923
3111bfc2
PM
2924 if (!vfp_access_check(s)) {
2925 return true;
2926 }
2927
a84d1d13 2928 fpst = fpstatus_ptr(FPST_FPCR);
3111bfc2
PM
2929 vm = tcg_temp_new_i32();
2930 neon_load_reg32(vm, a->vm);
2931
2932 if (a->s) {
2933 if (a->rz) {
2934 gen_helper_vfp_tosizs(vm, vm, fpst);
2935 } else {
2936 gen_helper_vfp_tosis(vm, vm, fpst);
2937 }
2938 } else {
2939 if (a->rz) {
2940 gen_helper_vfp_touizs(vm, vm, fpst);
2941 } else {
2942 gen_helper_vfp_touis(vm, vm, fpst);
2943 }
2944 }
2945 neon_store_reg32(vm, a->vd);
2946 tcg_temp_free_i32(vm);
2947 tcg_temp_free_ptr(fpst);
2948 return true;
2949}
2950
2951static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
2952{
2953 TCGv_i32 vd;
2954 TCGv_i64 vm;
2955 TCGv_ptr fpst;
2956
799449ab 2957 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3111bfc2
PM
2958 return false;
2959 }
2960
799449ab
RH
2961 /* UNDEF accesses to D16-D31 if they don't exist. */
2962 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
1120827f
PM
2963 return false;
2964 }
2965
3111bfc2
PM
2966 if (!vfp_access_check(s)) {
2967 return true;
2968 }
2969
a84d1d13 2970 fpst = fpstatus_ptr(FPST_FPCR);
3111bfc2
PM
2971 vm = tcg_temp_new_i64();
2972 vd = tcg_temp_new_i32();
2973 neon_load_reg64(vm, a->vm);
2974
2975 if (a->s) {
2976 if (a->rz) {
2977 gen_helper_vfp_tosizd(vd, vm, fpst);
2978 } else {
2979 gen_helper_vfp_tosid(vd, vm, fpst);
2980 }
2981 } else {
2982 if (a->rz) {
2983 gen_helper_vfp_touizd(vd, vm, fpst);
2984 } else {
2985 gen_helper_vfp_touid(vd, vm, fpst);
2986 }
2987 }
2988 neon_store_reg32(vd, a->vd);
2989 tcg_temp_free_i32(vd);
2990 tcg_temp_free_i64(vm);
2991 tcg_temp_free_ptr(fpst);
2992 return true;
2993}
dc778a68
RH
2994
2995/*
2996 * Decode VLLDM and VLSTM are nonstandard because:
2997 * * if there is no FPU then these insns must NOP in
2998 * Secure state and UNDEF in Nonsecure state
2999 * * if there is an FPU then these insns do not have
3000 * the usual behaviour that vfp_access_check() provides of
3001 * being controlled by CPACR/NSACR enable bits or the
3002 * lazy-stacking logic.
3003 */
3004static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
3005{
3006 TCGv_i32 fptr;
3007
3008 if (!arm_dc_feature(s, ARM_FEATURE_M) ||
3009 !arm_dc_feature(s, ARM_FEATURE_V8)) {
3010 return false;
3011 }
a3494d46
PM
3012 /*
3013 * If not secure, UNDEF. We must emit code for this
3014 * rather than returning false so that this takes
3015 * precedence over the m-nocp.decode NOCP fallback.
3016 */
dc778a68 3017 if (!s->v8m_secure) {
a3494d46
PM
3018 unallocated_encoding(s);
3019 return true;
dc778a68
RH
3020 }
3021 /* If no fpu, NOP. */
3022 if (!dc_isar_feature(aa32_vfp, s)) {
3023 return true;
3024 }
3025
3026 fptr = load_reg(s, a->rn);
3027 if (a->l) {
3028 gen_helper_v7m_vlldm(cpu_env, fptr);
3029 } else {
3030 gen_helper_v7m_vlstm(cpu_env, fptr);
3031 }
3032 tcg_temp_free_i32(fptr);
3033
3034 /* End the TB, because we have updated FP control bits */
14407ec2 3035 s->base.is_jmp = DISAS_UPDATE_EXIT;
dc778a68
RH
3036 return true;
3037}
a3494d46
PM
3038
3039static bool trans_NOCP(DisasContext *s, arg_NOCP *a)
3040{
3041 /*
3042 * Handle M-profile early check for disabled coprocessor:
3043 * all we need to do here is emit the NOCP exception if
3044 * the coprocessor is disabled. Otherwise we return false
3045 * and the real VFP/etc decode will handle the insn.
3046 */
3047 assert(arm_dc_feature(s, ARM_FEATURE_M));
3048
3049 if (a->cp == 11) {
3050 a->cp = 10;
3051 }
3052 /* TODO: in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
3053
3054 if (a->cp != 10) {
3055 gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
3056 syn_uncategorized(), default_exception_el(s));
3057 return true;
3058 }
3059
3060 if (s->fp_excp_el != 0) {
3061 gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
3062 syn_uncategorized(), s->fp_excp_el);
3063 return true;
3064 }
3065
3066 return false;
3067}