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