]> git.proxmox.com Git - mirror_qemu.git/blame - target/arm/translate-vfp.c.inc
target/arm: Do M-profile NOCP checks early and via decodetree
[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
362 fpst = get_fpstatus_ptr(0);
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
425 fpst = get_fpstatus_ptr(0);
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();
1234 fpst = get_fpstatus_ptr(0);
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
1269static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn,
1270 int vd, int vn, int vm, bool reads_vd)
1271{
1272 uint32_t delta_m = 0;
1273 uint32_t delta_d = 0;
266bd25c
PM
1274 int veclen = s->vec_len;
1275 TCGv_i64 f0, f1, fd;
1276 TCGv_ptr fpst;
1277
799449ab 1278 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
266bd25c
PM
1279 return false;
1280 }
1281
799449ab
RH
1282 /* UNDEF accesses to D16-D31 if they don't exist */
1283 if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) {
1120827f
PM
1284 return false;
1285 }
1286
266bd25c
PM
1287 if (!dc_isar_feature(aa32_fpshvec, s) &&
1288 (veclen != 0 || s->vec_stride != 0)) {
1289 return false;
1290 }
1291
1292 if (!vfp_access_check(s)) {
1293 return true;
1294 }
1295
1296 if (veclen > 0) {
266bd25c 1297 /* Figure out what type of vector operation this is. */
18cf951a 1298 if (vfp_dreg_is_scalar(vd)) {
266bd25c
PM
1299 /* scalar */
1300 veclen = 0;
1301 } else {
1302 delta_d = (s->vec_stride >> 1) + 1;
1303
18cf951a 1304 if (vfp_dreg_is_scalar(vm)) {
266bd25c
PM
1305 /* mixed scalar/vector */
1306 delta_m = 0;
1307 } else {
1308 /* vector */
1309 delta_m = delta_d;
1310 }
1311 }
1312 }
1313
1314 f0 = tcg_temp_new_i64();
1315 f1 = tcg_temp_new_i64();
1316 fd = tcg_temp_new_i64();
1317 fpst = get_fpstatus_ptr(0);
1318
1319 neon_load_reg64(f0, vn);
1320 neon_load_reg64(f1, vm);
1321
1322 for (;;) {
1323 if (reads_vd) {
1324 neon_load_reg64(fd, vd);
1325 }
1326 fn(fd, f0, f1, fpst);
1327 neon_store_reg64(fd, vd);
1328
1329 if (veclen == 0) {
1330 break;
1331 }
1332 /* Set up the operands for the next iteration */
1333 veclen--;
18cf951a
PM
1334 vd = vfp_advance_dreg(vd, delta_d);
1335 vn = vfp_advance_dreg(vn, delta_d);
266bd25c
PM
1336 neon_load_reg64(f0, vn);
1337 if (delta_m) {
18cf951a 1338 vm = vfp_advance_dreg(vm, delta_m);
266bd25c
PM
1339 neon_load_reg64(f1, vm);
1340 }
1341 }
1342
1343 tcg_temp_free_i64(f0);
1344 tcg_temp_free_i64(f1);
1345 tcg_temp_free_i64(fd);
1346 tcg_temp_free_ptr(fpst);
1347
1348 return true;
1349}
1350
90287e22
PM
1351static bool do_vfp_2op_sp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
1352{
1353 uint32_t delta_m = 0;
1354 uint32_t delta_d = 0;
90287e22
PM
1355 int veclen = s->vec_len;
1356 TCGv_i32 f0, fd;
1357
82f6abe1
RH
1358 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
1359 return false;
1360 }
1361
90287e22
PM
1362 if (!dc_isar_feature(aa32_fpshvec, s) &&
1363 (veclen != 0 || s->vec_stride != 0)) {
1364 return false;
1365 }
1366
1367 if (!vfp_access_check(s)) {
1368 return true;
1369 }
1370
1371 if (veclen > 0) {
90287e22 1372 /* Figure out what type of vector operation this is. */
18cf951a 1373 if (vfp_sreg_is_scalar(vd)) {
90287e22
PM
1374 /* scalar */
1375 veclen = 0;
1376 } else {
1377 delta_d = s->vec_stride + 1;
1378
18cf951a 1379 if (vfp_sreg_is_scalar(vm)) {
90287e22
PM
1380 /* mixed scalar/vector */
1381 delta_m = 0;
1382 } else {
1383 /* vector */
1384 delta_m = delta_d;
1385 }
1386 }
1387 }
1388
1389 f0 = tcg_temp_new_i32();
1390 fd = tcg_temp_new_i32();
1391
1392 neon_load_reg32(f0, vm);
1393
1394 for (;;) {
1395 fn(fd, f0);
1396 neon_store_reg32(fd, vd);
1397
1398 if (veclen == 0) {
1399 break;
1400 }
1401
1402 if (delta_m == 0) {
1403 /* single source one-many */
1404 while (veclen--) {
18cf951a 1405 vd = vfp_advance_sreg(vd, delta_d);
90287e22
PM
1406 neon_store_reg32(fd, vd);
1407 }
1408 break;
1409 }
1410
1411 /* Set up the operands for the next iteration */
1412 veclen--;
18cf951a
PM
1413 vd = vfp_advance_sreg(vd, delta_d);
1414 vm = vfp_advance_sreg(vm, delta_m);
90287e22
PM
1415 neon_load_reg32(f0, vm);
1416 }
1417
1418 tcg_temp_free_i32(f0);
1419 tcg_temp_free_i32(fd);
1420
1421 return true;
1422}
1423
1424static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm)
1425{
1426 uint32_t delta_m = 0;
1427 uint32_t delta_d = 0;
90287e22
PM
1428 int veclen = s->vec_len;
1429 TCGv_i64 f0, fd;
1430
799449ab 1431 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
90287e22
PM
1432 return false;
1433 }
1434
799449ab
RH
1435 /* UNDEF accesses to D16-D31 if they don't exist */
1436 if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) {
1120827f
PM
1437 return false;
1438 }
1439
90287e22
PM
1440 if (!dc_isar_feature(aa32_fpshvec, s) &&
1441 (veclen != 0 || s->vec_stride != 0)) {
1442 return false;
1443 }
1444
1445 if (!vfp_access_check(s)) {
1446 return true;
1447 }
1448
1449 if (veclen > 0) {
90287e22 1450 /* Figure out what type of vector operation this is. */
18cf951a 1451 if (vfp_dreg_is_scalar(vd)) {
90287e22
PM
1452 /* scalar */
1453 veclen = 0;
1454 } else {
1455 delta_d = (s->vec_stride >> 1) + 1;
1456
18cf951a 1457 if (vfp_dreg_is_scalar(vm)) {
90287e22
PM
1458 /* mixed scalar/vector */
1459 delta_m = 0;
1460 } else {
1461 /* vector */
1462 delta_m = delta_d;
1463 }
1464 }
1465 }
1466
1467 f0 = tcg_temp_new_i64();
1468 fd = tcg_temp_new_i64();
1469
1470 neon_load_reg64(f0, vm);
1471
1472 for (;;) {
1473 fn(fd, f0);
1474 neon_store_reg64(fd, vd);
1475
1476 if (veclen == 0) {
1477 break;
1478 }
1479
1480 if (delta_m == 0) {
1481 /* single source one-many */
1482 while (veclen--) {
18cf951a 1483 vd = vfp_advance_dreg(vd, delta_d);
90287e22
PM
1484 neon_store_reg64(fd, vd);
1485 }
1486 break;
1487 }
1488
1489 /* Set up the operands for the next iteration */
1490 veclen--;
18cf951a
PM
1491 vd = vfp_advance_dreg(vd, delta_d);
1492 vd = vfp_advance_dreg(vm, delta_m);
90287e22
PM
1493 neon_load_reg64(f0, vm);
1494 }
1495
1496 tcg_temp_free_i64(f0);
1497 tcg_temp_free_i64(fd);
1498
1499 return true;
1500}
1501
266bd25c
PM
1502static void gen_VMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1503{
1504 /* Note that order of inputs to the add matters for NaNs */
1505 TCGv_i32 tmp = tcg_temp_new_i32();
1506
1507 gen_helper_vfp_muls(tmp, vn, vm, fpst);
1508 gen_helper_vfp_adds(vd, vd, tmp, fpst);
1509 tcg_temp_free_i32(tmp);
1510}
1511
1512static bool trans_VMLA_sp(DisasContext *s, arg_VMLA_sp *a)
1513{
1514 return do_vfp_3op_sp(s, gen_VMLA_sp, a->vd, a->vn, a->vm, true);
1515}
1516
1517static void gen_VMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1518{
1519 /* Note that order of inputs to the add matters for NaNs */
1520 TCGv_i64 tmp = tcg_temp_new_i64();
1521
1522 gen_helper_vfp_muld(tmp, vn, vm, fpst);
1523 gen_helper_vfp_addd(vd, vd, tmp, fpst);
1524 tcg_temp_free_i64(tmp);
1525}
1526
83655223 1527static bool trans_VMLA_dp(DisasContext *s, arg_VMLA_dp *a)
266bd25c
PM
1528{
1529 return do_vfp_3op_dp(s, gen_VMLA_dp, a->vd, a->vn, a->vm, true);
1530}
e7258280
PM
1531
1532static void gen_VMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1533{
1534 /*
1535 * VMLS: vd = vd + -(vn * vm)
1536 * Note that order of inputs to the add matters for NaNs.
1537 */
1538 TCGv_i32 tmp = tcg_temp_new_i32();
1539
1540 gen_helper_vfp_muls(tmp, vn, vm, fpst);
1541 gen_helper_vfp_negs(tmp, tmp);
1542 gen_helper_vfp_adds(vd, vd, tmp, fpst);
1543 tcg_temp_free_i32(tmp);
1544}
1545
1546static bool trans_VMLS_sp(DisasContext *s, arg_VMLS_sp *a)
1547{
1548 return do_vfp_3op_sp(s, gen_VMLS_sp, a->vd, a->vn, a->vm, true);
1549}
1550
1551static void gen_VMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1552{
1553 /*
1554 * VMLS: vd = vd + -(vn * vm)
1555 * Note that order of inputs to the add matters for NaNs.
1556 */
1557 TCGv_i64 tmp = tcg_temp_new_i64();
1558
1559 gen_helper_vfp_muld(tmp, vn, vm, fpst);
1560 gen_helper_vfp_negd(tmp, tmp);
1561 gen_helper_vfp_addd(vd, vd, tmp, fpst);
1562 tcg_temp_free_i64(tmp);
1563}
1564
83655223 1565static bool trans_VMLS_dp(DisasContext *s, arg_VMLS_dp *a)
e7258280
PM
1566{
1567 return do_vfp_3op_dp(s, gen_VMLS_dp, a->vd, a->vn, a->vm, true);
1568}
c54a416c
PM
1569
1570static void gen_VNMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1571{
1572 /*
1573 * VNMLS: -fd + (fn * fm)
1574 * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1575 * plausible looking simplifications because this will give wrong results
1576 * for NaNs.
1577 */
1578 TCGv_i32 tmp = tcg_temp_new_i32();
1579
1580 gen_helper_vfp_muls(tmp, vn, vm, fpst);
1581 gen_helper_vfp_negs(vd, vd);
1582 gen_helper_vfp_adds(vd, vd, tmp, fpst);
1583 tcg_temp_free_i32(tmp);
1584}
1585
1586static bool trans_VNMLS_sp(DisasContext *s, arg_VNMLS_sp *a)
1587{
1588 return do_vfp_3op_sp(s, gen_VNMLS_sp, a->vd, a->vn, a->vm, true);
1589}
1590
1591static void gen_VNMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1592{
1593 /*
1594 * VNMLS: -fd + (fn * fm)
1595 * Note that it isn't valid to replace (-A + B) with (B - A) or similar
1596 * plausible looking simplifications because this will give wrong results
1597 * for NaNs.
1598 */
1599 TCGv_i64 tmp = tcg_temp_new_i64();
1600
1601 gen_helper_vfp_muld(tmp, vn, vm, fpst);
1602 gen_helper_vfp_negd(vd, vd);
1603 gen_helper_vfp_addd(vd, vd, tmp, fpst);
1604 tcg_temp_free_i64(tmp);
1605}
1606
83655223 1607static bool trans_VNMLS_dp(DisasContext *s, arg_VNMLS_dp *a)
c54a416c
PM
1608{
1609 return do_vfp_3op_dp(s, gen_VNMLS_dp, a->vd, a->vn, a->vm, true);
1610}
8a483533
PM
1611
1612static void gen_VNMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1613{
1614 /* VNMLA: -fd + -(fn * fm) */
1615 TCGv_i32 tmp = tcg_temp_new_i32();
1616
1617 gen_helper_vfp_muls(tmp, vn, vm, fpst);
1618 gen_helper_vfp_negs(tmp, tmp);
1619 gen_helper_vfp_negs(vd, vd);
1620 gen_helper_vfp_adds(vd, vd, tmp, fpst);
1621 tcg_temp_free_i32(tmp);
1622}
1623
1624static bool trans_VNMLA_sp(DisasContext *s, arg_VNMLA_sp *a)
1625{
1626 return do_vfp_3op_sp(s, gen_VNMLA_sp, a->vd, a->vn, a->vm, true);
1627}
1628
1629static void gen_VNMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1630{
1631 /* VNMLA: -fd + (fn * fm) */
1632 TCGv_i64 tmp = tcg_temp_new_i64();
1633
1634 gen_helper_vfp_muld(tmp, vn, vm, fpst);
1635 gen_helper_vfp_negd(tmp, tmp);
1636 gen_helper_vfp_negd(vd, vd);
1637 gen_helper_vfp_addd(vd, vd, tmp, fpst);
1638 tcg_temp_free_i64(tmp);
1639}
1640
83655223 1641static bool trans_VNMLA_dp(DisasContext *s, arg_VNMLA_dp *a)
8a483533
PM
1642{
1643 return do_vfp_3op_dp(s, gen_VNMLA_dp, a->vd, a->vn, a->vm, true);
1644}
88c5188c
PM
1645
1646static bool trans_VMUL_sp(DisasContext *s, arg_VMUL_sp *a)
1647{
1648 return do_vfp_3op_sp(s, gen_helper_vfp_muls, a->vd, a->vn, a->vm, false);
1649}
1650
83655223 1651static bool trans_VMUL_dp(DisasContext *s, arg_VMUL_dp *a)
88c5188c
PM
1652{
1653 return do_vfp_3op_dp(s, gen_helper_vfp_muld, a->vd, a->vn, a->vm, false);
1654}
43c4be12
PM
1655
1656static void gen_VNMUL_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
1657{
1658 /* VNMUL: -(fn * fm) */
1659 gen_helper_vfp_muls(vd, vn, vm, fpst);
1660 gen_helper_vfp_negs(vd, vd);
1661}
1662
1663static bool trans_VNMUL_sp(DisasContext *s, arg_VNMUL_sp *a)
1664{
1665 return do_vfp_3op_sp(s, gen_VNMUL_sp, a->vd, a->vn, a->vm, false);
1666}
1667
1668static void gen_VNMUL_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
1669{
1670 /* VNMUL: -(fn * fm) */
1671 gen_helper_vfp_muld(vd, vn, vm, fpst);
1672 gen_helper_vfp_negd(vd, vd);
1673}
1674
83655223 1675static bool trans_VNMUL_dp(DisasContext *s, arg_VNMUL_dp *a)
43c4be12
PM
1676{
1677 return do_vfp_3op_dp(s, gen_VNMUL_dp, a->vd, a->vn, a->vm, false);
1678}
ce28b303
PM
1679
1680static bool trans_VADD_sp(DisasContext *s, arg_VADD_sp *a)
1681{
1682 return do_vfp_3op_sp(s, gen_helper_vfp_adds, a->vd, a->vn, a->vm, false);
1683}
1684
83655223 1685static bool trans_VADD_dp(DisasContext *s, arg_VADD_dp *a)
ce28b303
PM
1686{
1687 return do_vfp_3op_dp(s, gen_helper_vfp_addd, a->vd, a->vn, a->vm, false);
1688}
8fec9a11
PM
1689
1690static bool trans_VSUB_sp(DisasContext *s, arg_VSUB_sp *a)
1691{
1692 return do_vfp_3op_sp(s, gen_helper_vfp_subs, a->vd, a->vn, a->vm, false);
1693}
1694
83655223 1695static bool trans_VSUB_dp(DisasContext *s, arg_VSUB_dp *a)
8fec9a11
PM
1696{
1697 return do_vfp_3op_dp(s, gen_helper_vfp_subd, a->vd, a->vn, a->vm, false);
1698}
519ee7ae
PM
1699
1700static bool trans_VDIV_sp(DisasContext *s, arg_VDIV_sp *a)
1701{
1702 return do_vfp_3op_sp(s, gen_helper_vfp_divs, a->vd, a->vn, a->vm, false);
1703}
1704
83655223 1705static bool trans_VDIV_dp(DisasContext *s, arg_VDIV_dp *a)
519ee7ae
PM
1706{
1707 return do_vfp_3op_dp(s, gen_helper_vfp_divd, a->vd, a->vn, a->vm, false);
1708}
d4893b01 1709
f2eafb75
RH
1710static bool trans_VMINNM_sp(DisasContext *s, arg_VMINNM_sp *a)
1711{
1712 if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1713 return false;
1714 }
1715 return do_vfp_3op_sp(s, gen_helper_vfp_minnums,
1716 a->vd, a->vn, a->vm, false);
1717}
1718
1719static bool trans_VMAXNM_sp(DisasContext *s, arg_VMAXNM_sp *a)
1720{
1721 if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1722 return false;
1723 }
1724 return do_vfp_3op_sp(s, gen_helper_vfp_maxnums,
1725 a->vd, a->vn, a->vm, false);
1726}
1727
1728static bool trans_VMINNM_dp(DisasContext *s, arg_VMINNM_dp *a)
1729{
1730 if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1731 return false;
1732 }
1733 return do_vfp_3op_dp(s, gen_helper_vfp_minnumd,
1734 a->vd, a->vn, a->vm, false);
1735}
1736
1737static bool trans_VMAXNM_dp(DisasContext *s, arg_VMAXNM_dp *a)
1738{
1739 if (!dc_isar_feature(aa32_vminmaxnm, s)) {
1740 return false;
1741 }
1742 return do_vfp_3op_dp(s, gen_helper_vfp_maxnumd,
1743 a->vd, a->vn, a->vm, false);
1744}
1745
d486f830 1746static bool do_vfm_sp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
d4893b01
PM
1747{
1748 /*
1749 * VFNMA : fd = muladd(-fd, fn, fm)
1750 * VFNMS : fd = muladd(-fd, -fn, fm)
1751 * VFMA : fd = muladd( fd, fn, fm)
1752 * VFMS : fd = muladd( fd, -fn, fm)
1753 *
1754 * These are fused multiply-add, and must be done as one floating
1755 * point operation with no rounding between the multiplication and
1756 * addition steps. NB that doing the negations here as separate
1757 * steps is correct : an input NaN should come out with its sign
1758 * bit flipped if it is a negated-input.
1759 */
1760 TCGv_ptr fpst;
1761 TCGv_i32 vn, vm, vd;
1762
1763 /*
1764 * Present in VFPv4 only.
c52881bb
RH
1765 * Note that we can't rely on the SIMDFMAC check alone, because
1766 * in a Neon-no-VFP core that ID register field will be non-zero.
1767 */
1768 if (!dc_isar_feature(aa32_simdfmac, s) ||
1769 !dc_isar_feature(aa32_fpsp_v2, s)) {
1770 return false;
1771 }
1772 /*
d4893b01
PM
1773 * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
1774 * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
1775 */
c52881bb 1776 if (s->vec_len != 0 || s->vec_stride != 0) {
d4893b01
PM
1777 return false;
1778 }
1779
1780 if (!vfp_access_check(s)) {
1781 return true;
1782 }
1783
1784 vn = tcg_temp_new_i32();
1785 vm = tcg_temp_new_i32();
1786 vd = tcg_temp_new_i32();
1787
1788 neon_load_reg32(vn, a->vn);
1789 neon_load_reg32(vm, a->vm);
d486f830 1790 if (neg_n) {
d4893b01
PM
1791 /* VFNMS, VFMS */
1792 gen_helper_vfp_negs(vn, vn);
1793 }
1794 neon_load_reg32(vd, a->vd);
d486f830 1795 if (neg_d) {
d4893b01
PM
1796 /* VFNMA, VFNMS */
1797 gen_helper_vfp_negs(vd, vd);
1798 }
1799 fpst = get_fpstatus_ptr(0);
1800 gen_helper_vfp_muladds(vd, vn, vm, vd, fpst);
1801 neon_store_reg32(vd, a->vd);
1802
1803 tcg_temp_free_ptr(fpst);
1804 tcg_temp_free_i32(vn);
1805 tcg_temp_free_i32(vm);
1806 tcg_temp_free_i32(vd);
1807
1808 return true;
1809}
1810
d486f830
RH
1811static bool trans_VFMA_sp(DisasContext *s, arg_VFMA_sp *a)
1812{
1813 return do_vfm_sp(s, a, false, false);
1814}
1815
1816static bool trans_VFMS_sp(DisasContext *s, arg_VFMS_sp *a)
1817{
1818 return do_vfm_sp(s, a, true, false);
1819}
1820
1821static bool trans_VFNMA_sp(DisasContext *s, arg_VFNMA_sp *a)
1822{
1823 return do_vfm_sp(s, a, false, true);
1824}
1825
1826static bool trans_VFNMS_sp(DisasContext *s, arg_VFNMS_sp *a)
1827{
1828 return do_vfm_sp(s, a, true, true);
1829}
1830
1831static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d)
d4893b01
PM
1832{
1833 /*
1834 * VFNMA : fd = muladd(-fd, fn, fm)
1835 * VFNMS : fd = muladd(-fd, -fn, fm)
1836 * VFMA : fd = muladd( fd, fn, fm)
1837 * VFMS : fd = muladd( fd, -fn, fm)
1838 *
1839 * These are fused multiply-add, and must be done as one floating
1840 * point operation with no rounding between the multiplication and
1841 * addition steps. NB that doing the negations here as separate
1842 * steps is correct : an input NaN should come out with its sign
1843 * bit flipped if it is a negated-input.
1844 */
1845 TCGv_ptr fpst;
1846 TCGv_i64 vn, vm, vd;
1847
1848 /*
1849 * Present in VFPv4 only.
c52881bb
RH
1850 * Note that we can't rely on the SIMDFMAC check alone, because
1851 * in a Neon-no-VFP core that ID register field will be non-zero.
1852 */
1853 if (!dc_isar_feature(aa32_simdfmac, s) ||
1854 !dc_isar_feature(aa32_fpdp_v2, s)) {
1855 return false;
1856 }
1857 /*
d4893b01
PM
1858 * In v7A, UNPREDICTABLE with non-zero vector length/stride; from
1859 * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
1860 */
c52881bb 1861 if (s->vec_len != 0 || s->vec_stride != 0) {
d4893b01
PM
1862 return false;
1863 }
1864
1865 /* UNDEF accesses to D16-D31 if they don't exist. */
0e13ba78
RH
1866 if (!dc_isar_feature(aa32_simd_r32, s) &&
1867 ((a->vd | a->vn | a->vm) & 0x10)) {
d4893b01
PM
1868 return false;
1869 }
1870
1871 if (!vfp_access_check(s)) {
1872 return true;
1873 }
1874
1875 vn = tcg_temp_new_i64();
1876 vm = tcg_temp_new_i64();
1877 vd = tcg_temp_new_i64();
1878
1879 neon_load_reg64(vn, a->vn);
1880 neon_load_reg64(vm, a->vm);
d486f830 1881 if (neg_n) {
d4893b01
PM
1882 /* VFNMS, VFMS */
1883 gen_helper_vfp_negd(vn, vn);
1884 }
1885 neon_load_reg64(vd, a->vd);
d486f830 1886 if (neg_d) {
d4893b01
PM
1887 /* VFNMA, VFNMS */
1888 gen_helper_vfp_negd(vd, vd);
1889 }
1890 fpst = get_fpstatus_ptr(0);
1891 gen_helper_vfp_muladdd(vd, vn, vm, vd, fpst);
1892 neon_store_reg64(vd, a->vd);
1893
1894 tcg_temp_free_ptr(fpst);
1895 tcg_temp_free_i64(vn);
1896 tcg_temp_free_i64(vm);
1897 tcg_temp_free_i64(vd);
1898
1899 return true;
1900}
b518c753 1901
d486f830
RH
1902static bool trans_VFMA_dp(DisasContext *s, arg_VFMA_dp *a)
1903{
1904 return do_vfm_dp(s, a, false, false);
1905}
1906
1907static bool trans_VFMS_dp(DisasContext *s, arg_VFMS_dp *a)
1908{
1909 return do_vfm_dp(s, a, true, false);
1910}
1911
1912static bool trans_VFNMA_dp(DisasContext *s, arg_VFNMA_dp *a)
1913{
1914 return do_vfm_dp(s, a, false, true);
1915}
1916
1917static bool trans_VFNMS_dp(DisasContext *s, arg_VFNMS_dp *a)
1918{
1919 return do_vfm_dp(s, a, true, true);
1920}
1921
b518c753
PM
1922static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
1923{
1924 uint32_t delta_d = 0;
b518c753
PM
1925 int veclen = s->vec_len;
1926 TCGv_i32 fd;
9bee50b4 1927 uint32_t vd;
b518c753
PM
1928
1929 vd = a->vd;
1930
84774cc3 1931 if (!dc_isar_feature(aa32_fpsp_v3, s)) {
b518c753
PM
1932 return false;
1933 }
1934
84774cc3
RH
1935 if (!dc_isar_feature(aa32_fpshvec, s) &&
1936 (veclen != 0 || s->vec_stride != 0)) {
b518c753
PM
1937 return false;
1938 }
1939
1940 if (!vfp_access_check(s)) {
1941 return true;
1942 }
1943
1944 if (veclen > 0) {
b518c753 1945 /* Figure out what type of vector operation this is. */
18cf951a 1946 if (vfp_sreg_is_scalar(vd)) {
b518c753
PM
1947 /* scalar */
1948 veclen = 0;
1949 } else {
1950 delta_d = s->vec_stride + 1;
1951 }
1952 }
1953
9bee50b4 1954 fd = tcg_const_i32(vfp_expand_imm(MO_32, a->imm));
b518c753
PM
1955
1956 for (;;) {
1957 neon_store_reg32(fd, vd);
1958
1959 if (veclen == 0) {
1960 break;
1961 }
1962
1963 /* Set up the operands for the next iteration */
1964 veclen--;
18cf951a 1965 vd = vfp_advance_sreg(vd, delta_d);
b518c753
PM
1966 }
1967
1968 tcg_temp_free_i32(fd);
1969 return true;
1970}
1971
1972static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
1973{
1974 uint32_t delta_d = 0;
b518c753
PM
1975 int veclen = s->vec_len;
1976 TCGv_i64 fd;
9bee50b4 1977 uint32_t vd;
b518c753
PM
1978
1979 vd = a->vd;
1980
84774cc3 1981 if (!dc_isar_feature(aa32_fpdp_v3, s)) {
b518c753
PM
1982 return false;
1983 }
1984
799449ab
RH
1985 /* UNDEF accesses to D16-D31 if they don't exist. */
1986 if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) {
1120827f
PM
1987 return false;
1988 }
1989
b518c753
PM
1990 if (!dc_isar_feature(aa32_fpshvec, s) &&
1991 (veclen != 0 || s->vec_stride != 0)) {
1992 return false;
1993 }
1994
b518c753
PM
1995 if (!vfp_access_check(s)) {
1996 return true;
1997 }
1998
1999 if (veclen > 0) {
b518c753 2000 /* Figure out what type of vector operation this is. */
18cf951a 2001 if (vfp_dreg_is_scalar(vd)) {
b518c753
PM
2002 /* scalar */
2003 veclen = 0;
2004 } else {
2005 delta_d = (s->vec_stride >> 1) + 1;
2006 }
2007 }
2008
9bee50b4 2009 fd = tcg_const_i64(vfp_expand_imm(MO_64, a->imm));
b518c753
PM
2010
2011 for (;;) {
2012 neon_store_reg64(fd, vd);
2013
2014 if (veclen == 0) {
2015 break;
2016 }
2017
2018 /* Set up the operands for the next iteration */
2019 veclen--;
89a11ff7 2020 vd = vfp_advance_dreg(vd, delta_d);
b518c753
PM
2021 }
2022
2023 tcg_temp_free_i64(fd);
2024 return true;
2025}
90287e22 2026
17552b97
PM
2027static bool trans_VMOV_reg_sp(DisasContext *s, arg_VMOV_reg_sp *a)
2028{
2029 return do_vfp_2op_sp(s, tcg_gen_mov_i32, a->vd, a->vm);
2030}
2031
2032static bool trans_VMOV_reg_dp(DisasContext *s, arg_VMOV_reg_dp *a)
2033{
2034 return do_vfp_2op_dp(s, tcg_gen_mov_i64, a->vd, a->vm);
2035}
2036
90287e22
PM
2037static bool trans_VABS_sp(DisasContext *s, arg_VABS_sp *a)
2038{
2039 return do_vfp_2op_sp(s, gen_helper_vfp_abss, a->vd, a->vm);
2040}
2041
2042static bool trans_VABS_dp(DisasContext *s, arg_VABS_dp *a)
2043{
2044 return do_vfp_2op_dp(s, gen_helper_vfp_absd, a->vd, a->vm);
2045}
1882651a
PM
2046
2047static bool trans_VNEG_sp(DisasContext *s, arg_VNEG_sp *a)
2048{
2049 return do_vfp_2op_sp(s, gen_helper_vfp_negs, a->vd, a->vm);
2050}
2051
2052static bool trans_VNEG_dp(DisasContext *s, arg_VNEG_dp *a)
2053{
2054 return do_vfp_2op_dp(s, gen_helper_vfp_negd, a->vd, a->vm);
2055}
b8474540
PM
2056
2057static void gen_VSQRT_sp(TCGv_i32 vd, TCGv_i32 vm)
2058{
2059 gen_helper_vfp_sqrts(vd, vm, cpu_env);
2060}
2061
2062static bool trans_VSQRT_sp(DisasContext *s, arg_VSQRT_sp *a)
2063{
2064 return do_vfp_2op_sp(s, gen_VSQRT_sp, a->vd, a->vm);
2065}
2066
2067static void gen_VSQRT_dp(TCGv_i64 vd, TCGv_i64 vm)
2068{
2069 gen_helper_vfp_sqrtd(vd, vm, cpu_env);
2070}
2071
2072static bool trans_VSQRT_dp(DisasContext *s, arg_VSQRT_dp *a)
2073{
2074 return do_vfp_2op_dp(s, gen_VSQRT_dp, a->vd, a->vm);
2075}
386bba23
PM
2076
2077static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a)
2078{
2079 TCGv_i32 vd, vm;
2080
82f6abe1
RH
2081 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2082 return false;
2083 }
2084
386bba23
PM
2085 /* Vm/M bits must be zero for the Z variant */
2086 if (a->z && a->vm != 0) {
2087 return false;
2088 }
2089
2090 if (!vfp_access_check(s)) {
2091 return true;
2092 }
2093
2094 vd = tcg_temp_new_i32();
2095 vm = tcg_temp_new_i32();
2096
2097 neon_load_reg32(vd, a->vd);
2098 if (a->z) {
2099 tcg_gen_movi_i32(vm, 0);
2100 } else {
2101 neon_load_reg32(vm, a->vm);
2102 }
2103
2104 if (a->e) {
2105 gen_helper_vfp_cmpes(vd, vm, cpu_env);
2106 } else {
2107 gen_helper_vfp_cmps(vd, vm, cpu_env);
2108 }
2109
2110 tcg_temp_free_i32(vd);
2111 tcg_temp_free_i32(vm);
2112
2113 return true;
2114}
2115
2116static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a)
2117{
2118 TCGv_i64 vd, vm;
2119
799449ab
RH
2120 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
2121 return false;
2122 }
2123
386bba23
PM
2124 /* Vm/M bits must be zero for the Z variant */
2125 if (a->z && a->vm != 0) {
2126 return false;
2127 }
2128
2129 /* UNDEF accesses to D16-D31 if they don't exist. */
0e13ba78 2130 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
386bba23
PM
2131 return false;
2132 }
2133
2134 if (!vfp_access_check(s)) {
2135 return true;
2136 }
2137
2138 vd = tcg_temp_new_i64();
2139 vm = tcg_temp_new_i64();
2140
2141 neon_load_reg64(vd, a->vd);
2142 if (a->z) {
2143 tcg_gen_movi_i64(vm, 0);
2144 } else {
2145 neon_load_reg64(vm, a->vm);
2146 }
2147
2148 if (a->e) {
2149 gen_helper_vfp_cmped(vd, vm, cpu_env);
2150 } else {
2151 gen_helper_vfp_cmpd(vd, vm, cpu_env);
2152 }
2153
2154 tcg_temp_free_i64(vd);
2155 tcg_temp_free_i64(vm);
2156
2157 return true;
2158}
b623d803
PM
2159
2160static bool trans_VCVT_f32_f16(DisasContext *s, arg_VCVT_f32_f16 *a)
2161{
2162 TCGv_ptr fpst;
2163 TCGv_i32 ahp_mode;
2164 TCGv_i32 tmp;
2165
2166 if (!dc_isar_feature(aa32_fp16_spconv, s)) {
2167 return false;
2168 }
2169
2170 if (!vfp_access_check(s)) {
2171 return true;
2172 }
2173
2174 fpst = get_fpstatus_ptr(false);
2175 ahp_mode = get_ahp_flag();
2176 tmp = tcg_temp_new_i32();
2177 /* The T bit tells us if we want the low or high 16 bits of Vm */
2178 tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t));
2179 gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp_mode);
2180 neon_store_reg32(tmp, a->vd);
2181 tcg_temp_free_i32(ahp_mode);
2182 tcg_temp_free_ptr(fpst);
2183 tcg_temp_free_i32(tmp);
2184 return true;
2185}
2186
2187static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a)
2188{
2189 TCGv_ptr fpst;
2190 TCGv_i32 ahp_mode;
2191 TCGv_i32 tmp;
2192 TCGv_i64 vd;
2193
799449ab 2194 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
b623d803
PM
2195 return false;
2196 }
2197
799449ab 2198 if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
b623d803
PM
2199 return false;
2200 }
2201
799449ab
RH
2202 /* UNDEF accesses to D16-D31 if they don't exist. */
2203 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
1120827f
PM
2204 return false;
2205 }
2206
b623d803
PM
2207 if (!vfp_access_check(s)) {
2208 return true;
2209 }
2210
2211 fpst = get_fpstatus_ptr(false);
2212 ahp_mode = get_ahp_flag();
2213 tmp = tcg_temp_new_i32();
2214 /* The T bit tells us if we want the low or high 16 bits of Vm */
2215 tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t));
2216 vd = tcg_temp_new_i64();
2217 gen_helper_vfp_fcvt_f16_to_f64(vd, tmp, fpst, ahp_mode);
2218 neon_store_reg64(vd, a->vd);
2219 tcg_temp_free_i32(ahp_mode);
2220 tcg_temp_free_ptr(fpst);
2221 tcg_temp_free_i32(tmp);
2222 tcg_temp_free_i64(vd);
2223 return true;
2224}
cdfd14e8
PM
2225
2226static bool trans_VCVT_f16_f32(DisasContext *s, arg_VCVT_f16_f32 *a)
2227{
2228 TCGv_ptr fpst;
2229 TCGv_i32 ahp_mode;
2230 TCGv_i32 tmp;
2231
2232 if (!dc_isar_feature(aa32_fp16_spconv, s)) {
2233 return false;
2234 }
2235
2236 if (!vfp_access_check(s)) {
2237 return true;
2238 }
2239
2240 fpst = get_fpstatus_ptr(false);
2241 ahp_mode = get_ahp_flag();
2242 tmp = tcg_temp_new_i32();
2243
2244 neon_load_reg32(tmp, a->vm);
2245 gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp_mode);
2246 tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t));
2247 tcg_temp_free_i32(ahp_mode);
2248 tcg_temp_free_ptr(fpst);
2249 tcg_temp_free_i32(tmp);
2250 return true;
2251}
2252
2253static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a)
2254{
2255 TCGv_ptr fpst;
2256 TCGv_i32 ahp_mode;
2257 TCGv_i32 tmp;
2258 TCGv_i64 vm;
2259
799449ab 2260 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
cdfd14e8
PM
2261 return false;
2262 }
2263
799449ab 2264 if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
cdfd14e8
PM
2265 return false;
2266 }
2267
799449ab
RH
2268 /* UNDEF accesses to D16-D31 if they don't exist. */
2269 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
1120827f
PM
2270 return false;
2271 }
2272
cdfd14e8
PM
2273 if (!vfp_access_check(s)) {
2274 return true;
2275 }
2276
2277 fpst = get_fpstatus_ptr(false);
2278 ahp_mode = get_ahp_flag();
2279 tmp = tcg_temp_new_i32();
2280 vm = tcg_temp_new_i64();
2281
2282 neon_load_reg64(vm, a->vm);
2283 gen_helper_vfp_fcvt_f64_to_f16(tmp, vm, fpst, ahp_mode);
2284 tcg_temp_free_i64(vm);
2285 tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t));
2286 tcg_temp_free_i32(ahp_mode);
2287 tcg_temp_free_ptr(fpst);
2288 tcg_temp_free_i32(tmp);
2289 return true;
2290}
e25155f5
PM
2291
2292static bool trans_VRINTR_sp(DisasContext *s, arg_VRINTR_sp *a)
2293{
2294 TCGv_ptr fpst;
2295 TCGv_i32 tmp;
2296
2297 if (!dc_isar_feature(aa32_vrint, s)) {
2298 return false;
2299 }
2300
2301 if (!vfp_access_check(s)) {
2302 return true;
2303 }
2304
2305 tmp = tcg_temp_new_i32();
2306 neon_load_reg32(tmp, a->vm);
2307 fpst = get_fpstatus_ptr(false);
2308 gen_helper_rints(tmp, tmp, fpst);
2309 neon_store_reg32(tmp, a->vd);
2310 tcg_temp_free_ptr(fpst);
2311 tcg_temp_free_i32(tmp);
2312 return true;
2313}
2314
83655223 2315static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a)
e25155f5
PM
2316{
2317 TCGv_ptr fpst;
2318 TCGv_i64 tmp;
2319
799449ab 2320 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
e25155f5
PM
2321 return false;
2322 }
2323
799449ab 2324 if (!dc_isar_feature(aa32_vrint, s)) {
e25155f5
PM
2325 return false;
2326 }
2327
799449ab
RH
2328 /* UNDEF accesses to D16-D31 if they don't exist. */
2329 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
1120827f
PM
2330 return false;
2331 }
2332
e25155f5
PM
2333 if (!vfp_access_check(s)) {
2334 return true;
2335 }
2336
2337 tmp = tcg_temp_new_i64();
2338 neon_load_reg64(tmp, a->vm);
2339 fpst = get_fpstatus_ptr(false);
2340 gen_helper_rintd(tmp, tmp, fpst);
2341 neon_store_reg64(tmp, a->vd);
2342 tcg_temp_free_ptr(fpst);
2343 tcg_temp_free_i64(tmp);
2344 return true;
2345}
2346
2347static bool trans_VRINTZ_sp(DisasContext *s, arg_VRINTZ_sp *a)
2348{
2349 TCGv_ptr fpst;
2350 TCGv_i32 tmp;
2351 TCGv_i32 tcg_rmode;
2352
2353 if (!dc_isar_feature(aa32_vrint, s)) {
2354 return false;
2355 }
2356
2357 if (!vfp_access_check(s)) {
2358 return true;
2359 }
2360
2361 tmp = tcg_temp_new_i32();
2362 neon_load_reg32(tmp, a->vm);
2363 fpst = get_fpstatus_ptr(false);
2364 tcg_rmode = tcg_const_i32(float_round_to_zero);
2365 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2366 gen_helper_rints(tmp, tmp, fpst);
2367 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2368 neon_store_reg32(tmp, a->vd);
2369 tcg_temp_free_ptr(fpst);
2370 tcg_temp_free_i32(tcg_rmode);
2371 tcg_temp_free_i32(tmp);
2372 return true;
2373}
2374
83655223 2375static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a)
e25155f5
PM
2376{
2377 TCGv_ptr fpst;
2378 TCGv_i64 tmp;
2379 TCGv_i32 tcg_rmode;
2380
799449ab 2381 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
e25155f5
PM
2382 return false;
2383 }
2384
799449ab 2385 if (!dc_isar_feature(aa32_vrint, s)) {
e25155f5
PM
2386 return false;
2387 }
2388
799449ab
RH
2389 /* UNDEF accesses to D16-D31 if they don't exist. */
2390 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
1120827f
PM
2391 return false;
2392 }
2393
e25155f5
PM
2394 if (!vfp_access_check(s)) {
2395 return true;
2396 }
2397
2398 tmp = tcg_temp_new_i64();
2399 neon_load_reg64(tmp, a->vm);
2400 fpst = get_fpstatus_ptr(false);
2401 tcg_rmode = tcg_const_i32(float_round_to_zero);
2402 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2403 gen_helper_rintd(tmp, tmp, fpst);
2404 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
2405 neon_store_reg64(tmp, a->vd);
2406 tcg_temp_free_ptr(fpst);
2407 tcg_temp_free_i64(tmp);
2408 tcg_temp_free_i32(tcg_rmode);
2409 return true;
2410}
2411
2412static bool trans_VRINTX_sp(DisasContext *s, arg_VRINTX_sp *a)
2413{
2414 TCGv_ptr fpst;
2415 TCGv_i32 tmp;
2416
2417 if (!dc_isar_feature(aa32_vrint, s)) {
2418 return false;
2419 }
2420
2421 if (!vfp_access_check(s)) {
2422 return true;
2423 }
2424
2425 tmp = tcg_temp_new_i32();
2426 neon_load_reg32(tmp, a->vm);
2427 fpst = get_fpstatus_ptr(false);
2428 gen_helper_rints_exact(tmp, tmp, fpst);
2429 neon_store_reg32(tmp, a->vd);
2430 tcg_temp_free_ptr(fpst);
2431 tcg_temp_free_i32(tmp);
2432 return true;
2433}
2434
2435static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a)
2436{
2437 TCGv_ptr fpst;
2438 TCGv_i64 tmp;
2439
799449ab 2440 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
e25155f5
PM
2441 return false;
2442 }
2443
799449ab 2444 if (!dc_isar_feature(aa32_vrint, s)) {
e25155f5
PM
2445 return false;
2446 }
2447
799449ab
RH
2448 /* UNDEF accesses to D16-D31 if they don't exist. */
2449 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
1120827f
PM
2450 return false;
2451 }
2452
e25155f5
PM
2453 if (!vfp_access_check(s)) {
2454 return true;
2455 }
2456
2457 tmp = tcg_temp_new_i64();
2458 neon_load_reg64(tmp, a->vm);
2459 fpst = get_fpstatus_ptr(false);
2460 gen_helper_rintd_exact(tmp, tmp, fpst);
2461 neon_store_reg64(tmp, a->vd);
2462 tcg_temp_free_ptr(fpst);
2463 tcg_temp_free_i64(tmp);
2464 return true;
2465}
6ed7e49c
PM
2466
2467static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a)
2468{
2469 TCGv_i64 vd;
2470 TCGv_i32 vm;
2471
799449ab 2472 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
6ed7e49c
PM
2473 return false;
2474 }
2475
799449ab
RH
2476 /* UNDEF accesses to D16-D31 if they don't exist. */
2477 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
1120827f
PM
2478 return false;
2479 }
2480
6ed7e49c
PM
2481 if (!vfp_access_check(s)) {
2482 return true;
2483 }
2484
2485 vm = tcg_temp_new_i32();
2486 vd = tcg_temp_new_i64();
2487 neon_load_reg32(vm, a->vm);
2488 gen_helper_vfp_fcvtds(vd, vm, cpu_env);
2489 neon_store_reg64(vd, a->vd);
2490 tcg_temp_free_i32(vm);
2491 tcg_temp_free_i64(vd);
2492 return true;
2493}
2494
2495static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a)
2496{
2497 TCGv_i64 vm;
2498 TCGv_i32 vd;
2499
799449ab 2500 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
6ed7e49c
PM
2501 return false;
2502 }
2503
799449ab
RH
2504 /* UNDEF accesses to D16-D31 if they don't exist. */
2505 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
1120827f
PM
2506 return false;
2507 }
2508
6ed7e49c
PM
2509 if (!vfp_access_check(s)) {
2510 return true;
2511 }
2512
2513 vd = tcg_temp_new_i32();
2514 vm = tcg_temp_new_i64();
2515 neon_load_reg64(vm, a->vm);
2516 gen_helper_vfp_fcvtsd(vd, vm, cpu_env);
2517 neon_store_reg32(vd, a->vd);
2518 tcg_temp_free_i32(vd);
2519 tcg_temp_free_i64(vm);
2520 return true;
2521}
8fc9d891
PM
2522
2523static bool trans_VCVT_int_sp(DisasContext *s, arg_VCVT_int_sp *a)
2524{
2525 TCGv_i32 vm;
2526 TCGv_ptr fpst;
2527
82f6abe1
RH
2528 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2529 return false;
2530 }
2531
8fc9d891
PM
2532 if (!vfp_access_check(s)) {
2533 return true;
2534 }
2535
2536 vm = tcg_temp_new_i32();
2537 neon_load_reg32(vm, a->vm);
2538 fpst = get_fpstatus_ptr(false);
2539 if (a->s) {
2540 /* i32 -> f32 */
2541 gen_helper_vfp_sitos(vm, vm, fpst);
2542 } else {
2543 /* u32 -> f32 */
2544 gen_helper_vfp_uitos(vm, vm, fpst);
2545 }
2546 neon_store_reg32(vm, a->vd);
2547 tcg_temp_free_i32(vm);
2548 tcg_temp_free_ptr(fpst);
2549 return true;
2550}
2551
2552static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a)
2553{
2554 TCGv_i32 vm;
2555 TCGv_i64 vd;
2556 TCGv_ptr fpst;
2557
799449ab 2558 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
8fc9d891
PM
2559 return false;
2560 }
2561
799449ab
RH
2562 /* UNDEF accesses to D16-D31 if they don't exist. */
2563 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
1120827f
PM
2564 return false;
2565 }
2566
8fc9d891
PM
2567 if (!vfp_access_check(s)) {
2568 return true;
2569 }
2570
2571 vm = tcg_temp_new_i32();
2572 vd = tcg_temp_new_i64();
2573 neon_load_reg32(vm, a->vm);
2574 fpst = get_fpstatus_ptr(false);
2575 if (a->s) {
2576 /* i32 -> f64 */
2577 gen_helper_vfp_sitod(vd, vm, fpst);
2578 } else {
2579 /* u32 -> f64 */
2580 gen_helper_vfp_uitod(vd, vm, fpst);
2581 }
2582 neon_store_reg64(vd, a->vd);
2583 tcg_temp_free_i32(vm);
2584 tcg_temp_free_i64(vd);
2585 tcg_temp_free_ptr(fpst);
2586 return true;
2587}
92073e94
PM
2588
2589static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a)
2590{
2591 TCGv_i32 vd;
2592 TCGv_i64 vm;
2593
799449ab 2594 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
92073e94
PM
2595 return false;
2596 }
2597
799449ab 2598 if (!dc_isar_feature(aa32_jscvt, s)) {
92073e94
PM
2599 return false;
2600 }
2601
799449ab
RH
2602 /* UNDEF accesses to D16-D31 if they don't exist. */
2603 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
1120827f
PM
2604 return false;
2605 }
2606
92073e94
PM
2607 if (!vfp_access_check(s)) {
2608 return true;
2609 }
2610
2611 vm = tcg_temp_new_i64();
2612 vd = tcg_temp_new_i32();
2613 neon_load_reg64(vm, a->vm);
2614 gen_helper_vjcvt(vd, vm, cpu_env);
2615 neon_store_reg32(vd, a->vd);
2616 tcg_temp_free_i64(vm);
2617 tcg_temp_free_i32(vd);
2618 return true;
2619}
e3d6f429
PM
2620
2621static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a)
2622{
2623 TCGv_i32 vd, shift;
2624 TCGv_ptr fpst;
2625 int frac_bits;
2626
84774cc3 2627 if (!dc_isar_feature(aa32_fpsp_v3, s)) {
e3d6f429
PM
2628 return false;
2629 }
2630
2631 if (!vfp_access_check(s)) {
2632 return true;
2633 }
2634
2635 frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
2636
2637 vd = tcg_temp_new_i32();
2638 neon_load_reg32(vd, a->vd);
2639
2640 fpst = get_fpstatus_ptr(false);
2641 shift = tcg_const_i32(frac_bits);
2642
2643 /* Switch on op:U:sx bits */
2644 switch (a->opc) {
2645 case 0:
2646 gen_helper_vfp_shtos(vd, vd, shift, fpst);
2647 break;
2648 case 1:
2649 gen_helper_vfp_sltos(vd, vd, shift, fpst);
2650 break;
2651 case 2:
2652 gen_helper_vfp_uhtos(vd, vd, shift, fpst);
2653 break;
2654 case 3:
2655 gen_helper_vfp_ultos(vd, vd, shift, fpst);
2656 break;
2657 case 4:
2658 gen_helper_vfp_toshs_round_to_zero(vd, vd, shift, fpst);
2659 break;
2660 case 5:
2661 gen_helper_vfp_tosls_round_to_zero(vd, vd, shift, fpst);
2662 break;
2663 case 6:
2664 gen_helper_vfp_touhs_round_to_zero(vd, vd, shift, fpst);
2665 break;
2666 case 7:
2667 gen_helper_vfp_touls_round_to_zero(vd, vd, shift, fpst);
2668 break;
2669 default:
2670 g_assert_not_reached();
2671 }
2672
2673 neon_store_reg32(vd, a->vd);
2674 tcg_temp_free_i32(vd);
2675 tcg_temp_free_i32(shift);
2676 tcg_temp_free_ptr(fpst);
2677 return true;
2678}
2679
2680static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
2681{
2682 TCGv_i64 vd;
2683 TCGv_i32 shift;
2684 TCGv_ptr fpst;
2685 int frac_bits;
2686
84774cc3 2687 if (!dc_isar_feature(aa32_fpdp_v3, s)) {
e3d6f429
PM
2688 return false;
2689 }
2690
799449ab
RH
2691 /* UNDEF accesses to D16-D31 if they don't exist. */
2692 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
1120827f
PM
2693 return false;
2694 }
2695
e3d6f429
PM
2696 if (!vfp_access_check(s)) {
2697 return true;
2698 }
2699
2700 frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm);
2701
2702 vd = tcg_temp_new_i64();
2703 neon_load_reg64(vd, a->vd);
2704
2705 fpst = get_fpstatus_ptr(false);
2706 shift = tcg_const_i32(frac_bits);
2707
2708 /* Switch on op:U:sx bits */
2709 switch (a->opc) {
2710 case 0:
2711 gen_helper_vfp_shtod(vd, vd, shift, fpst);
2712 break;
2713 case 1:
2714 gen_helper_vfp_sltod(vd, vd, shift, fpst);
2715 break;
2716 case 2:
2717 gen_helper_vfp_uhtod(vd, vd, shift, fpst);
2718 break;
2719 case 3:
2720 gen_helper_vfp_ultod(vd, vd, shift, fpst);
2721 break;
2722 case 4:
2723 gen_helper_vfp_toshd_round_to_zero(vd, vd, shift, fpst);
2724 break;
2725 case 5:
2726 gen_helper_vfp_tosld_round_to_zero(vd, vd, shift, fpst);
2727 break;
2728 case 6:
2729 gen_helper_vfp_touhd_round_to_zero(vd, vd, shift, fpst);
2730 break;
2731 case 7:
2732 gen_helper_vfp_tould_round_to_zero(vd, vd, shift, fpst);
2733 break;
2734 default:
2735 g_assert_not_reached();
2736 }
2737
2738 neon_store_reg64(vd, a->vd);
2739 tcg_temp_free_i64(vd);
2740 tcg_temp_free_i32(shift);
2741 tcg_temp_free_ptr(fpst);
2742 return true;
2743}
3111bfc2
PM
2744
2745static bool trans_VCVT_sp_int(DisasContext *s, arg_VCVT_sp_int *a)
2746{
2747 TCGv_i32 vm;
2748 TCGv_ptr fpst;
2749
82f6abe1
RH
2750 if (!dc_isar_feature(aa32_fpsp_v2, s)) {
2751 return false;
2752 }
2753
3111bfc2
PM
2754 if (!vfp_access_check(s)) {
2755 return true;
2756 }
2757
2758 fpst = get_fpstatus_ptr(false);
2759 vm = tcg_temp_new_i32();
2760 neon_load_reg32(vm, a->vm);
2761
2762 if (a->s) {
2763 if (a->rz) {
2764 gen_helper_vfp_tosizs(vm, vm, fpst);
2765 } else {
2766 gen_helper_vfp_tosis(vm, vm, fpst);
2767 }
2768 } else {
2769 if (a->rz) {
2770 gen_helper_vfp_touizs(vm, vm, fpst);
2771 } else {
2772 gen_helper_vfp_touis(vm, vm, fpst);
2773 }
2774 }
2775 neon_store_reg32(vm, a->vd);
2776 tcg_temp_free_i32(vm);
2777 tcg_temp_free_ptr(fpst);
2778 return true;
2779}
2780
2781static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
2782{
2783 TCGv_i32 vd;
2784 TCGv_i64 vm;
2785 TCGv_ptr fpst;
2786
799449ab 2787 if (!dc_isar_feature(aa32_fpdp_v2, s)) {
3111bfc2
PM
2788 return false;
2789 }
2790
799449ab
RH
2791 /* UNDEF accesses to D16-D31 if they don't exist. */
2792 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
1120827f
PM
2793 return false;
2794 }
2795
3111bfc2
PM
2796 if (!vfp_access_check(s)) {
2797 return true;
2798 }
2799
2800 fpst = get_fpstatus_ptr(false);
2801 vm = tcg_temp_new_i64();
2802 vd = tcg_temp_new_i32();
2803 neon_load_reg64(vm, a->vm);
2804
2805 if (a->s) {
2806 if (a->rz) {
2807 gen_helper_vfp_tosizd(vd, vm, fpst);
2808 } else {
2809 gen_helper_vfp_tosid(vd, vm, fpst);
2810 }
2811 } else {
2812 if (a->rz) {
2813 gen_helper_vfp_touizd(vd, vm, fpst);
2814 } else {
2815 gen_helper_vfp_touid(vd, vm, fpst);
2816 }
2817 }
2818 neon_store_reg32(vd, a->vd);
2819 tcg_temp_free_i32(vd);
2820 tcg_temp_free_i64(vm);
2821 tcg_temp_free_ptr(fpst);
2822 return true;
2823}
dc778a68
RH
2824
2825/*
2826 * Decode VLLDM and VLSTM are nonstandard because:
2827 * * if there is no FPU then these insns must NOP in
2828 * Secure state and UNDEF in Nonsecure state
2829 * * if there is an FPU then these insns do not have
2830 * the usual behaviour that vfp_access_check() provides of
2831 * being controlled by CPACR/NSACR enable bits or the
2832 * lazy-stacking logic.
2833 */
2834static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
2835{
2836 TCGv_i32 fptr;
2837
2838 if (!arm_dc_feature(s, ARM_FEATURE_M) ||
2839 !arm_dc_feature(s, ARM_FEATURE_V8)) {
2840 return false;
2841 }
a3494d46
PM
2842 /*
2843 * If not secure, UNDEF. We must emit code for this
2844 * rather than returning false so that this takes
2845 * precedence over the m-nocp.decode NOCP fallback.
2846 */
dc778a68 2847 if (!s->v8m_secure) {
a3494d46
PM
2848 unallocated_encoding(s);
2849 return true;
dc778a68
RH
2850 }
2851 /* If no fpu, NOP. */
2852 if (!dc_isar_feature(aa32_vfp, s)) {
2853 return true;
2854 }
2855
2856 fptr = load_reg(s, a->rn);
2857 if (a->l) {
2858 gen_helper_v7m_vlldm(cpu_env, fptr);
2859 } else {
2860 gen_helper_v7m_vlstm(cpu_env, fptr);
2861 }
2862 tcg_temp_free_i32(fptr);
2863
2864 /* End the TB, because we have updated FP control bits */
14407ec2 2865 s->base.is_jmp = DISAS_UPDATE_EXIT;
dc778a68
RH
2866 return true;
2867}
a3494d46
PM
2868
2869static bool trans_NOCP(DisasContext *s, arg_NOCP *a)
2870{
2871 /*
2872 * Handle M-profile early check for disabled coprocessor:
2873 * all we need to do here is emit the NOCP exception if
2874 * the coprocessor is disabled. Otherwise we return false
2875 * and the real VFP/etc decode will handle the insn.
2876 */
2877 assert(arm_dc_feature(s, ARM_FEATURE_M));
2878
2879 if (a->cp == 11) {
2880 a->cp = 10;
2881 }
2882 /* TODO: in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
2883
2884 if (a->cp != 10) {
2885 gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
2886 syn_uncategorized(), default_exception_el(s));
2887 return true;
2888 }
2889
2890 if (s->fp_excp_el != 0) {
2891 gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
2892 syn_uncategorized(), s->fp_excp_el);
2893 return true;
2894 }
2895
2896 return false;
2897}