2 * ARM translation: M-profile MVE instructions
4 * Copyright (c) 2021 Linaro, Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "tcg/tcg-op.h"
22 #include "tcg/tcg-op-gvec.h"
23 #include "exec/exec-all.h"
24 #include "exec/gen-icount.h"
25 #include "translate.h"
26 #include "translate-a32.h"
28 /* Include the generated decoder */
29 #include "decode-mve.c.inc"
31 typedef void MVEGenLdStFn(TCGv_ptr
, TCGv_ptr
, TCGv_i32
);
32 typedef void MVEGenOneOpFn(TCGv_ptr
, TCGv_ptr
, TCGv_ptr
);
33 typedef void MVEGenTwoOpFn(TCGv_ptr
, TCGv_ptr
, TCGv_ptr
, TCGv_ptr
);
34 typedef void MVEGenTwoOpScalarFn(TCGv_ptr
, TCGv_ptr
, TCGv_ptr
, TCGv_i32
);
35 typedef void MVEGenDualAccOpFn(TCGv_i64
, TCGv_ptr
, TCGv_ptr
, TCGv_ptr
, TCGv_i64
);
36 typedef void MVEGenVADDVFn(TCGv_i32
, TCGv_ptr
, TCGv_ptr
, TCGv_i32
);
38 /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */
39 static inline long mve_qreg_offset(unsigned reg
)
41 return offsetof(CPUARMState
, vfp
.zregs
[reg
].d
[0]);
44 static TCGv_ptr
mve_qreg_ptr(unsigned reg
)
46 TCGv_ptr ret
= tcg_temp_new_ptr();
47 tcg_gen_addi_ptr(ret
, cpu_env
, mve_qreg_offset(reg
));
51 static bool mve_check_qreg_bank(DisasContext
*s
, int qmask
)
54 * Check whether Qregs are in range. For v8.1M only Q0..Q7
55 * are supported, see VFPSmallRegisterBank().
60 bool mve_eci_check(DisasContext
*s
)
63 * This is a beatwise insn: check that ECI is valid (not a
64 * reserved value) and note that we are handling it.
65 * Return true if OK, false if we generated an exception.
67 s
->eci_handled
= true;
76 /* Reserved value: INVSTATE UsageFault */
77 gen_exception_insn(s
, s
->pc_curr
, EXCP_INVSTATE
, syn_uncategorized(),
78 default_exception_el(s
));
83 static void mve_update_eci(DisasContext
*s
)
86 * The helper function will always update the CPUState field,
87 * so we only need to update the DisasContext field.
90 s
->eci
= (s
->eci
== ECI_A0A1A2B0
) ? ECI_A0
: ECI_NONE
;
94 void mve_update_and_store_eci(DisasContext
*s
)
97 * For insns which don't call a helper function that will call
98 * mve_advance_vpt(), this version updates s->eci and also stores
99 * it out to the CPUState field.
103 store_cpu_field(tcg_constant_i32(s
->eci
<< 4), condexec_bits
);
107 static bool mve_skip_first_beat(DisasContext
*s
)
109 /* Return true if PSR.ECI says we must skip the first beat of this insn */
119 g_assert_not_reached();
123 static bool do_ldst(DisasContext
*s
, arg_VLDR_VSTR
*a
, MVEGenLdStFn
*fn
)
129 if (!dc_isar_feature(aa32_mve
, s
) ||
130 !mve_check_qreg_bank(s
, a
->qd
) ||
135 /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
136 if (a
->rn
== 15 || (a
->rn
== 13 && a
->w
)) {
140 if (!mve_eci_check(s
) || !vfp_access_check(s
)) {
144 offset
= a
->imm
<< a
->size
;
148 addr
= load_reg(s
, a
->rn
);
150 tcg_gen_addi_i32(addr
, addr
, offset
);
153 qreg
= mve_qreg_ptr(a
->qd
);
154 fn(cpu_env
, qreg
, addr
);
155 tcg_temp_free_ptr(qreg
);
158 * Writeback always happens after the last beat of the insn,
159 * regardless of predication
163 tcg_gen_addi_i32(addr
, addr
, offset
);
165 store_reg(s
, a
->rn
, addr
);
167 tcg_temp_free_i32(addr
);
173 static bool trans_VLDR_VSTR(DisasContext
*s
, arg_VLDR_VSTR
*a
)
175 static MVEGenLdStFn
* const ldstfns
[4][2] = {
176 { gen_helper_mve_vstrb
, gen_helper_mve_vldrb
},
177 { gen_helper_mve_vstrh
, gen_helper_mve_vldrh
},
178 { gen_helper_mve_vstrw
, gen_helper_mve_vldrw
},
181 return do_ldst(s
, a
, ldstfns
[a
->size
][a
->l
]);
184 #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST) \
185 static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a) \
187 static MVEGenLdStFn * const ldstfns[2][2] = { \
188 { gen_helper_mve_##ST, gen_helper_mve_##SLD }, \
189 { NULL, gen_helper_mve_##ULD }, \
191 return do_ldst(s, a, ldstfns[a->u][a->l]); \
194 DO_VLDST_WIDE_NARROW(VLDSTB_H
, vldrb_sh
, vldrb_uh
, vstrb_h
)
195 DO_VLDST_WIDE_NARROW(VLDSTB_W
, vldrb_sw
, vldrb_uw
, vstrb_w
)
196 DO_VLDST_WIDE_NARROW(VLDSTH_W
, vldrh_sw
, vldrh_uw
, vstrh_w
)
198 static bool trans_VDUP(DisasContext
*s
, arg_VDUP
*a
)
203 if (!dc_isar_feature(aa32_mve
, s
) ||
204 !mve_check_qreg_bank(s
, a
->qd
)) {
207 if (a
->rt
== 13 || a
->rt
== 15) {
208 /* UNPREDICTABLE; we choose to UNDEF */
211 if (!mve_eci_check(s
) || !vfp_access_check(s
)) {
215 qd
= mve_qreg_ptr(a
->qd
);
216 rt
= load_reg(s
, a
->rt
);
217 tcg_gen_dup_i32(a
->size
, rt
, rt
);
218 gen_helper_mve_vdup(cpu_env
, qd
, rt
);
219 tcg_temp_free_ptr(qd
);
220 tcg_temp_free_i32(rt
);
225 static bool do_1op(DisasContext
*s
, arg_1op
*a
, MVEGenOneOpFn fn
)
229 if (!dc_isar_feature(aa32_mve
, s
) ||
230 !mve_check_qreg_bank(s
, a
->qd
| a
->qm
) ||
235 if (!mve_eci_check(s
) || !vfp_access_check(s
)) {
239 qd
= mve_qreg_ptr(a
->qd
);
240 qm
= mve_qreg_ptr(a
->qm
);
242 tcg_temp_free_ptr(qd
);
243 tcg_temp_free_ptr(qm
);
248 #define DO_1OP(INSN, FN) \
249 static bool trans_##INSN(DisasContext *s, arg_1op *a) \
251 static MVEGenOneOpFn * const fns[] = { \
252 gen_helper_mve_##FN##b, \
253 gen_helper_mve_##FN##h, \
254 gen_helper_mve_##FN##w, \
257 return do_1op(s, a, fns[a->size]); \
265 static bool trans_VREV16(DisasContext
*s
, arg_1op
*a
)
267 static MVEGenOneOpFn
* const fns
[] = {
268 gen_helper_mve_vrev16b
,
273 return do_1op(s
, a
, fns
[a
->size
]);
276 static bool trans_VREV32(DisasContext
*s
, arg_1op
*a
)
278 static MVEGenOneOpFn
* const fns
[] = {
279 gen_helper_mve_vrev32b
,
280 gen_helper_mve_vrev32h
,
284 return do_1op(s
, a
, fns
[a
->size
]);
287 static bool trans_VREV64(DisasContext
*s
, arg_1op
*a
)
289 static MVEGenOneOpFn
* const fns
[] = {
290 gen_helper_mve_vrev64b
,
291 gen_helper_mve_vrev64h
,
292 gen_helper_mve_vrev64w
,
295 return do_1op(s
, a
, fns
[a
->size
]);
298 static bool trans_VMVN(DisasContext
*s
, arg_1op
*a
)
300 return do_1op(s
, a
, gen_helper_mve_vmvn
);
303 static bool trans_VABS_fp(DisasContext
*s
, arg_1op
*a
)
305 static MVEGenOneOpFn
* const fns
[] = {
307 gen_helper_mve_vfabsh
,
308 gen_helper_mve_vfabss
,
311 if (!dc_isar_feature(aa32_mve_fp
, s
)) {
314 return do_1op(s
, a
, fns
[a
->size
]);
317 static bool trans_VNEG_fp(DisasContext
*s
, arg_1op
*a
)
319 static MVEGenOneOpFn
* const fns
[] = {
321 gen_helper_mve_vfnegh
,
322 gen_helper_mve_vfnegs
,
325 if (!dc_isar_feature(aa32_mve_fp
, s
)) {
328 return do_1op(s
, a
, fns
[a
->size
]);
331 static bool do_2op(DisasContext
*s
, arg_2op
*a
, MVEGenTwoOpFn fn
)
335 if (!dc_isar_feature(aa32_mve
, s
) ||
336 !mve_check_qreg_bank(s
, a
->qd
| a
->qn
| a
->qm
) ||
340 if (!mve_eci_check(s
) || !vfp_access_check(s
)) {
344 qd
= mve_qreg_ptr(a
->qd
);
345 qn
= mve_qreg_ptr(a
->qn
);
346 qm
= mve_qreg_ptr(a
->qm
);
347 fn(cpu_env
, qd
, qn
, qm
);
348 tcg_temp_free_ptr(qd
);
349 tcg_temp_free_ptr(qn
);
350 tcg_temp_free_ptr(qm
);
355 #define DO_LOGIC(INSN, HELPER) \
356 static bool trans_##INSN(DisasContext *s, arg_2op *a) \
358 return do_2op(s, a, HELPER); \
361 DO_LOGIC(VAND
, gen_helper_mve_vand
)
362 DO_LOGIC(VBIC
, gen_helper_mve_vbic
)
363 DO_LOGIC(VORR
, gen_helper_mve_vorr
)
364 DO_LOGIC(VORN
, gen_helper_mve_vorn
)
365 DO_LOGIC(VEOR
, gen_helper_mve_veor
)
367 #define DO_2OP(INSN, FN) \
368 static bool trans_##INSN(DisasContext *s, arg_2op *a) \
370 static MVEGenTwoOpFn * const fns[] = { \
371 gen_helper_mve_##FN##b, \
372 gen_helper_mve_##FN##h, \
373 gen_helper_mve_##FN##w, \
376 return do_2op(s, a, fns[a->size]); \
382 DO_2OP(VMULH_S
, vmulhs
)
383 DO_2OP(VMULH_U
, vmulhu
)
384 DO_2OP(VRMULH_S
, vrmulhs
)
385 DO_2OP(VRMULH_U
, vrmulhu
)
386 DO_2OP(VMAX_S
, vmaxs
)
387 DO_2OP(VMAX_U
, vmaxu
)
388 DO_2OP(VMIN_S
, vmins
)
389 DO_2OP(VMIN_U
, vminu
)
390 DO_2OP(VABD_S
, vabds
)
391 DO_2OP(VABD_U
, vabdu
)
392 DO_2OP(VHADD_S
, vhadds
)
393 DO_2OP(VHADD_U
, vhaddu
)
394 DO_2OP(VHSUB_S
, vhsubs
)
395 DO_2OP(VHSUB_U
, vhsubu
)
396 DO_2OP(VMULL_BS
, vmullbs
)
397 DO_2OP(VMULL_BU
, vmullbu
)
398 DO_2OP(VMULL_TS
, vmullts
)
399 DO_2OP(VMULL_TU
, vmulltu
)
400 DO_2OP(VQDMULH
, vqdmulh
)
401 DO_2OP(VQRDMULH
, vqrdmulh
)
402 DO_2OP(VQADD_S
, vqadds
)
403 DO_2OP(VQADD_U
, vqaddu
)
404 DO_2OP(VQSUB_S
, vqsubs
)
405 DO_2OP(VQSUB_U
, vqsubu
)
406 DO_2OP(VSHL_S
, vshls
)
407 DO_2OP(VSHL_U
, vshlu
)
408 DO_2OP(VRSHL_S
, vrshls
)
409 DO_2OP(VRSHL_U
, vrshlu
)
410 DO_2OP(VQSHL_S
, vqshls
)
411 DO_2OP(VQSHL_U
, vqshlu
)
412 DO_2OP(VQRSHL_S
, vqrshls
)
413 DO_2OP(VQRSHL_U
, vqrshlu
)
414 DO_2OP(VQDMLADH
, vqdmladh
)
415 DO_2OP(VQDMLADHX
, vqdmladhx
)
416 DO_2OP(VQRDMLADH
, vqrdmladh
)
417 DO_2OP(VQRDMLADHX
, vqrdmladhx
)
418 DO_2OP(VQDMLSDH
, vqdmlsdh
)
419 DO_2OP(VQDMLSDHX
, vqdmlsdhx
)
420 DO_2OP(VQRDMLSDH
, vqrdmlsdh
)
421 DO_2OP(VQRDMLSDHX
, vqrdmlsdhx
)
422 DO_2OP(VRHADD_S
, vrhadds
)
423 DO_2OP(VRHADD_U
, vrhaddu
)
425 * VCADD Qd == Qm at size MO_32 is UNPREDICTABLE; we choose not to diagnose
426 * so we can reuse the DO_2OP macro. (Our implementation calculates the
427 * "expected" results in this case.) Similarly for VHCADD.
429 DO_2OP(VCADD90
, vcadd90
)
430 DO_2OP(VCADD270
, vcadd270
)
431 DO_2OP(VHCADD90
, vhcadd90
)
432 DO_2OP(VHCADD270
, vhcadd270
)
434 static bool trans_VQDMULLB(DisasContext
*s
, arg_2op
*a
)
436 static MVEGenTwoOpFn
* const fns
[] = {
438 gen_helper_mve_vqdmullbh
,
439 gen_helper_mve_vqdmullbw
,
442 if (a
->size
== MO_32
&& (a
->qd
== a
->qm
|| a
->qd
== a
->qn
)) {
443 /* UNPREDICTABLE; we choose to undef */
446 return do_2op(s
, a
, fns
[a
->size
]);
449 static bool trans_VQDMULLT(DisasContext
*s
, arg_2op
*a
)
451 static MVEGenTwoOpFn
* const fns
[] = {
453 gen_helper_mve_vqdmullth
,
454 gen_helper_mve_vqdmulltw
,
457 if (a
->size
== MO_32
&& (a
->qd
== a
->qm
|| a
->qd
== a
->qn
)) {
458 /* UNPREDICTABLE; we choose to undef */
461 return do_2op(s
, a
, fns
[a
->size
]);
465 * VADC and VSBC: these perform an add-with-carry or subtract-with-carry
466 * of the 32-bit elements in each lane of the input vectors, where the
467 * carry-out of each add is the carry-in of the next. The initial carry
468 * input is either fixed (0 for VADCI, 1 for VSBCI) or is from FPSCR.C
469 * (for VADC and VSBC); the carry out at the end is written back to FPSCR.C.
470 * These insns are subject to beat-wise execution. Partial execution
471 * of an I=1 (initial carry input fixed) insn which does not
472 * execute the first beat must start with the current FPSCR.NZCV
473 * value, not the fixed constant input.
475 static bool trans_VADC(DisasContext
*s
, arg_2op
*a
)
477 return do_2op(s
, a
, gen_helper_mve_vadc
);
480 static bool trans_VADCI(DisasContext
*s
, arg_2op
*a
)
482 if (mve_skip_first_beat(s
)) {
483 return trans_VADC(s
, a
);
485 return do_2op(s
, a
, gen_helper_mve_vadci
);
488 static bool trans_VSBC(DisasContext
*s
, arg_2op
*a
)
490 return do_2op(s
, a
, gen_helper_mve_vsbc
);
493 static bool trans_VSBCI(DisasContext
*s
, arg_2op
*a
)
495 if (mve_skip_first_beat(s
)) {
496 return trans_VSBC(s
, a
);
498 return do_2op(s
, a
, gen_helper_mve_vsbci
);
501 static bool do_2op_scalar(DisasContext
*s
, arg_2scalar
*a
,
502 MVEGenTwoOpScalarFn fn
)
507 if (!dc_isar_feature(aa32_mve
, s
) ||
508 !mve_check_qreg_bank(s
, a
->qd
| a
->qn
) ||
512 if (a
->rm
== 13 || a
->rm
== 15) {
516 if (!mve_eci_check(s
) || !vfp_access_check(s
)) {
520 qd
= mve_qreg_ptr(a
->qd
);
521 qn
= mve_qreg_ptr(a
->qn
);
522 rm
= load_reg(s
, a
->rm
);
523 fn(cpu_env
, qd
, qn
, rm
);
524 tcg_temp_free_i32(rm
);
525 tcg_temp_free_ptr(qd
);
526 tcg_temp_free_ptr(qn
);
531 #define DO_2OP_SCALAR(INSN, FN) \
532 static bool trans_##INSN(DisasContext *s, arg_2scalar *a) \
534 static MVEGenTwoOpScalarFn * const fns[] = { \
535 gen_helper_mve_##FN##b, \
536 gen_helper_mve_##FN##h, \
537 gen_helper_mve_##FN##w, \
540 return do_2op_scalar(s, a, fns[a->size]); \
543 DO_2OP_SCALAR(VADD_scalar
, vadd_scalar
)
544 DO_2OP_SCALAR(VSUB_scalar
, vsub_scalar
)
545 DO_2OP_SCALAR(VMUL_scalar
, vmul_scalar
)
546 DO_2OP_SCALAR(VHADD_S_scalar
, vhadds_scalar
)
547 DO_2OP_SCALAR(VHADD_U_scalar
, vhaddu_scalar
)
548 DO_2OP_SCALAR(VHSUB_S_scalar
, vhsubs_scalar
)
549 DO_2OP_SCALAR(VHSUB_U_scalar
, vhsubu_scalar
)
550 DO_2OP_SCALAR(VQADD_S_scalar
, vqadds_scalar
)
551 DO_2OP_SCALAR(VQADD_U_scalar
, vqaddu_scalar
)
552 DO_2OP_SCALAR(VQSUB_S_scalar
, vqsubs_scalar
)
553 DO_2OP_SCALAR(VQSUB_U_scalar
, vqsubu_scalar
)
554 DO_2OP_SCALAR(VQDMULH_scalar
, vqdmulh_scalar
)
555 DO_2OP_SCALAR(VQRDMULH_scalar
, vqrdmulh_scalar
)
556 DO_2OP_SCALAR(VBRSR
, vbrsr
)
558 static bool trans_VQDMULLB_scalar(DisasContext
*s
, arg_2scalar
*a
)
560 static MVEGenTwoOpScalarFn
* const fns
[] = {
562 gen_helper_mve_vqdmullb_scalarh
,
563 gen_helper_mve_vqdmullb_scalarw
,
566 if (a
->qd
== a
->qn
&& a
->size
== MO_32
) {
567 /* UNPREDICTABLE; we choose to undef */
570 return do_2op_scalar(s
, a
, fns
[a
->size
]);
573 static bool trans_VQDMULLT_scalar(DisasContext
*s
, arg_2scalar
*a
)
575 static MVEGenTwoOpScalarFn
* const fns
[] = {
577 gen_helper_mve_vqdmullt_scalarh
,
578 gen_helper_mve_vqdmullt_scalarw
,
581 if (a
->qd
== a
->qn
&& a
->size
== MO_32
) {
582 /* UNPREDICTABLE; we choose to undef */
585 return do_2op_scalar(s
, a
, fns
[a
->size
]);
588 static bool do_long_dual_acc(DisasContext
*s
, arg_vmlaldav
*a
,
589 MVEGenDualAccOpFn
*fn
)
593 TCGv_i32 rdalo
, rdahi
;
595 if (!dc_isar_feature(aa32_mve
, s
) ||
596 !mve_check_qreg_bank(s
, a
->qn
| a
->qm
) ||
601 * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
602 * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
604 if (a
->rdahi
== 13 || a
->rdahi
== 15) {
607 if (!mve_eci_check(s
) || !vfp_access_check(s
)) {
611 qn
= mve_qreg_ptr(a
->qn
);
612 qm
= mve_qreg_ptr(a
->qm
);
615 * This insn is subject to beat-wise execution. Partial execution
616 * of an A=0 (no-accumulate) insn which does not execute the first
617 * beat must start with the current rda value, not 0.
619 if (a
->a
|| mve_skip_first_beat(s
)) {
620 rda
= tcg_temp_new_i64();
621 rdalo
= load_reg(s
, a
->rdalo
);
622 rdahi
= load_reg(s
, a
->rdahi
);
623 tcg_gen_concat_i32_i64(rda
, rdalo
, rdahi
);
624 tcg_temp_free_i32(rdalo
);
625 tcg_temp_free_i32(rdahi
);
627 rda
= tcg_const_i64(0);
630 fn(rda
, cpu_env
, qn
, qm
, rda
);
631 tcg_temp_free_ptr(qn
);
632 tcg_temp_free_ptr(qm
);
634 rdalo
= tcg_temp_new_i32();
635 rdahi
= tcg_temp_new_i32();
636 tcg_gen_extrl_i64_i32(rdalo
, rda
);
637 tcg_gen_extrh_i64_i32(rdahi
, rda
);
638 store_reg(s
, a
->rdalo
, rdalo
);
639 store_reg(s
, a
->rdahi
, rdahi
);
640 tcg_temp_free_i64(rda
);
645 static bool trans_VMLALDAV_S(DisasContext
*s
, arg_vmlaldav
*a
)
647 static MVEGenDualAccOpFn
* const fns
[4][2] = {
649 { gen_helper_mve_vmlaldavsh
, gen_helper_mve_vmlaldavxsh
},
650 { gen_helper_mve_vmlaldavsw
, gen_helper_mve_vmlaldavxsw
},
653 return do_long_dual_acc(s
, a
, fns
[a
->size
][a
->x
]);
656 static bool trans_VMLALDAV_U(DisasContext
*s
, arg_vmlaldav
*a
)
658 static MVEGenDualAccOpFn
* const fns
[4][2] = {
660 { gen_helper_mve_vmlaldavuh
, NULL
},
661 { gen_helper_mve_vmlaldavuw
, NULL
},
664 return do_long_dual_acc(s
, a
, fns
[a
->size
][a
->x
]);
667 static bool trans_VMLSLDAV(DisasContext
*s
, arg_vmlaldav
*a
)
669 static MVEGenDualAccOpFn
* const fns
[4][2] = {
671 { gen_helper_mve_vmlsldavsh
, gen_helper_mve_vmlsldavxsh
},
672 { gen_helper_mve_vmlsldavsw
, gen_helper_mve_vmlsldavxsw
},
675 return do_long_dual_acc(s
, a
, fns
[a
->size
][a
->x
]);
678 static bool trans_VRMLALDAVH_S(DisasContext
*s
, arg_vmlaldav
*a
)
680 static MVEGenDualAccOpFn
* const fns
[] = {
681 gen_helper_mve_vrmlaldavhsw
, gen_helper_mve_vrmlaldavhxsw
,
683 return do_long_dual_acc(s
, a
, fns
[a
->x
]);
686 static bool trans_VRMLALDAVH_U(DisasContext
*s
, arg_vmlaldav
*a
)
688 static MVEGenDualAccOpFn
* const fns
[] = {
689 gen_helper_mve_vrmlaldavhuw
, NULL
,
691 return do_long_dual_acc(s
, a
, fns
[a
->x
]);
694 static bool trans_VRMLSLDAVH(DisasContext
*s
, arg_vmlaldav
*a
)
696 static MVEGenDualAccOpFn
* const fns
[] = {
697 gen_helper_mve_vrmlsldavhsw
, gen_helper_mve_vrmlsldavhxsw
,
699 return do_long_dual_acc(s
, a
, fns
[a
->x
]);
702 static bool trans_VPST(DisasContext
*s
, arg_VPST
*a
)
706 /* mask == 0 is a "related encoding" */
707 if (!dc_isar_feature(aa32_mve
, s
) || !a
->mask
) {
710 if (!mve_eci_check(s
) || !vfp_access_check(s
)) {
714 * Set the VPR mask fields. We take advantage of MASK01 and MASK23
715 * being adjacent fields in the register.
717 * This insn is not predicated, but it is subject to beat-wise
718 * execution, and the mask is updated on the odd-numbered beats.
719 * So if PSR.ECI says we should skip beat 1, we mustn't update the
722 vpr
= load_cpu_field(v7m
.vpr
);
726 /* Update both 01 and 23 fields */
727 tcg_gen_deposit_i32(vpr
, vpr
,
728 tcg_constant_i32(a
->mask
| (a
->mask
<< 4)),
729 R_V7M_VPR_MASK01_SHIFT
,
730 R_V7M_VPR_MASK01_LENGTH
+ R_V7M_VPR_MASK23_LENGTH
);
735 /* Update only the 23 mask field */
736 tcg_gen_deposit_i32(vpr
, vpr
,
737 tcg_constant_i32(a
->mask
),
738 R_V7M_VPR_MASK23_SHIFT
, R_V7M_VPR_MASK23_LENGTH
);
741 g_assert_not_reached();
743 store_cpu_field(vpr
, v7m
.vpr
);
744 mve_update_and_store_eci(s
);
748 static bool trans_VADDV(DisasContext
*s
, arg_VADDV
*a
)
750 /* VADDV: vector add across vector */
751 static MVEGenVADDVFn
* const fns
[4][2] = {
752 { gen_helper_mve_vaddvsb
, gen_helper_mve_vaddvub
},
753 { gen_helper_mve_vaddvsh
, gen_helper_mve_vaddvuh
},
754 { gen_helper_mve_vaddvsw
, gen_helper_mve_vaddvuw
},
760 if (!dc_isar_feature(aa32_mve
, s
) ||
764 if (!mve_eci_check(s
) || !vfp_access_check(s
)) {
769 * This insn is subject to beat-wise execution. Partial execution
770 * of an A=0 (no-accumulate) insn which does not execute the first
771 * beat must start with the current value of Rda, not zero.
773 if (a
->a
|| mve_skip_first_beat(s
)) {
774 /* Accumulate input from Rda */
775 rda
= load_reg(s
, a
->rda
);
777 /* Accumulate starting at zero */
778 rda
= tcg_const_i32(0);
781 qm
= mve_qreg_ptr(a
->qm
);
782 fns
[a
->size
][a
->u
](rda
, cpu_env
, qm
, rda
);
783 store_reg(s
, a
->rda
, rda
);
784 tcg_temp_free_ptr(qm
);