machine: pass QAPI struct to mc->smp_parse
[qemu/kevin.git] / target / arm / translate-mve.c
blob67462bdf27d632c7f4bacc59139a9b3f52a218e5
1 /*
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));
48 return ret;
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().
57 return qmask < 8;
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;
68 switch (s->eci) {
69 case ECI_NONE:
70 case ECI_A0:
71 case ECI_A0A1:
72 case ECI_A0A1A2:
73 case ECI_A0A1A2B0:
74 return true;
75 default:
76 /* Reserved value: INVSTATE UsageFault */
77 gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(),
78 default_exception_el(s));
79 return false;
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.
89 if (s->eci) {
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.
101 if (s->eci) {
102 mve_update_eci(s);
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 */
110 switch (s->eci) {
111 case ECI_NONE:
112 return false;
113 case ECI_A0:
114 case ECI_A0A1:
115 case ECI_A0A1A2:
116 case ECI_A0A1A2B0:
117 return true;
118 default:
119 g_assert_not_reached();
123 static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn)
125 TCGv_i32 addr;
126 uint32_t offset;
127 TCGv_ptr qreg;
129 if (!dc_isar_feature(aa32_mve, s) ||
130 !mve_check_qreg_bank(s, a->qd) ||
131 !fn) {
132 return false;
135 /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
136 if (a->rn == 15 || (a->rn == 13 && a->w)) {
137 return false;
140 if (!mve_eci_check(s) || !vfp_access_check(s)) {
141 return true;
144 offset = a->imm << a->size;
145 if (!a->a) {
146 offset = -offset;
148 addr = load_reg(s, a->rn);
149 if (a->p) {
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
161 if (a->w) {
162 if (!a->p) {
163 tcg_gen_addi_i32(addr, addr, offset);
165 store_reg(s, a->rn, addr);
166 } else {
167 tcg_temp_free_i32(addr);
169 mve_update_eci(s);
170 return true;
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 },
179 { NULL, NULL }
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 }, \
190 }; \
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)
200 TCGv_ptr qd;
201 TCGv_i32 rt;
203 if (!dc_isar_feature(aa32_mve, s) ||
204 !mve_check_qreg_bank(s, a->qd)) {
205 return false;
207 if (a->rt == 13 || a->rt == 15) {
208 /* UNPREDICTABLE; we choose to UNDEF */
209 return false;
211 if (!mve_eci_check(s) || !vfp_access_check(s)) {
212 return true;
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);
221 mve_update_eci(s);
222 return true;
225 static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
227 TCGv_ptr qd, qm;
229 if (!dc_isar_feature(aa32_mve, s) ||
230 !mve_check_qreg_bank(s, a->qd | a->qm) ||
231 !fn) {
232 return false;
235 if (!mve_eci_check(s) || !vfp_access_check(s)) {
236 return true;
239 qd = mve_qreg_ptr(a->qd);
240 qm = mve_qreg_ptr(a->qm);
241 fn(cpu_env, qd, qm);
242 tcg_temp_free_ptr(qd);
243 tcg_temp_free_ptr(qm);
244 mve_update_eci(s);
245 return true;
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, \
255 NULL, \
256 }; \
257 return do_1op(s, a, fns[a->size]); \
260 DO_1OP(VCLZ, vclz)
261 DO_1OP(VCLS, vcls)
262 DO_1OP(VABS, vabs)
263 DO_1OP(VNEG, vneg)
265 static bool trans_VREV16(DisasContext *s, arg_1op *a)
267 static MVEGenOneOpFn * const fns[] = {
268 gen_helper_mve_vrev16b,
269 NULL,
270 NULL,
271 NULL,
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,
281 NULL,
282 NULL,
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,
293 NULL,
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[] = {
306 NULL,
307 gen_helper_mve_vfabsh,
308 gen_helper_mve_vfabss,
309 NULL,
311 if (!dc_isar_feature(aa32_mve_fp, s)) {
312 return false;
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[] = {
320 NULL,
321 gen_helper_mve_vfnegh,
322 gen_helper_mve_vfnegs,
323 NULL,
325 if (!dc_isar_feature(aa32_mve_fp, s)) {
326 return false;
328 return do_1op(s, a, fns[a->size]);
331 static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
333 TCGv_ptr qd, qn, qm;
335 if (!dc_isar_feature(aa32_mve, s) ||
336 !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) ||
337 !fn) {
338 return false;
340 if (!mve_eci_check(s) || !vfp_access_check(s)) {
341 return true;
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);
351 mve_update_eci(s);
352 return true;
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, \
374 NULL, \
375 }; \
376 return do_2op(s, a, fns[a->size]); \
379 DO_2OP(VADD, vadd)
380 DO_2OP(VSUB, vsub)
381 DO_2OP(VMUL, vmul)
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[] = {
437 NULL,
438 gen_helper_mve_vqdmullbh,
439 gen_helper_mve_vqdmullbw,
440 NULL,
442 if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
443 /* UNPREDICTABLE; we choose to undef */
444 return false;
446 return do_2op(s, a, fns[a->size]);
449 static bool trans_VQDMULLT(DisasContext *s, arg_2op *a)
451 static MVEGenTwoOpFn * const fns[] = {
452 NULL,
453 gen_helper_mve_vqdmullth,
454 gen_helper_mve_vqdmulltw,
455 NULL,
457 if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
458 /* UNPREDICTABLE; we choose to undef */
459 return false;
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)
504 TCGv_ptr qd, qn;
505 TCGv_i32 rm;
507 if (!dc_isar_feature(aa32_mve, s) ||
508 !mve_check_qreg_bank(s, a->qd | a->qn) ||
509 !fn) {
510 return false;
512 if (a->rm == 13 || a->rm == 15) {
513 /* UNPREDICTABLE */
514 return false;
516 if (!mve_eci_check(s) || !vfp_access_check(s)) {
517 return true;
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);
527 mve_update_eci(s);
528 return true;
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, \
538 NULL, \
539 }; \
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[] = {
561 NULL,
562 gen_helper_mve_vqdmullb_scalarh,
563 gen_helper_mve_vqdmullb_scalarw,
564 NULL,
566 if (a->qd == a->qn && a->size == MO_32) {
567 /* UNPREDICTABLE; we choose to undef */
568 return false;
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[] = {
576 NULL,
577 gen_helper_mve_vqdmullt_scalarh,
578 gen_helper_mve_vqdmullt_scalarw,
579 NULL,
581 if (a->qd == a->qn && a->size == MO_32) {
582 /* UNPREDICTABLE; we choose to undef */
583 return false;
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)
591 TCGv_ptr qn, qm;
592 TCGv_i64 rda;
593 TCGv_i32 rdalo, rdahi;
595 if (!dc_isar_feature(aa32_mve, s) ||
596 !mve_check_qreg_bank(s, a->qn | a->qm) ||
597 !fn) {
598 return false;
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) {
605 return false;
607 if (!mve_eci_check(s) || !vfp_access_check(s)) {
608 return true;
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);
626 } else {
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);
641 mve_update_eci(s);
642 return true;
645 static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a)
647 static MVEGenDualAccOpFn * const fns[4][2] = {
648 { NULL, NULL },
649 { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh },
650 { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw },
651 { NULL, NULL },
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] = {
659 { NULL, NULL },
660 { gen_helper_mve_vmlaldavuh, NULL },
661 { gen_helper_mve_vmlaldavuw, NULL },
662 { NULL, 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] = {
670 { NULL, NULL },
671 { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh },
672 { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw },
673 { NULL, NULL },
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)
704 TCGv_i32 vpr;
706 /* mask == 0 is a "related encoding" */
707 if (!dc_isar_feature(aa32_mve, s) || !a->mask) {
708 return false;
710 if (!mve_eci_check(s) || !vfp_access_check(s)) {
711 return true;
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
720 * 01 mask field.
722 vpr = load_cpu_field(v7m.vpr);
723 switch (s->eci) {
724 case ECI_NONE:
725 case ECI_A0:
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);
731 break;
732 case ECI_A0A1:
733 case ECI_A0A1A2:
734 case ECI_A0A1A2B0:
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);
739 break;
740 default:
741 g_assert_not_reached();
743 store_cpu_field(vpr, v7m.vpr);
744 mve_update_and_store_eci(s);
745 return true;
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 },
755 { NULL, NULL }
757 TCGv_ptr qm;
758 TCGv_i32 rda;
760 if (!dc_isar_feature(aa32_mve, s) ||
761 a->size == 3) {
762 return false;
764 if (!mve_eci_check(s) || !vfp_access_check(s)) {
765 return true;
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);
776 } else {
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);
786 mve_update_eci(s);
787 return true;