xref: /qemu/target/arm/tcg/translate-mve.c (revision dc18628b1833157a50a424cb6b83b63eca560402)
16390eed4SPeter Maydell /*
26390eed4SPeter Maydell  *  ARM translation: M-profile MVE instructions
36390eed4SPeter Maydell  *
46390eed4SPeter Maydell  *  Copyright (c) 2021 Linaro, Ltd.
56390eed4SPeter Maydell  *
66390eed4SPeter Maydell  * This library is free software; you can redistribute it and/or
76390eed4SPeter Maydell  * modify it under the terms of the GNU Lesser General Public
86390eed4SPeter Maydell  * License as published by the Free Software Foundation; either
96390eed4SPeter Maydell  * version 2.1 of the License, or (at your option) any later version.
106390eed4SPeter Maydell  *
116390eed4SPeter Maydell  * This library is distributed in the hope that it will be useful,
126390eed4SPeter Maydell  * but WITHOUT ANY WARRANTY; without even the implied warranty of
136390eed4SPeter Maydell  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
146390eed4SPeter Maydell  * Lesser General Public License for more details.
156390eed4SPeter Maydell  *
166390eed4SPeter Maydell  * You should have received a copy of the GNU Lesser General Public
176390eed4SPeter Maydell  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
186390eed4SPeter Maydell  */
196390eed4SPeter Maydell 
206390eed4SPeter Maydell #include "qemu/osdep.h"
216390eed4SPeter Maydell #include "tcg/tcg-op.h"
226390eed4SPeter Maydell #include "tcg/tcg-op-gvec.h"
236390eed4SPeter Maydell #include "exec/exec-all.h"
246390eed4SPeter Maydell #include "exec/gen-icount.h"
256390eed4SPeter Maydell #include "translate.h"
266390eed4SPeter Maydell #include "translate-a32.h"
276390eed4SPeter Maydell 
28395b92d5SPeter Maydell static inline int vidup_imm(DisasContext *s, int x)
29395b92d5SPeter Maydell {
30395b92d5SPeter Maydell     return 1 << x;
31395b92d5SPeter Maydell }
32395b92d5SPeter Maydell 
336390eed4SPeter Maydell /* Include the generated decoder */
346390eed4SPeter Maydell #include "decode-mve.c.inc"
35507b6a50SPeter Maydell 
36507b6a50SPeter Maydell typedef void MVEGenLdStFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
37*dc18628bSPeter Maydell typedef void MVEGenLdStSGFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
380f0f2bd5SPeter Maydell typedef void MVEGenOneOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
3968245e44SPeter Maydell typedef void MVEGenTwoOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr);
40e51896b3SPeter Maydell typedef void MVEGenTwoOpScalarFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
41f9ed6174SPeter Maydell typedef void MVEGenTwoOpShiftFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
42640cdf20SPeter Maydell typedef void MVEGenLongDualAccOpFn(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64);
436f060a63SPeter Maydell typedef void MVEGenVADDVFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32);
44eab84139SPeter Maydell typedef void MVEGenOneOpImmFn(TCGv_ptr, TCGv_ptr, TCGv_i64);
45395b92d5SPeter Maydell typedef void MVEGenVIDUPFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32, TCGv_i32);
46395b92d5SPeter Maydell typedef void MVEGenVIWDUPFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32);
47eff5d9a9SPeter Maydell typedef void MVEGenCmpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
48cce81873SPeter Maydell typedef void MVEGenScalarCmpFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
497f061c0aSPeter Maydell typedef void MVEGenVABAVFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
50f0ffff51SPeter Maydell typedef void MVEGenDualAccOpFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
51507b6a50SPeter Maydell 
52507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */
53507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg)
54507b6a50SPeter Maydell {
55507b6a50SPeter Maydell     return offsetof(CPUARMState, vfp.zregs[reg].d[0]);
56507b6a50SPeter Maydell }
57507b6a50SPeter Maydell 
58507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg)
59507b6a50SPeter Maydell {
60507b6a50SPeter Maydell     TCGv_ptr ret = tcg_temp_new_ptr();
61507b6a50SPeter Maydell     tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg));
62507b6a50SPeter Maydell     return ret;
63507b6a50SPeter Maydell }
64507b6a50SPeter Maydell 
65507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask)
66507b6a50SPeter Maydell {
67507b6a50SPeter Maydell     /*
68507b6a50SPeter Maydell      * Check whether Qregs are in range. For v8.1M only Q0..Q7
69507b6a50SPeter Maydell      * are supported, see VFPSmallRegisterBank().
70507b6a50SPeter Maydell      */
71507b6a50SPeter Maydell     return qmask < 8;
72507b6a50SPeter Maydell }
73507b6a50SPeter Maydell 
744f57ef95SPeter Maydell bool mve_eci_check(DisasContext *s)
75507b6a50SPeter Maydell {
76507b6a50SPeter Maydell     /*
77507b6a50SPeter Maydell      * This is a beatwise insn: check that ECI is valid (not a
78507b6a50SPeter Maydell      * reserved value) and note that we are handling it.
79507b6a50SPeter Maydell      * Return true if OK, false if we generated an exception.
80507b6a50SPeter Maydell      */
81507b6a50SPeter Maydell     s->eci_handled = true;
82507b6a50SPeter Maydell     switch (s->eci) {
83507b6a50SPeter Maydell     case ECI_NONE:
84507b6a50SPeter Maydell     case ECI_A0:
85507b6a50SPeter Maydell     case ECI_A0A1:
86507b6a50SPeter Maydell     case ECI_A0A1A2:
87507b6a50SPeter Maydell     case ECI_A0A1A2B0:
88507b6a50SPeter Maydell         return true;
89507b6a50SPeter Maydell     default:
90507b6a50SPeter Maydell         /* Reserved value: INVSTATE UsageFault */
91507b6a50SPeter Maydell         gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(),
92507b6a50SPeter Maydell                            default_exception_el(s));
93507b6a50SPeter Maydell         return false;
94507b6a50SPeter Maydell     }
95507b6a50SPeter Maydell }
96507b6a50SPeter Maydell 
970f31e37cSPeter Maydell void mve_update_eci(DisasContext *s)
98507b6a50SPeter Maydell {
99507b6a50SPeter Maydell     /*
100507b6a50SPeter Maydell      * The helper function will always update the CPUState field,
101507b6a50SPeter Maydell      * so we only need to update the DisasContext field.
102507b6a50SPeter Maydell      */
103507b6a50SPeter Maydell     if (s->eci) {
104507b6a50SPeter Maydell         s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE;
105507b6a50SPeter Maydell     }
106507b6a50SPeter Maydell }
107507b6a50SPeter Maydell 
1084f57ef95SPeter Maydell void mve_update_and_store_eci(DisasContext *s)
109387debdbSPeter Maydell {
110387debdbSPeter Maydell     /*
111387debdbSPeter Maydell      * For insns which don't call a helper function that will call
112387debdbSPeter Maydell      * mve_advance_vpt(), this version updates s->eci and also stores
113387debdbSPeter Maydell      * it out to the CPUState field.
114387debdbSPeter Maydell      */
115387debdbSPeter Maydell     if (s->eci) {
116387debdbSPeter Maydell         mve_update_eci(s);
117387debdbSPeter Maydell         store_cpu_field(tcg_constant_i32(s->eci << 4), condexec_bits);
118387debdbSPeter Maydell     }
119387debdbSPeter Maydell }
120387debdbSPeter Maydell 
1211d2386f7SPeter Maydell static bool mve_skip_first_beat(DisasContext *s)
1221d2386f7SPeter Maydell {
1231d2386f7SPeter Maydell     /* Return true if PSR.ECI says we must skip the first beat of this insn */
1241d2386f7SPeter Maydell     switch (s->eci) {
1251d2386f7SPeter Maydell     case ECI_NONE:
1261d2386f7SPeter Maydell         return false;
1271d2386f7SPeter Maydell     case ECI_A0:
1281d2386f7SPeter Maydell     case ECI_A0A1:
1291d2386f7SPeter Maydell     case ECI_A0A1A2:
1301d2386f7SPeter Maydell     case ECI_A0A1A2B0:
1311d2386f7SPeter Maydell         return true;
1321d2386f7SPeter Maydell     default:
1331d2386f7SPeter Maydell         g_assert_not_reached();
1341d2386f7SPeter Maydell     }
1351d2386f7SPeter Maydell }
1361d2386f7SPeter Maydell 
137d59ccc30SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn,
138d59ccc30SPeter Maydell                     unsigned msize)
139507b6a50SPeter Maydell {
140507b6a50SPeter Maydell     TCGv_i32 addr;
141507b6a50SPeter Maydell     uint32_t offset;
142507b6a50SPeter Maydell     TCGv_ptr qreg;
143507b6a50SPeter Maydell 
144507b6a50SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
145507b6a50SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
146507b6a50SPeter Maydell         !fn) {
147507b6a50SPeter Maydell         return false;
148507b6a50SPeter Maydell     }
149507b6a50SPeter Maydell 
150507b6a50SPeter Maydell     /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
151507b6a50SPeter Maydell     if (a->rn == 15 || (a->rn == 13 && a->w)) {
152507b6a50SPeter Maydell         return false;
153507b6a50SPeter Maydell     }
154507b6a50SPeter Maydell 
155507b6a50SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
156507b6a50SPeter Maydell         return true;
157507b6a50SPeter Maydell     }
158507b6a50SPeter Maydell 
159d59ccc30SPeter Maydell     offset = a->imm << msize;
160507b6a50SPeter Maydell     if (!a->a) {
161507b6a50SPeter Maydell         offset = -offset;
162507b6a50SPeter Maydell     }
163507b6a50SPeter Maydell     addr = load_reg(s, a->rn);
164507b6a50SPeter Maydell     if (a->p) {
165507b6a50SPeter Maydell         tcg_gen_addi_i32(addr, addr, offset);
166507b6a50SPeter Maydell     }
167507b6a50SPeter Maydell 
168507b6a50SPeter Maydell     qreg = mve_qreg_ptr(a->qd);
169507b6a50SPeter Maydell     fn(cpu_env, qreg, addr);
170507b6a50SPeter Maydell     tcg_temp_free_ptr(qreg);
171507b6a50SPeter Maydell 
172507b6a50SPeter Maydell     /*
173507b6a50SPeter Maydell      * Writeback always happens after the last beat of the insn,
174507b6a50SPeter Maydell      * regardless of predication
175507b6a50SPeter Maydell      */
176507b6a50SPeter Maydell     if (a->w) {
177507b6a50SPeter Maydell         if (!a->p) {
178507b6a50SPeter Maydell             tcg_gen_addi_i32(addr, addr, offset);
179507b6a50SPeter Maydell         }
180507b6a50SPeter Maydell         store_reg(s, a->rn, addr);
181507b6a50SPeter Maydell     } else {
182507b6a50SPeter Maydell         tcg_temp_free_i32(addr);
183507b6a50SPeter Maydell     }
184507b6a50SPeter Maydell     mve_update_eci(s);
185507b6a50SPeter Maydell     return true;
186507b6a50SPeter Maydell }
187507b6a50SPeter Maydell 
188507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a)
189507b6a50SPeter Maydell {
190507b6a50SPeter Maydell     static MVEGenLdStFn * const ldstfns[4][2] = {
191507b6a50SPeter Maydell         { gen_helper_mve_vstrb, gen_helper_mve_vldrb },
192507b6a50SPeter Maydell         { gen_helper_mve_vstrh, gen_helper_mve_vldrh },
193507b6a50SPeter Maydell         { gen_helper_mve_vstrw, gen_helper_mve_vldrw },
194507b6a50SPeter Maydell         { NULL, NULL }
195507b6a50SPeter Maydell     };
196d59ccc30SPeter Maydell     return do_ldst(s, a, ldstfns[a->size][a->l], a->size);
197507b6a50SPeter Maydell }
1982fc6b751SPeter Maydell 
199d59ccc30SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST, MSIZE)           \
2002fc6b751SPeter Maydell     static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a)   \
2012fc6b751SPeter Maydell     {                                                           \
2022fc6b751SPeter Maydell         static MVEGenLdStFn * const ldstfns[2][2] = {           \
2032fc6b751SPeter Maydell             { gen_helper_mve_##ST, gen_helper_mve_##SLD },      \
2042fc6b751SPeter Maydell             { NULL, gen_helper_mve_##ULD },                     \
2052fc6b751SPeter Maydell         };                                                      \
206d59ccc30SPeter Maydell         return do_ldst(s, a, ldstfns[a->u][a->l], MSIZE);       \
2072fc6b751SPeter Maydell     }
2082fc6b751SPeter Maydell 
209d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h, MO_8)
210d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w, MO_8)
211d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w, MO_16)
2120f0f2bd5SPeter Maydell 
213*dc18628bSPeter Maydell static bool do_ldst_sg(DisasContext *s, arg_vldst_sg *a, MVEGenLdStSGFn fn)
214*dc18628bSPeter Maydell {
215*dc18628bSPeter Maydell     TCGv_i32 addr;
216*dc18628bSPeter Maydell     TCGv_ptr qd, qm;
217*dc18628bSPeter Maydell 
218*dc18628bSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
219*dc18628bSPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
220*dc18628bSPeter Maydell         !fn || a->rn == 15) {
221*dc18628bSPeter Maydell         /* Rn case is UNPREDICTABLE */
222*dc18628bSPeter Maydell         return false;
223*dc18628bSPeter Maydell     }
224*dc18628bSPeter Maydell 
225*dc18628bSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
226*dc18628bSPeter Maydell         return true;
227*dc18628bSPeter Maydell     }
228*dc18628bSPeter Maydell 
229*dc18628bSPeter Maydell     addr = load_reg(s, a->rn);
230*dc18628bSPeter Maydell 
231*dc18628bSPeter Maydell     qd = mve_qreg_ptr(a->qd);
232*dc18628bSPeter Maydell     qm = mve_qreg_ptr(a->qm);
233*dc18628bSPeter Maydell     fn(cpu_env, qd, qm, addr);
234*dc18628bSPeter Maydell     tcg_temp_free_ptr(qd);
235*dc18628bSPeter Maydell     tcg_temp_free_ptr(qm);
236*dc18628bSPeter Maydell     tcg_temp_free_i32(addr);
237*dc18628bSPeter Maydell     mve_update_eci(s);
238*dc18628bSPeter Maydell     return true;
239*dc18628bSPeter Maydell }
240*dc18628bSPeter Maydell 
241*dc18628bSPeter Maydell /*
242*dc18628bSPeter Maydell  * The naming scheme here is "vldrb_sg_sh == in-memory byte loads
243*dc18628bSPeter Maydell  * signextended to halfword elements in register". _os_ indicates that
244*dc18628bSPeter Maydell  * the offsets in Qm should be scaled by the element size.
245*dc18628bSPeter Maydell  */
246*dc18628bSPeter Maydell /* This macro is just to make the arrays more compact in these functions */
247*dc18628bSPeter Maydell #define F(N) gen_helper_mve_##N
248*dc18628bSPeter Maydell 
249*dc18628bSPeter Maydell /* VLDRB/VSTRB (ie msize 1) with OS=1 is UNPREDICTABLE; we UNDEF */
250*dc18628bSPeter Maydell static bool trans_VLDR_S_sg(DisasContext *s, arg_vldst_sg *a)
251*dc18628bSPeter Maydell {
252*dc18628bSPeter Maydell     static MVEGenLdStSGFn * const fns[2][4][4] = { {
253*dc18628bSPeter Maydell             { NULL, F(vldrb_sg_sh), F(vldrb_sg_sw), NULL },
254*dc18628bSPeter Maydell             { NULL, NULL,           F(vldrh_sg_sw), NULL },
255*dc18628bSPeter Maydell             { NULL, NULL,           NULL,           NULL },
256*dc18628bSPeter Maydell             { NULL, NULL,           NULL,           NULL }
257*dc18628bSPeter Maydell         }, {
258*dc18628bSPeter Maydell             { NULL, NULL,              NULL,              NULL },
259*dc18628bSPeter Maydell             { NULL, NULL,              F(vldrh_sg_os_sw), NULL },
260*dc18628bSPeter Maydell             { NULL, NULL,              NULL,              NULL },
261*dc18628bSPeter Maydell             { NULL, NULL,              NULL,              NULL }
262*dc18628bSPeter Maydell         }
263*dc18628bSPeter Maydell     };
264*dc18628bSPeter Maydell     if (a->qd == a->qm) {
265*dc18628bSPeter Maydell         return false; /* UNPREDICTABLE */
266*dc18628bSPeter Maydell     }
267*dc18628bSPeter Maydell     return do_ldst_sg(s, a, fns[a->os][a->msize][a->size]);
268*dc18628bSPeter Maydell }
269*dc18628bSPeter Maydell 
270*dc18628bSPeter Maydell static bool trans_VLDR_U_sg(DisasContext *s, arg_vldst_sg *a)
271*dc18628bSPeter Maydell {
272*dc18628bSPeter Maydell     static MVEGenLdStSGFn * const fns[2][4][4] = { {
273*dc18628bSPeter Maydell             { F(vldrb_sg_ub), F(vldrb_sg_uh), F(vldrb_sg_uw), NULL },
274*dc18628bSPeter Maydell             { NULL,           F(vldrh_sg_uh), F(vldrh_sg_uw), NULL },
275*dc18628bSPeter Maydell             { NULL,           NULL,           F(vldrw_sg_uw), NULL },
276*dc18628bSPeter Maydell             { NULL,           NULL,           NULL,           F(vldrd_sg_ud) }
277*dc18628bSPeter Maydell         }, {
278*dc18628bSPeter Maydell             { NULL, NULL,              NULL,              NULL },
279*dc18628bSPeter Maydell             { NULL, F(vldrh_sg_os_uh), F(vldrh_sg_os_uw), NULL },
280*dc18628bSPeter Maydell             { NULL, NULL,              F(vldrw_sg_os_uw), NULL },
281*dc18628bSPeter Maydell             { NULL, NULL,              NULL,              F(vldrd_sg_os_ud) }
282*dc18628bSPeter Maydell         }
283*dc18628bSPeter Maydell     };
284*dc18628bSPeter Maydell     if (a->qd == a->qm) {
285*dc18628bSPeter Maydell         return false; /* UNPREDICTABLE */
286*dc18628bSPeter Maydell     }
287*dc18628bSPeter Maydell     return do_ldst_sg(s, a, fns[a->os][a->msize][a->size]);
288*dc18628bSPeter Maydell }
289*dc18628bSPeter Maydell 
290*dc18628bSPeter Maydell static bool trans_VSTR_sg(DisasContext *s, arg_vldst_sg *a)
291*dc18628bSPeter Maydell {
292*dc18628bSPeter Maydell     static MVEGenLdStSGFn * const fns[2][4][4] = { {
293*dc18628bSPeter Maydell             { F(vstrb_sg_ub), F(vstrb_sg_uh), F(vstrb_sg_uw), NULL },
294*dc18628bSPeter Maydell             { NULL,           F(vstrh_sg_uh), F(vstrh_sg_uw), NULL },
295*dc18628bSPeter Maydell             { NULL,           NULL,           F(vstrw_sg_uw), NULL },
296*dc18628bSPeter Maydell             { NULL,           NULL,           NULL,           F(vstrd_sg_ud) }
297*dc18628bSPeter Maydell         }, {
298*dc18628bSPeter Maydell             { NULL, NULL,              NULL,              NULL },
299*dc18628bSPeter Maydell             { NULL, F(vstrh_sg_os_uh), F(vstrh_sg_os_uw), NULL },
300*dc18628bSPeter Maydell             { NULL, NULL,              F(vstrw_sg_os_uw), NULL },
301*dc18628bSPeter Maydell             { NULL, NULL,              NULL,              F(vstrd_sg_os_ud) }
302*dc18628bSPeter Maydell         }
303*dc18628bSPeter Maydell     };
304*dc18628bSPeter Maydell     return do_ldst_sg(s, a, fns[a->os][a->msize][a->size]);
305*dc18628bSPeter Maydell }
306*dc18628bSPeter Maydell 
307*dc18628bSPeter Maydell #undef F
308*dc18628bSPeter Maydell 
309ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
310ab59362fSPeter Maydell {
311ab59362fSPeter Maydell     TCGv_ptr qd;
312ab59362fSPeter Maydell     TCGv_i32 rt;
313ab59362fSPeter Maydell 
314ab59362fSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
315ab59362fSPeter Maydell         !mve_check_qreg_bank(s, a->qd)) {
316ab59362fSPeter Maydell         return false;
317ab59362fSPeter Maydell     }
318ab59362fSPeter Maydell     if (a->rt == 13 || a->rt == 15) {
319ab59362fSPeter Maydell         /* UNPREDICTABLE; we choose to UNDEF */
320ab59362fSPeter Maydell         return false;
321ab59362fSPeter Maydell     }
322ab59362fSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
323ab59362fSPeter Maydell         return true;
324ab59362fSPeter Maydell     }
325ab59362fSPeter Maydell 
326ab59362fSPeter Maydell     qd = mve_qreg_ptr(a->qd);
327ab59362fSPeter Maydell     rt = load_reg(s, a->rt);
328ab59362fSPeter Maydell     tcg_gen_dup_i32(a->size, rt, rt);
329ab59362fSPeter Maydell     gen_helper_mve_vdup(cpu_env, qd, rt);
330ab59362fSPeter Maydell     tcg_temp_free_ptr(qd);
331ab59362fSPeter Maydell     tcg_temp_free_i32(rt);
332ab59362fSPeter Maydell     mve_update_eci(s);
333ab59362fSPeter Maydell     return true;
334ab59362fSPeter Maydell }
335ab59362fSPeter Maydell 
3360f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
3370f0f2bd5SPeter Maydell {
3380f0f2bd5SPeter Maydell     TCGv_ptr qd, qm;
3390f0f2bd5SPeter Maydell 
3400f0f2bd5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
3410f0f2bd5SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
3420f0f2bd5SPeter Maydell         !fn) {
3430f0f2bd5SPeter Maydell         return false;
3440f0f2bd5SPeter Maydell     }
3450f0f2bd5SPeter Maydell 
3460f0f2bd5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
3470f0f2bd5SPeter Maydell         return true;
3480f0f2bd5SPeter Maydell     }
3490f0f2bd5SPeter Maydell 
3500f0f2bd5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
3510f0f2bd5SPeter Maydell     qm = mve_qreg_ptr(a->qm);
3520f0f2bd5SPeter Maydell     fn(cpu_env, qd, qm);
3530f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qd);
3540f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qm);
3550f0f2bd5SPeter Maydell     mve_update_eci(s);
3560f0f2bd5SPeter Maydell     return true;
3570f0f2bd5SPeter Maydell }
3580f0f2bd5SPeter Maydell 
3590f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN)                                        \
3600f0f2bd5SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
3610f0f2bd5SPeter Maydell     {                                                           \
3620f0f2bd5SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
3630f0f2bd5SPeter Maydell             gen_helper_mve_##FN##b,                             \
3640f0f2bd5SPeter Maydell             gen_helper_mve_##FN##h,                             \
3650f0f2bd5SPeter Maydell             gen_helper_mve_##FN##w,                             \
3660f0f2bd5SPeter Maydell             NULL,                                               \
3670f0f2bd5SPeter Maydell         };                                                      \
3680f0f2bd5SPeter Maydell         return do_1op(s, a, fns[a->size]);                      \
3690f0f2bd5SPeter Maydell     }
3700f0f2bd5SPeter Maydell 
3710f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz)
3726437f1f7SPeter Maydell DO_1OP(VCLS, vcls)
37359c91773SPeter Maydell DO_1OP(VABS, vabs)
374399a8c76SPeter Maydell DO_1OP(VNEG, vneg)
375398e7cd3SPeter Maydell DO_1OP(VQABS, vqabs)
376398e7cd3SPeter Maydell DO_1OP(VQNEG, vqneg)
377d5c571eaSPeter Maydell DO_1OP(VMAXA, vmaxa)
378d5c571eaSPeter Maydell DO_1OP(VMINA, vmina)
379249b5309SPeter Maydell 
38054dc78a9SPeter Maydell /* Narrowing moves: only size 0 and 1 are valid */
38154dc78a9SPeter Maydell #define DO_VMOVN(INSN, FN) \
38254dc78a9SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
38354dc78a9SPeter Maydell     {                                                           \
38454dc78a9SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
38554dc78a9SPeter Maydell             gen_helper_mve_##FN##b,                             \
38654dc78a9SPeter Maydell             gen_helper_mve_##FN##h,                             \
38754dc78a9SPeter Maydell             NULL,                                               \
38854dc78a9SPeter Maydell             NULL,                                               \
38954dc78a9SPeter Maydell         };                                                      \
39054dc78a9SPeter Maydell         return do_1op(s, a, fns[a->size]);                      \
39154dc78a9SPeter Maydell     }
39254dc78a9SPeter Maydell 
39354dc78a9SPeter Maydell DO_VMOVN(VMOVNB, vmovnb)
39454dc78a9SPeter Maydell DO_VMOVN(VMOVNT, vmovnt)
39554dc78a9SPeter Maydell DO_VMOVN(VQMOVUNB, vqmovunb)
39654dc78a9SPeter Maydell DO_VMOVN(VQMOVUNT, vqmovunt)
39754dc78a9SPeter Maydell DO_VMOVN(VQMOVN_BS, vqmovnbs)
39854dc78a9SPeter Maydell DO_VMOVN(VQMOVN_TS, vqmovnts)
39954dc78a9SPeter Maydell DO_VMOVN(VQMOVN_BU, vqmovnbu)
40054dc78a9SPeter Maydell DO_VMOVN(VQMOVN_TU, vqmovntu)
40154dc78a9SPeter Maydell 
402249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a)
403249b5309SPeter Maydell {
404249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
405249b5309SPeter Maydell         gen_helper_mve_vrev16b,
406249b5309SPeter Maydell         NULL,
407249b5309SPeter Maydell         NULL,
408249b5309SPeter Maydell         NULL,
409249b5309SPeter Maydell     };
410249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
411249b5309SPeter Maydell }
412249b5309SPeter Maydell 
413249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a)
414249b5309SPeter Maydell {
415249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
416249b5309SPeter Maydell         gen_helper_mve_vrev32b,
417249b5309SPeter Maydell         gen_helper_mve_vrev32h,
418249b5309SPeter Maydell         NULL,
419249b5309SPeter Maydell         NULL,
420249b5309SPeter Maydell     };
421249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
422249b5309SPeter Maydell }
423249b5309SPeter Maydell 
424249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a)
425249b5309SPeter Maydell {
426249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
427249b5309SPeter Maydell         gen_helper_mve_vrev64b,
428249b5309SPeter Maydell         gen_helper_mve_vrev64h,
429249b5309SPeter Maydell         gen_helper_mve_vrev64w,
430249b5309SPeter Maydell         NULL,
431249b5309SPeter Maydell     };
432249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
433249b5309SPeter Maydell }
4348abd3c80SPeter Maydell 
4358abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a)
4368abd3c80SPeter Maydell {
4378abd3c80SPeter Maydell     return do_1op(s, a, gen_helper_mve_vmvn);
4388abd3c80SPeter Maydell }
43959c91773SPeter Maydell 
44059c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a)
44159c91773SPeter Maydell {
44259c91773SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
44359c91773SPeter Maydell         NULL,
44459c91773SPeter Maydell         gen_helper_mve_vfabsh,
44559c91773SPeter Maydell         gen_helper_mve_vfabss,
44659c91773SPeter Maydell         NULL,
44759c91773SPeter Maydell     };
44859c91773SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
44959c91773SPeter Maydell         return false;
45059c91773SPeter Maydell     }
45159c91773SPeter Maydell     return do_1op(s, a, fns[a->size]);
45259c91773SPeter Maydell }
453399a8c76SPeter Maydell 
454399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a)
455399a8c76SPeter Maydell {
456399a8c76SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
457399a8c76SPeter Maydell         NULL,
458399a8c76SPeter Maydell         gen_helper_mve_vfnegh,
459399a8c76SPeter Maydell         gen_helper_mve_vfnegs,
460399a8c76SPeter Maydell         NULL,
461399a8c76SPeter Maydell     };
462399a8c76SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
463399a8c76SPeter Maydell         return false;
464399a8c76SPeter Maydell     }
465399a8c76SPeter Maydell     return do_1op(s, a, fns[a->size]);
466399a8c76SPeter Maydell }
46768245e44SPeter Maydell 
46868245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
46968245e44SPeter Maydell {
47068245e44SPeter Maydell     TCGv_ptr qd, qn, qm;
47168245e44SPeter Maydell 
47268245e44SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
47368245e44SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) ||
47468245e44SPeter Maydell         !fn) {
47568245e44SPeter Maydell         return false;
47668245e44SPeter Maydell     }
47768245e44SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
47868245e44SPeter Maydell         return true;
47968245e44SPeter Maydell     }
48068245e44SPeter Maydell 
48168245e44SPeter Maydell     qd = mve_qreg_ptr(a->qd);
48268245e44SPeter Maydell     qn = mve_qreg_ptr(a->qn);
48368245e44SPeter Maydell     qm = mve_qreg_ptr(a->qm);
48468245e44SPeter Maydell     fn(cpu_env, qd, qn, qm);
48568245e44SPeter Maydell     tcg_temp_free_ptr(qd);
48668245e44SPeter Maydell     tcg_temp_free_ptr(qn);
48768245e44SPeter Maydell     tcg_temp_free_ptr(qm);
48868245e44SPeter Maydell     mve_update_eci(s);
48968245e44SPeter Maydell     return true;
49068245e44SPeter Maydell }
49168245e44SPeter Maydell 
49268245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER)                                  \
49368245e44SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
49468245e44SPeter Maydell     {                                                           \
49568245e44SPeter Maydell         return do_2op(s, a, HELPER);                            \
49668245e44SPeter Maydell     }
49768245e44SPeter Maydell 
49868245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand)
49968245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic)
50068245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr)
50168245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn)
50268245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor)
5039333fe4dSPeter Maydell 
504c386443bSPeter Maydell DO_LOGIC(VPSEL, gen_helper_mve_vpsel)
505c386443bSPeter Maydell 
5069333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \
5079333fe4dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
5089333fe4dSPeter Maydell     {                                                           \
5099333fe4dSPeter Maydell         static MVEGenTwoOpFn * const fns[] = {                  \
5109333fe4dSPeter Maydell             gen_helper_mve_##FN##b,                             \
5119333fe4dSPeter Maydell             gen_helper_mve_##FN##h,                             \
5129333fe4dSPeter Maydell             gen_helper_mve_##FN##w,                             \
5139333fe4dSPeter Maydell             NULL,                                               \
5149333fe4dSPeter Maydell         };                                                      \
5159333fe4dSPeter Maydell         return do_2op(s, a, fns[a->size]);                      \
5169333fe4dSPeter Maydell     }
5179333fe4dSPeter Maydell 
5189333fe4dSPeter Maydell DO_2OP(VADD, vadd)
5199333fe4dSPeter Maydell DO_2OP(VSUB, vsub)
5209333fe4dSPeter Maydell DO_2OP(VMUL, vmul)
521ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs)
522ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu)
523fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs)
524fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu)
525cd367ff3SPeter Maydell DO_2OP(VMAX_S, vmaxs)
526cd367ff3SPeter Maydell DO_2OP(VMAX_U, vmaxu)
527cd367ff3SPeter Maydell DO_2OP(VMIN_S, vmins)
528cd367ff3SPeter Maydell DO_2OP(VMIN_U, vminu)
529bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds)
530bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu)
531abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds)
532abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu)
533abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs)
534abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu)
535ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs)
536ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu)
537ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts)
538ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu)
539380caf6cSPeter Maydell DO_2OP(VQDMULH, vqdmulh)
540380caf6cSPeter Maydell DO_2OP(VQRDMULH, vqrdmulh)
541f741707bSPeter Maydell DO_2OP(VQADD_S, vqadds)
542f741707bSPeter Maydell DO_2OP(VQADD_U, vqaddu)
543f741707bSPeter Maydell DO_2OP(VQSUB_S, vqsubs)
544f741707bSPeter Maydell DO_2OP(VQSUB_U, vqsubu)
5450372cad8SPeter Maydell DO_2OP(VSHL_S, vshls)
5460372cad8SPeter Maydell DO_2OP(VSHL_U, vshlu)
547bb002345SPeter Maydell DO_2OP(VRSHL_S, vrshls)
548bb002345SPeter Maydell DO_2OP(VRSHL_U, vrshlu)
549483da661SPeter Maydell DO_2OP(VQSHL_S, vqshls)
550483da661SPeter Maydell DO_2OP(VQSHL_U, vqshlu)
5519dc868c4SPeter Maydell DO_2OP(VQRSHL_S, vqrshls)
5529dc868c4SPeter Maydell DO_2OP(VQRSHL_U, vqrshlu)
553fd677f80SPeter Maydell DO_2OP(VQDMLADH, vqdmladh)
554fd677f80SPeter Maydell DO_2OP(VQDMLADHX, vqdmladhx)
555fd677f80SPeter Maydell DO_2OP(VQRDMLADH, vqrdmladh)
556fd677f80SPeter Maydell DO_2OP(VQRDMLADHX, vqrdmladhx)
55792f11732SPeter Maydell DO_2OP(VQDMLSDH, vqdmlsdh)
55892f11732SPeter Maydell DO_2OP(VQDMLSDHX, vqdmlsdhx)
55992f11732SPeter Maydell DO_2OP(VQRDMLSDH, vqrdmlsdh)
56092f11732SPeter Maydell DO_2OP(VQRDMLSDHX, vqrdmlsdhx)
5611eb987a8SPeter Maydell DO_2OP(VRHADD_S, vrhadds)
5621eb987a8SPeter Maydell DO_2OP(VRHADD_U, vrhaddu)
56367ec113bSPeter Maydell /*
56467ec113bSPeter Maydell  * VCADD Qd == Qm at size MO_32 is UNPREDICTABLE; we choose not to diagnose
56567ec113bSPeter Maydell  * so we can reuse the DO_2OP macro. (Our implementation calculates the
5668625693aSPeter Maydell  * "expected" results in this case.) Similarly for VHCADD.
56767ec113bSPeter Maydell  */
56867ec113bSPeter Maydell DO_2OP(VCADD90, vcadd90)
56967ec113bSPeter Maydell DO_2OP(VCADD270, vcadd270)
5708625693aSPeter Maydell DO_2OP(VHCADD90, vhcadd90)
5718625693aSPeter Maydell DO_2OP(VHCADD270, vhcadd270)
5721d2386f7SPeter Maydell 
57343364321SPeter Maydell static bool trans_VQDMULLB(DisasContext *s, arg_2op *a)
57443364321SPeter Maydell {
57543364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
57643364321SPeter Maydell         NULL,
57743364321SPeter Maydell         gen_helper_mve_vqdmullbh,
57843364321SPeter Maydell         gen_helper_mve_vqdmullbw,
57943364321SPeter Maydell         NULL,
58043364321SPeter Maydell     };
58143364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
58243364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
58343364321SPeter Maydell         return false;
58443364321SPeter Maydell     }
58543364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
58643364321SPeter Maydell }
58743364321SPeter Maydell 
58843364321SPeter Maydell static bool trans_VQDMULLT(DisasContext *s, arg_2op *a)
58943364321SPeter Maydell {
59043364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
59143364321SPeter Maydell         NULL,
59243364321SPeter Maydell         gen_helper_mve_vqdmullth,
59343364321SPeter Maydell         gen_helper_mve_vqdmulltw,
59443364321SPeter Maydell         NULL,
59543364321SPeter Maydell     };
59643364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
59743364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
59843364321SPeter Maydell         return false;
59943364321SPeter Maydell     }
60043364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
60143364321SPeter Maydell }
60243364321SPeter Maydell 
603c1bd78cbSPeter Maydell static bool trans_VMULLP_B(DisasContext *s, arg_2op *a)
604c1bd78cbSPeter Maydell {
605c1bd78cbSPeter Maydell     /*
606c1bd78cbSPeter Maydell      * Note that a->size indicates the output size, ie VMULL.P8
607c1bd78cbSPeter Maydell      * is the 8x8->16 operation and a->size is MO_16; VMULL.P16
608c1bd78cbSPeter Maydell      * is the 16x16->32 operation and a->size is MO_32.
609c1bd78cbSPeter Maydell      */
610c1bd78cbSPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
611c1bd78cbSPeter Maydell         NULL,
612c1bd78cbSPeter Maydell         gen_helper_mve_vmullpbh,
613c1bd78cbSPeter Maydell         gen_helper_mve_vmullpbw,
614c1bd78cbSPeter Maydell         NULL,
615c1bd78cbSPeter Maydell     };
616c1bd78cbSPeter Maydell     return do_2op(s, a, fns[a->size]);
617c1bd78cbSPeter Maydell }
618c1bd78cbSPeter Maydell 
619c1bd78cbSPeter Maydell static bool trans_VMULLP_T(DisasContext *s, arg_2op *a)
620c1bd78cbSPeter Maydell {
621c1bd78cbSPeter Maydell     /* a->size is as for trans_VMULLP_B */
622c1bd78cbSPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
623c1bd78cbSPeter Maydell         NULL,
624c1bd78cbSPeter Maydell         gen_helper_mve_vmullpth,
625c1bd78cbSPeter Maydell         gen_helper_mve_vmullptw,
626c1bd78cbSPeter Maydell         NULL,
627c1bd78cbSPeter Maydell     };
628c1bd78cbSPeter Maydell     return do_2op(s, a, fns[a->size]);
629c1bd78cbSPeter Maydell }
630c1bd78cbSPeter Maydell 
63189bc4c4fSPeter Maydell /*
63289bc4c4fSPeter Maydell  * VADC and VSBC: these perform an add-with-carry or subtract-with-carry
63389bc4c4fSPeter Maydell  * of the 32-bit elements in each lane of the input vectors, where the
63489bc4c4fSPeter Maydell  * carry-out of each add is the carry-in of the next.  The initial carry
63589bc4c4fSPeter Maydell  * input is either fixed (0 for VADCI, 1 for VSBCI) or is from FPSCR.C
63689bc4c4fSPeter Maydell  * (for VADC and VSBC); the carry out at the end is written back to FPSCR.C.
63789bc4c4fSPeter Maydell  * These insns are subject to beat-wise execution.  Partial execution
63889bc4c4fSPeter Maydell  * of an I=1 (initial carry input fixed) insn which does not
63989bc4c4fSPeter Maydell  * execute the first beat must start with the current FPSCR.NZCV
64089bc4c4fSPeter Maydell  * value, not the fixed constant input.
64189bc4c4fSPeter Maydell  */
64289bc4c4fSPeter Maydell static bool trans_VADC(DisasContext *s, arg_2op *a)
64389bc4c4fSPeter Maydell {
64489bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadc);
64589bc4c4fSPeter Maydell }
64689bc4c4fSPeter Maydell 
64789bc4c4fSPeter Maydell static bool trans_VADCI(DisasContext *s, arg_2op *a)
64889bc4c4fSPeter Maydell {
64989bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
65089bc4c4fSPeter Maydell         return trans_VADC(s, a);
65189bc4c4fSPeter Maydell     }
65289bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadci);
65389bc4c4fSPeter Maydell }
65489bc4c4fSPeter Maydell 
65589bc4c4fSPeter Maydell static bool trans_VSBC(DisasContext *s, arg_2op *a)
65689bc4c4fSPeter Maydell {
65789bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbc);
65889bc4c4fSPeter Maydell }
65989bc4c4fSPeter Maydell 
66089bc4c4fSPeter Maydell static bool trans_VSBCI(DisasContext *s, arg_2op *a)
66189bc4c4fSPeter Maydell {
66289bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
66389bc4c4fSPeter Maydell         return trans_VSBC(s, a);
66489bc4c4fSPeter Maydell     }
66589bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbci);
66689bc4c4fSPeter Maydell }
66789bc4c4fSPeter Maydell 
668e51896b3SPeter Maydell static bool do_2op_scalar(DisasContext *s, arg_2scalar *a,
669e51896b3SPeter Maydell                           MVEGenTwoOpScalarFn fn)
670e51896b3SPeter Maydell {
671e51896b3SPeter Maydell     TCGv_ptr qd, qn;
672e51896b3SPeter Maydell     TCGv_i32 rm;
673e51896b3SPeter Maydell 
674e51896b3SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
675e51896b3SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn) ||
676e51896b3SPeter Maydell         !fn) {
677e51896b3SPeter Maydell         return false;
678e51896b3SPeter Maydell     }
679e51896b3SPeter Maydell     if (a->rm == 13 || a->rm == 15) {
680e51896b3SPeter Maydell         /* UNPREDICTABLE */
681e51896b3SPeter Maydell         return false;
682e51896b3SPeter Maydell     }
683e51896b3SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
684e51896b3SPeter Maydell         return true;
685e51896b3SPeter Maydell     }
686e51896b3SPeter Maydell 
687e51896b3SPeter Maydell     qd = mve_qreg_ptr(a->qd);
688e51896b3SPeter Maydell     qn = mve_qreg_ptr(a->qn);
689e51896b3SPeter Maydell     rm = load_reg(s, a->rm);
690e51896b3SPeter Maydell     fn(cpu_env, qd, qn, rm);
691e51896b3SPeter Maydell     tcg_temp_free_i32(rm);
692e51896b3SPeter Maydell     tcg_temp_free_ptr(qd);
693e51896b3SPeter Maydell     tcg_temp_free_ptr(qn);
694e51896b3SPeter Maydell     mve_update_eci(s);
695e51896b3SPeter Maydell     return true;
696e51896b3SPeter Maydell }
697e51896b3SPeter Maydell 
698e51896b3SPeter Maydell #define DO_2OP_SCALAR(INSN, FN) \
699e51896b3SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2scalar *a)   \
700e51896b3SPeter Maydell     {                                                           \
701e51896b3SPeter Maydell         static MVEGenTwoOpScalarFn * const fns[] = {            \
702e51896b3SPeter Maydell             gen_helper_mve_##FN##b,                             \
703e51896b3SPeter Maydell             gen_helper_mve_##FN##h,                             \
704e51896b3SPeter Maydell             gen_helper_mve_##FN##w,                             \
705e51896b3SPeter Maydell             NULL,                                               \
706e51896b3SPeter Maydell         };                                                      \
707e51896b3SPeter Maydell         return do_2op_scalar(s, a, fns[a->size]);               \
708e51896b3SPeter Maydell     }
709e51896b3SPeter Maydell 
710e51896b3SPeter Maydell DO_2OP_SCALAR(VADD_scalar, vadd_scalar)
71191a358fdSPeter Maydell DO_2OP_SCALAR(VSUB_scalar, vsub_scalar)
71291a358fdSPeter Maydell DO_2OP_SCALAR(VMUL_scalar, vmul_scalar)
713644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_S_scalar, vhadds_scalar)
714644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_U_scalar, vhaddu_scalar)
715644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_S_scalar, vhsubs_scalar)
716644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_U_scalar, vhsubu_scalar)
71739f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_S_scalar, vqadds_scalar)
71839f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_U_scalar, vqaddu_scalar)
71939f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_S_scalar, vqsubs_scalar)
72039f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_U_scalar, vqsubu_scalar)
72166c05767SPeter Maydell DO_2OP_SCALAR(VQDMULH_scalar, vqdmulh_scalar)
72266c05767SPeter Maydell DO_2OP_SCALAR(VQRDMULH_scalar, vqrdmulh_scalar)
723b050543bSPeter Maydell DO_2OP_SCALAR(VBRSR, vbrsr)
724c69e34c6SPeter Maydell DO_2OP_SCALAR(VMLA, vmla)
7256b895bf8SPeter Maydell DO_2OP_SCALAR(VMLAS, vmlas)
7268be9a250SPeter Maydell DO_2OP_SCALAR(VQDMLAH, vqdmlah)
7278be9a250SPeter Maydell DO_2OP_SCALAR(VQRDMLAH, vqrdmlah)
7288be9a250SPeter Maydell DO_2OP_SCALAR(VQDMLASH, vqdmlash)
7298be9a250SPeter Maydell DO_2OP_SCALAR(VQRDMLASH, vqrdmlash)
730e51896b3SPeter Maydell 
731a8890353SPeter Maydell static bool trans_VQDMULLB_scalar(DisasContext *s, arg_2scalar *a)
732a8890353SPeter Maydell {
733a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
734a8890353SPeter Maydell         NULL,
735a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarh,
736a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarw,
737a8890353SPeter Maydell         NULL,
738a8890353SPeter Maydell     };
739a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
740a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
741a8890353SPeter Maydell         return false;
742a8890353SPeter Maydell     }
743a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
744a8890353SPeter Maydell }
745a8890353SPeter Maydell 
746a8890353SPeter Maydell static bool trans_VQDMULLT_scalar(DisasContext *s, arg_2scalar *a)
747a8890353SPeter Maydell {
748a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
749a8890353SPeter Maydell         NULL,
750a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarh,
751a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarw,
752a8890353SPeter Maydell         NULL,
753a8890353SPeter Maydell     };
754a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
755a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
756a8890353SPeter Maydell         return false;
757a8890353SPeter Maydell     }
758a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
759a8890353SPeter Maydell }
760a8890353SPeter Maydell 
7611d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a,
762640cdf20SPeter Maydell                              MVEGenLongDualAccOpFn *fn)
7631d2386f7SPeter Maydell {
7641d2386f7SPeter Maydell     TCGv_ptr qn, qm;
7651d2386f7SPeter Maydell     TCGv_i64 rda;
7661d2386f7SPeter Maydell     TCGv_i32 rdalo, rdahi;
7671d2386f7SPeter Maydell 
7681d2386f7SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
7691d2386f7SPeter Maydell         !mve_check_qreg_bank(s, a->qn | a->qm) ||
7701d2386f7SPeter Maydell         !fn) {
7711d2386f7SPeter Maydell         return false;
7721d2386f7SPeter Maydell     }
7731d2386f7SPeter Maydell     /*
7741d2386f7SPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
7751d2386f7SPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
7761d2386f7SPeter Maydell      */
7771d2386f7SPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
7781d2386f7SPeter Maydell         return false;
7791d2386f7SPeter Maydell     }
7801d2386f7SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
7811d2386f7SPeter Maydell         return true;
7821d2386f7SPeter Maydell     }
7831d2386f7SPeter Maydell 
7841d2386f7SPeter Maydell     qn = mve_qreg_ptr(a->qn);
7851d2386f7SPeter Maydell     qm = mve_qreg_ptr(a->qm);
7861d2386f7SPeter Maydell 
7871d2386f7SPeter Maydell     /*
7881d2386f7SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
7891d2386f7SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
7901d2386f7SPeter Maydell      * beat must start with the current rda value, not 0.
7911d2386f7SPeter Maydell      */
7921d2386f7SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
7931d2386f7SPeter Maydell         rda = tcg_temp_new_i64();
7941d2386f7SPeter Maydell         rdalo = load_reg(s, a->rdalo);
7951d2386f7SPeter Maydell         rdahi = load_reg(s, a->rdahi);
7961d2386f7SPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
7971d2386f7SPeter Maydell         tcg_temp_free_i32(rdalo);
7981d2386f7SPeter Maydell         tcg_temp_free_i32(rdahi);
7991d2386f7SPeter Maydell     } else {
8001d2386f7SPeter Maydell         rda = tcg_const_i64(0);
8011d2386f7SPeter Maydell     }
8021d2386f7SPeter Maydell 
8031d2386f7SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
8041d2386f7SPeter Maydell     tcg_temp_free_ptr(qn);
8051d2386f7SPeter Maydell     tcg_temp_free_ptr(qm);
8061d2386f7SPeter Maydell 
8071d2386f7SPeter Maydell     rdalo = tcg_temp_new_i32();
8081d2386f7SPeter Maydell     rdahi = tcg_temp_new_i32();
8091d2386f7SPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
8101d2386f7SPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
8111d2386f7SPeter Maydell     store_reg(s, a->rdalo, rdalo);
8121d2386f7SPeter Maydell     store_reg(s, a->rdahi, rdahi);
8131d2386f7SPeter Maydell     tcg_temp_free_i64(rda);
8141d2386f7SPeter Maydell     mve_update_eci(s);
8151d2386f7SPeter Maydell     return true;
8161d2386f7SPeter Maydell }
8171d2386f7SPeter Maydell 
8181d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a)
8191d2386f7SPeter Maydell {
820640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
8211d2386f7SPeter Maydell         { NULL, NULL },
8221d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh },
8231d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw },
8241d2386f7SPeter Maydell         { NULL, NULL },
8251d2386f7SPeter Maydell     };
8261d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
8271d2386f7SPeter Maydell }
8281d2386f7SPeter Maydell 
8291d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a)
8301d2386f7SPeter Maydell {
831640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
8321d2386f7SPeter Maydell         { NULL, NULL },
8331d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuh, NULL },
8341d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuw, NULL },
8351d2386f7SPeter Maydell         { NULL, NULL },
8361d2386f7SPeter Maydell     };
8371d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
8381d2386f7SPeter Maydell }
839181cd971SPeter Maydell 
840181cd971SPeter Maydell static bool trans_VMLSLDAV(DisasContext *s, arg_vmlaldav *a)
841181cd971SPeter Maydell {
842640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
843181cd971SPeter Maydell         { NULL, NULL },
844181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh },
845181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw },
846181cd971SPeter Maydell         { NULL, NULL },
847181cd971SPeter Maydell     };
848181cd971SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
849181cd971SPeter Maydell }
85038548747SPeter Maydell 
85138548747SPeter Maydell static bool trans_VRMLALDAVH_S(DisasContext *s, arg_vmlaldav *a)
85238548747SPeter Maydell {
853640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
85438548747SPeter Maydell         gen_helper_mve_vrmlaldavhsw, gen_helper_mve_vrmlaldavhxsw,
85538548747SPeter Maydell     };
85638548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
85738548747SPeter Maydell }
85838548747SPeter Maydell 
85938548747SPeter Maydell static bool trans_VRMLALDAVH_U(DisasContext *s, arg_vmlaldav *a)
86038548747SPeter Maydell {
861640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
86238548747SPeter Maydell         gen_helper_mve_vrmlaldavhuw, NULL,
86338548747SPeter Maydell     };
86438548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
86538548747SPeter Maydell }
86638548747SPeter Maydell 
86738548747SPeter Maydell static bool trans_VRMLSLDAVH(DisasContext *s, arg_vmlaldav *a)
86838548747SPeter Maydell {
869640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
87038548747SPeter Maydell         gen_helper_mve_vrmlsldavhsw, gen_helper_mve_vrmlsldavhxsw,
87138548747SPeter Maydell     };
87238548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
87338548747SPeter Maydell }
874387debdbSPeter Maydell 
875f0ffff51SPeter Maydell static bool do_dual_acc(DisasContext *s, arg_vmladav *a, MVEGenDualAccOpFn *fn)
876f0ffff51SPeter Maydell {
877f0ffff51SPeter Maydell     TCGv_ptr qn, qm;
878f0ffff51SPeter Maydell     TCGv_i32 rda;
879f0ffff51SPeter Maydell 
880f0ffff51SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
881f0ffff51SPeter Maydell         !mve_check_qreg_bank(s, a->qn) ||
882f0ffff51SPeter Maydell         !fn) {
883f0ffff51SPeter Maydell         return false;
884f0ffff51SPeter Maydell     }
885f0ffff51SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
886f0ffff51SPeter Maydell         return true;
887f0ffff51SPeter Maydell     }
888f0ffff51SPeter Maydell 
889f0ffff51SPeter Maydell     qn = mve_qreg_ptr(a->qn);
890f0ffff51SPeter Maydell     qm = mve_qreg_ptr(a->qm);
891f0ffff51SPeter Maydell 
892f0ffff51SPeter Maydell     /*
893f0ffff51SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
894f0ffff51SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
895f0ffff51SPeter Maydell      * beat must start with the current rda value, not 0.
896f0ffff51SPeter Maydell      */
897f0ffff51SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
898f0ffff51SPeter Maydell         rda = load_reg(s, a->rda);
899f0ffff51SPeter Maydell     } else {
900f0ffff51SPeter Maydell         rda = tcg_const_i32(0);
901f0ffff51SPeter Maydell     }
902f0ffff51SPeter Maydell 
903f0ffff51SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
904f0ffff51SPeter Maydell     store_reg(s, a->rda, rda);
905f0ffff51SPeter Maydell     tcg_temp_free_ptr(qn);
906f0ffff51SPeter Maydell     tcg_temp_free_ptr(qm);
907f0ffff51SPeter Maydell 
908f0ffff51SPeter Maydell     mve_update_eci(s);
909f0ffff51SPeter Maydell     return true;
910f0ffff51SPeter Maydell }
911f0ffff51SPeter Maydell 
912f0ffff51SPeter Maydell #define DO_DUAL_ACC(INSN, FN)                                           \
913f0ffff51SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vmladav *a)           \
914f0ffff51SPeter Maydell     {                                                                   \
915f0ffff51SPeter Maydell         static MVEGenDualAccOpFn * const fns[4][2] = {                  \
916f0ffff51SPeter Maydell             { gen_helper_mve_##FN##b, gen_helper_mve_##FN##xb },        \
917f0ffff51SPeter Maydell             { gen_helper_mve_##FN##h, gen_helper_mve_##FN##xh },        \
918f0ffff51SPeter Maydell             { gen_helper_mve_##FN##w, gen_helper_mve_##FN##xw },        \
919f0ffff51SPeter Maydell             { NULL, NULL },                                             \
920f0ffff51SPeter Maydell         };                                                              \
921f0ffff51SPeter Maydell         return do_dual_acc(s, a, fns[a->size][a->x]);                   \
922f0ffff51SPeter Maydell     }
923f0ffff51SPeter Maydell 
924f0ffff51SPeter Maydell DO_DUAL_ACC(VMLADAV_S, vmladavs)
925f0ffff51SPeter Maydell DO_DUAL_ACC(VMLSDAV, vmlsdav)
926f0ffff51SPeter Maydell 
927f0ffff51SPeter Maydell static bool trans_VMLADAV_U(DisasContext *s, arg_vmladav *a)
928f0ffff51SPeter Maydell {
929f0ffff51SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
930f0ffff51SPeter Maydell         { gen_helper_mve_vmladavub, NULL },
931f0ffff51SPeter Maydell         { gen_helper_mve_vmladavuh, NULL },
932f0ffff51SPeter Maydell         { gen_helper_mve_vmladavuw, NULL },
933f0ffff51SPeter Maydell         { NULL, NULL },
934f0ffff51SPeter Maydell     };
935f0ffff51SPeter Maydell     return do_dual_acc(s, a, fns[a->size][a->x]);
936f0ffff51SPeter Maydell }
937f0ffff51SPeter Maydell 
93855251786SPeter Maydell static void gen_vpst(DisasContext *s, uint32_t mask)
939387debdbSPeter Maydell {
940387debdbSPeter Maydell     /*
941387debdbSPeter Maydell      * Set the VPR mask fields. We take advantage of MASK01 and MASK23
942387debdbSPeter Maydell      * being adjacent fields in the register.
943387debdbSPeter Maydell      *
94455251786SPeter Maydell      * Updating the masks is not predicated, but it is subject to beat-wise
945387debdbSPeter Maydell      * execution, and the mask is updated on the odd-numbered beats.
946387debdbSPeter Maydell      * So if PSR.ECI says we should skip beat 1, we mustn't update the
947387debdbSPeter Maydell      * 01 mask field.
948387debdbSPeter Maydell      */
94955251786SPeter Maydell     TCGv_i32 vpr = load_cpu_field(v7m.vpr);
950387debdbSPeter Maydell     switch (s->eci) {
951387debdbSPeter Maydell     case ECI_NONE:
952387debdbSPeter Maydell     case ECI_A0:
953387debdbSPeter Maydell         /* Update both 01 and 23 fields */
954387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
95555251786SPeter Maydell                             tcg_constant_i32(mask | (mask << 4)),
956387debdbSPeter Maydell                             R_V7M_VPR_MASK01_SHIFT,
957387debdbSPeter Maydell                             R_V7M_VPR_MASK01_LENGTH + R_V7M_VPR_MASK23_LENGTH);
958387debdbSPeter Maydell         break;
959387debdbSPeter Maydell     case ECI_A0A1:
960387debdbSPeter Maydell     case ECI_A0A1A2:
961387debdbSPeter Maydell     case ECI_A0A1A2B0:
962387debdbSPeter Maydell         /* Update only the 23 mask field */
963387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
96455251786SPeter Maydell                             tcg_constant_i32(mask),
965387debdbSPeter Maydell                             R_V7M_VPR_MASK23_SHIFT, R_V7M_VPR_MASK23_LENGTH);
966387debdbSPeter Maydell         break;
967387debdbSPeter Maydell     default:
968387debdbSPeter Maydell         g_assert_not_reached();
969387debdbSPeter Maydell     }
970387debdbSPeter Maydell     store_cpu_field(vpr, v7m.vpr);
97155251786SPeter Maydell }
97255251786SPeter Maydell 
97355251786SPeter Maydell static bool trans_VPST(DisasContext *s, arg_VPST *a)
97455251786SPeter Maydell {
97555251786SPeter Maydell     /* mask == 0 is a "related encoding" */
97655251786SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !a->mask) {
97755251786SPeter Maydell         return false;
97855251786SPeter Maydell     }
97955251786SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
98055251786SPeter Maydell         return true;
98155251786SPeter Maydell     }
98255251786SPeter Maydell     gen_vpst(s, a->mask);
983387debdbSPeter Maydell     mve_update_and_store_eci(s);
984387debdbSPeter Maydell     return true;
985387debdbSPeter Maydell }
9866f060a63SPeter Maydell 
987fea3958fSPeter Maydell static bool trans_VPNOT(DisasContext *s, arg_VPNOT *a)
988fea3958fSPeter Maydell {
989fea3958fSPeter Maydell     /*
990fea3958fSPeter Maydell      * Invert the predicate in VPR.P0. We have call out to
991fea3958fSPeter Maydell      * a helper because this insn itself is beatwise and can
992fea3958fSPeter Maydell      * be predicated.
993fea3958fSPeter Maydell      */
994fea3958fSPeter Maydell     if (!dc_isar_feature(aa32_mve, s)) {
995fea3958fSPeter Maydell         return false;
996fea3958fSPeter Maydell     }
997fea3958fSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
998fea3958fSPeter Maydell         return true;
999fea3958fSPeter Maydell     }
1000fea3958fSPeter Maydell 
1001fea3958fSPeter Maydell     gen_helper_mve_vpnot(cpu_env);
1002fea3958fSPeter Maydell     mve_update_eci(s);
1003fea3958fSPeter Maydell     return true;
1004fea3958fSPeter Maydell }
1005fea3958fSPeter Maydell 
10066f060a63SPeter Maydell static bool trans_VADDV(DisasContext *s, arg_VADDV *a)
10076f060a63SPeter Maydell {
10086f060a63SPeter Maydell     /* VADDV: vector add across vector */
10096f060a63SPeter Maydell     static MVEGenVADDVFn * const fns[4][2] = {
10106f060a63SPeter Maydell         { gen_helper_mve_vaddvsb, gen_helper_mve_vaddvub },
10116f060a63SPeter Maydell         { gen_helper_mve_vaddvsh, gen_helper_mve_vaddvuh },
10126f060a63SPeter Maydell         { gen_helper_mve_vaddvsw, gen_helper_mve_vaddvuw },
10136f060a63SPeter Maydell         { NULL, NULL }
10146f060a63SPeter Maydell     };
10156f060a63SPeter Maydell     TCGv_ptr qm;
10166f060a63SPeter Maydell     TCGv_i32 rda;
10176f060a63SPeter Maydell 
10186f060a63SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
10196f060a63SPeter Maydell         a->size == 3) {
10206f060a63SPeter Maydell         return false;
10216f060a63SPeter Maydell     }
10226f060a63SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
10236f060a63SPeter Maydell         return true;
10246f060a63SPeter Maydell     }
10256f060a63SPeter Maydell 
10266f060a63SPeter Maydell     /*
10276f060a63SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
10286f060a63SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
10296f060a63SPeter Maydell      * beat must start with the current value of Rda, not zero.
10306f060a63SPeter Maydell      */
10316f060a63SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
10326f060a63SPeter Maydell         /* Accumulate input from Rda */
10336f060a63SPeter Maydell         rda = load_reg(s, a->rda);
10346f060a63SPeter Maydell     } else {
10356f060a63SPeter Maydell         /* Accumulate starting at zero */
10366f060a63SPeter Maydell         rda = tcg_const_i32(0);
10376f060a63SPeter Maydell     }
10386f060a63SPeter Maydell 
10396f060a63SPeter Maydell     qm = mve_qreg_ptr(a->qm);
10406f060a63SPeter Maydell     fns[a->size][a->u](rda, cpu_env, qm, rda);
10416f060a63SPeter Maydell     store_reg(s, a->rda, rda);
10426f060a63SPeter Maydell     tcg_temp_free_ptr(qm);
10436f060a63SPeter Maydell 
10446f060a63SPeter Maydell     mve_update_eci(s);
10456f060a63SPeter Maydell     return true;
10466f060a63SPeter Maydell }
1047eab84139SPeter Maydell 
1048d43ebd9dSPeter Maydell static bool trans_VADDLV(DisasContext *s, arg_VADDLV *a)
1049d43ebd9dSPeter Maydell {
1050d43ebd9dSPeter Maydell     /*
1051d43ebd9dSPeter Maydell      * Vector Add Long Across Vector: accumulate the 32-bit
1052d43ebd9dSPeter Maydell      * elements of the vector into a 64-bit result stored in
1053d43ebd9dSPeter Maydell      * a pair of general-purpose registers.
1054d43ebd9dSPeter Maydell      * No need to check Qm's bank: it is only 3 bits in decode.
1055d43ebd9dSPeter Maydell      */
1056d43ebd9dSPeter Maydell     TCGv_ptr qm;
1057d43ebd9dSPeter Maydell     TCGv_i64 rda;
1058d43ebd9dSPeter Maydell     TCGv_i32 rdalo, rdahi;
1059d43ebd9dSPeter Maydell 
1060d43ebd9dSPeter Maydell     if (!dc_isar_feature(aa32_mve, s)) {
1061d43ebd9dSPeter Maydell         return false;
1062d43ebd9dSPeter Maydell     }
1063d43ebd9dSPeter Maydell     /*
1064d43ebd9dSPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
1065d43ebd9dSPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
1066d43ebd9dSPeter Maydell      */
1067d43ebd9dSPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
1068d43ebd9dSPeter Maydell         return false;
1069d43ebd9dSPeter Maydell     }
1070d43ebd9dSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1071d43ebd9dSPeter Maydell         return true;
1072d43ebd9dSPeter Maydell     }
1073d43ebd9dSPeter Maydell 
1074d43ebd9dSPeter Maydell     /*
1075d43ebd9dSPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
1076d43ebd9dSPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
1077d43ebd9dSPeter Maydell      * beat must start with the current value of RdaHi:RdaLo, not zero.
1078d43ebd9dSPeter Maydell      */
1079d43ebd9dSPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
1080d43ebd9dSPeter Maydell         /* Accumulate input from RdaHi:RdaLo */
1081d43ebd9dSPeter Maydell         rda = tcg_temp_new_i64();
1082d43ebd9dSPeter Maydell         rdalo = load_reg(s, a->rdalo);
1083d43ebd9dSPeter Maydell         rdahi = load_reg(s, a->rdahi);
1084d43ebd9dSPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
1085d43ebd9dSPeter Maydell         tcg_temp_free_i32(rdalo);
1086d43ebd9dSPeter Maydell         tcg_temp_free_i32(rdahi);
1087d43ebd9dSPeter Maydell     } else {
1088d43ebd9dSPeter Maydell         /* Accumulate starting at zero */
1089d43ebd9dSPeter Maydell         rda = tcg_const_i64(0);
1090d43ebd9dSPeter Maydell     }
1091d43ebd9dSPeter Maydell 
1092d43ebd9dSPeter Maydell     qm = mve_qreg_ptr(a->qm);
1093d43ebd9dSPeter Maydell     if (a->u) {
1094d43ebd9dSPeter Maydell         gen_helper_mve_vaddlv_u(rda, cpu_env, qm, rda);
1095d43ebd9dSPeter Maydell     } else {
1096d43ebd9dSPeter Maydell         gen_helper_mve_vaddlv_s(rda, cpu_env, qm, rda);
1097d43ebd9dSPeter Maydell     }
1098d43ebd9dSPeter Maydell     tcg_temp_free_ptr(qm);
1099d43ebd9dSPeter Maydell 
1100d43ebd9dSPeter Maydell     rdalo = tcg_temp_new_i32();
1101d43ebd9dSPeter Maydell     rdahi = tcg_temp_new_i32();
1102d43ebd9dSPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
1103d43ebd9dSPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
1104d43ebd9dSPeter Maydell     store_reg(s, a->rdalo, rdalo);
1105d43ebd9dSPeter Maydell     store_reg(s, a->rdahi, rdahi);
1106d43ebd9dSPeter Maydell     tcg_temp_free_i64(rda);
1107d43ebd9dSPeter Maydell     mve_update_eci(s);
1108d43ebd9dSPeter Maydell     return true;
1109d43ebd9dSPeter Maydell }
1110d43ebd9dSPeter Maydell 
1111eab84139SPeter Maydell static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
1112eab84139SPeter Maydell {
1113eab84139SPeter Maydell     TCGv_ptr qd;
1114eab84139SPeter Maydell     uint64_t imm;
1115eab84139SPeter Maydell 
1116eab84139SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
1117eab84139SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
1118eab84139SPeter Maydell         !fn) {
1119eab84139SPeter Maydell         return false;
1120eab84139SPeter Maydell     }
1121eab84139SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1122eab84139SPeter Maydell         return true;
1123eab84139SPeter Maydell     }
1124eab84139SPeter Maydell 
1125eab84139SPeter Maydell     imm = asimd_imm_const(a->imm, a->cmode, a->op);
1126eab84139SPeter Maydell 
1127eab84139SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1128eab84139SPeter Maydell     fn(cpu_env, qd, tcg_constant_i64(imm));
1129eab84139SPeter Maydell     tcg_temp_free_ptr(qd);
1130eab84139SPeter Maydell     mve_update_eci(s);
1131eab84139SPeter Maydell     return true;
1132eab84139SPeter Maydell }
1133eab84139SPeter Maydell 
1134eab84139SPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
1135eab84139SPeter Maydell {
1136eab84139SPeter Maydell     /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
1137eab84139SPeter Maydell     MVEGenOneOpImmFn *fn;
1138eab84139SPeter Maydell 
1139eab84139SPeter Maydell     if ((a->cmode & 1) && a->cmode < 12) {
1140eab84139SPeter Maydell         if (a->op) {
1141eab84139SPeter Maydell             /*
1142eab84139SPeter Maydell              * For op=1, the immediate will be inverted by asimd_imm_const(),
1143eab84139SPeter Maydell              * so the VBIC becomes a logical AND operation.
1144eab84139SPeter Maydell              */
1145eab84139SPeter Maydell             fn = gen_helper_mve_vandi;
1146eab84139SPeter Maydell         } else {
1147eab84139SPeter Maydell             fn = gen_helper_mve_vorri;
1148eab84139SPeter Maydell         }
1149eab84139SPeter Maydell     } else {
1150eab84139SPeter Maydell         /* There is one unallocated cmode/op combination in this space */
1151eab84139SPeter Maydell         if (a->cmode == 15 && a->op == 1) {
1152eab84139SPeter Maydell             return false;
1153eab84139SPeter Maydell         }
1154eab84139SPeter Maydell         /* asimd_imm_const() sorts out VMVNI vs VMOVI for us */
1155eab84139SPeter Maydell         fn = gen_helper_mve_vmovi;
1156eab84139SPeter Maydell     }
1157eab84139SPeter Maydell     return do_1imm(s, a, fn);
1158eab84139SPeter Maydell }
1159f9ed6174SPeter Maydell 
1160f9ed6174SPeter Maydell static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
1161f9ed6174SPeter Maydell                       bool negateshift)
1162f9ed6174SPeter Maydell {
1163f9ed6174SPeter Maydell     TCGv_ptr qd, qm;
1164f9ed6174SPeter Maydell     int shift = a->shift;
1165f9ed6174SPeter Maydell 
1166f9ed6174SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
1167f9ed6174SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
1168f9ed6174SPeter Maydell         !fn) {
1169f9ed6174SPeter Maydell         return false;
1170f9ed6174SPeter Maydell     }
1171f9ed6174SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1172f9ed6174SPeter Maydell         return true;
1173f9ed6174SPeter Maydell     }
1174f9ed6174SPeter Maydell 
1175f9ed6174SPeter Maydell     /*
1176f9ed6174SPeter Maydell      * When we handle a right shift insn using a left-shift helper
1177f9ed6174SPeter Maydell      * which permits a negative shift count to indicate a right-shift,
1178f9ed6174SPeter Maydell      * we must negate the shift count.
1179f9ed6174SPeter Maydell      */
1180f9ed6174SPeter Maydell     if (negateshift) {
1181f9ed6174SPeter Maydell         shift = -shift;
1182f9ed6174SPeter Maydell     }
1183f9ed6174SPeter Maydell 
1184f9ed6174SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1185f9ed6174SPeter Maydell     qm = mve_qreg_ptr(a->qm);
1186f9ed6174SPeter Maydell     fn(cpu_env, qd, qm, tcg_constant_i32(shift));
1187f9ed6174SPeter Maydell     tcg_temp_free_ptr(qd);
1188f9ed6174SPeter Maydell     tcg_temp_free_ptr(qm);
1189f9ed6174SPeter Maydell     mve_update_eci(s);
1190f9ed6174SPeter Maydell     return true;
1191f9ed6174SPeter Maydell }
1192f9ed6174SPeter Maydell 
1193f9ed6174SPeter Maydell #define DO_2SHIFT(INSN, FN, NEGATESHIFT)                         \
1194f9ed6174SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1195f9ed6174SPeter Maydell     {                                                           \
1196f9ed6174SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1197f9ed6174SPeter Maydell             gen_helper_mve_##FN##b,                             \
1198f9ed6174SPeter Maydell             gen_helper_mve_##FN##h,                             \
1199f9ed6174SPeter Maydell             gen_helper_mve_##FN##w,                             \
1200f9ed6174SPeter Maydell             NULL,                                               \
1201f9ed6174SPeter Maydell         };                                                      \
1202f9ed6174SPeter Maydell         return do_2shift(s, a, fns[a->size], NEGATESHIFT);      \
1203f9ed6174SPeter Maydell     }
1204f9ed6174SPeter Maydell 
1205f9ed6174SPeter Maydell DO_2SHIFT(VSHLI, vshli_u, false)
1206f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_S, vqshli_s, false)
1207f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_U, vqshli_u, false)
1208f9ed6174SPeter Maydell DO_2SHIFT(VQSHLUI, vqshlui_s, false)
12093394116fSPeter Maydell /* These right shifts use a left-shift helper with negated shift count */
12103394116fSPeter Maydell DO_2SHIFT(VSHRI_S, vshli_s, true)
12113394116fSPeter Maydell DO_2SHIFT(VSHRI_U, vshli_u, true)
12123394116fSPeter Maydell DO_2SHIFT(VRSHRI_S, vrshli_s, true)
12133394116fSPeter Maydell DO_2SHIFT(VRSHRI_U, vrshli_u, true)
1214c2262707SPeter Maydell 
1215a78b25faSPeter Maydell DO_2SHIFT(VSRI, vsri, false)
1216a78b25faSPeter Maydell DO_2SHIFT(VSLI, vsli, false)
1217a78b25faSPeter Maydell 
12181b15a97dSPeter Maydell static bool do_2shift_scalar(DisasContext *s, arg_shl_scalar *a,
12191b15a97dSPeter Maydell                              MVEGenTwoOpShiftFn *fn)
12201b15a97dSPeter Maydell {
12211b15a97dSPeter Maydell     TCGv_ptr qda;
12221b15a97dSPeter Maydell     TCGv_i32 rm;
12231b15a97dSPeter Maydell 
12241b15a97dSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
12251b15a97dSPeter Maydell         !mve_check_qreg_bank(s, a->qda) ||
12261b15a97dSPeter Maydell         a->rm == 13 || a->rm == 15 || !fn) {
12271b15a97dSPeter Maydell         /* Rm cases are UNPREDICTABLE */
12281b15a97dSPeter Maydell         return false;
12291b15a97dSPeter Maydell     }
12301b15a97dSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
12311b15a97dSPeter Maydell         return true;
12321b15a97dSPeter Maydell     }
12331b15a97dSPeter Maydell 
12341b15a97dSPeter Maydell     qda = mve_qreg_ptr(a->qda);
12351b15a97dSPeter Maydell     rm = load_reg(s, a->rm);
12361b15a97dSPeter Maydell     fn(cpu_env, qda, qda, rm);
12371b15a97dSPeter Maydell     tcg_temp_free_ptr(qda);
12381b15a97dSPeter Maydell     tcg_temp_free_i32(rm);
12391b15a97dSPeter Maydell     mve_update_eci(s);
12401b15a97dSPeter Maydell     return true;
12411b15a97dSPeter Maydell }
12421b15a97dSPeter Maydell 
12431b15a97dSPeter Maydell #define DO_2SHIFT_SCALAR(INSN, FN)                                      \
12441b15a97dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_shl_scalar *a)        \
12451b15a97dSPeter Maydell     {                                                                   \
12461b15a97dSPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {                     \
12471b15a97dSPeter Maydell             gen_helper_mve_##FN##b,                                     \
12481b15a97dSPeter Maydell             gen_helper_mve_##FN##h,                                     \
12491b15a97dSPeter Maydell             gen_helper_mve_##FN##w,                                     \
12501b15a97dSPeter Maydell             NULL,                                                       \
12511b15a97dSPeter Maydell         };                                                              \
12521b15a97dSPeter Maydell         return do_2shift_scalar(s, a, fns[a->size]);                    \
12531b15a97dSPeter Maydell     }
12541b15a97dSPeter Maydell 
12551b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VSHL_S_scalar, vshli_s)
12561b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VSHL_U_scalar, vshli_u)
12571b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VRSHL_S_scalar, vrshli_s)
12581b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VRSHL_U_scalar, vrshli_u)
12591b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQSHL_S_scalar, vqshli_s)
12601b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQSHL_U_scalar, vqshli_u)
12611b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQRSHL_S_scalar, vqrshli_s)
12621b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQRSHL_U_scalar, vqrshli_u)
12631b15a97dSPeter Maydell 
1264c2262707SPeter Maydell #define DO_VSHLL(INSN, FN)                                      \
1265c2262707SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1266c2262707SPeter Maydell     {                                                           \
1267c2262707SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1268c2262707SPeter Maydell             gen_helper_mve_##FN##b,                             \
1269c2262707SPeter Maydell             gen_helper_mve_##FN##h,                             \
1270c2262707SPeter Maydell         };                                                      \
1271c2262707SPeter Maydell         return do_2shift(s, a, fns[a->size], false);            \
1272c2262707SPeter Maydell     }
1273c2262707SPeter Maydell 
1274c2262707SPeter Maydell DO_VSHLL(VSHLL_BS, vshllbs)
1275c2262707SPeter Maydell DO_VSHLL(VSHLL_BU, vshllbu)
1276c2262707SPeter Maydell DO_VSHLL(VSHLL_TS, vshllts)
1277c2262707SPeter Maydell DO_VSHLL(VSHLL_TU, vshlltu)
1278162e2655SPeter Maydell 
1279162e2655SPeter Maydell #define DO_2SHIFT_N(INSN, FN)                                   \
1280162e2655SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1281162e2655SPeter Maydell     {                                                           \
1282162e2655SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1283162e2655SPeter Maydell             gen_helper_mve_##FN##b,                             \
1284162e2655SPeter Maydell             gen_helper_mve_##FN##h,                             \
1285162e2655SPeter Maydell         };                                                      \
1286162e2655SPeter Maydell         return do_2shift(s, a, fns[a->size], false);            \
1287162e2655SPeter Maydell     }
1288162e2655SPeter Maydell 
1289162e2655SPeter Maydell DO_2SHIFT_N(VSHRNB, vshrnb)
1290162e2655SPeter Maydell DO_2SHIFT_N(VSHRNT, vshrnt)
1291162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNB, vrshrnb)
1292162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNT, vrshrnt)
1293d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_S, vqshrnb_s)
1294d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_S, vqshrnt_s)
1295d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_U, vqshrnb_u)
1296d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_U, vqshrnt_u)
1297d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNB, vqshrunb)
1298d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNT, vqshrunt)
1299d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_S, vqrshrnb_s)
1300d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_S, vqrshrnt_s)
1301d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_U, vqrshrnb_u)
1302d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_U, vqrshrnt_u)
1303d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNB, vqrshrunb)
1304d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNT, vqrshrunt)
13052e6a4ce0SPeter Maydell 
13062e6a4ce0SPeter Maydell static bool trans_VSHLC(DisasContext *s, arg_VSHLC *a)
13072e6a4ce0SPeter Maydell {
13082e6a4ce0SPeter Maydell     /*
13092e6a4ce0SPeter Maydell      * Whole Vector Left Shift with Carry. The carry is taken
13102e6a4ce0SPeter Maydell      * from a general purpose register and written back there.
13112e6a4ce0SPeter Maydell      * An imm of 0 means "shift by 32".
13122e6a4ce0SPeter Maydell      */
13132e6a4ce0SPeter Maydell     TCGv_ptr qd;
13142e6a4ce0SPeter Maydell     TCGv_i32 rdm;
13152e6a4ce0SPeter Maydell 
13162e6a4ce0SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
13172e6a4ce0SPeter Maydell         return false;
13182e6a4ce0SPeter Maydell     }
13192e6a4ce0SPeter Maydell     if (a->rdm == 13 || a->rdm == 15) {
13202e6a4ce0SPeter Maydell         /* CONSTRAINED UNPREDICTABLE: we UNDEF */
13212e6a4ce0SPeter Maydell         return false;
13222e6a4ce0SPeter Maydell     }
13232e6a4ce0SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
13242e6a4ce0SPeter Maydell         return true;
13252e6a4ce0SPeter Maydell     }
13262e6a4ce0SPeter Maydell 
13272e6a4ce0SPeter Maydell     qd = mve_qreg_ptr(a->qd);
13282e6a4ce0SPeter Maydell     rdm = load_reg(s, a->rdm);
13292e6a4ce0SPeter Maydell     gen_helper_mve_vshlc(rdm, cpu_env, qd, rdm, tcg_constant_i32(a->imm));
13302e6a4ce0SPeter Maydell     store_reg(s, a->rdm, rdm);
13312e6a4ce0SPeter Maydell     tcg_temp_free_ptr(qd);
13322e6a4ce0SPeter Maydell     mve_update_eci(s);
13332e6a4ce0SPeter Maydell     return true;
13342e6a4ce0SPeter Maydell }
1335395b92d5SPeter Maydell 
1336395b92d5SPeter Maydell static bool do_vidup(DisasContext *s, arg_vidup *a, MVEGenVIDUPFn *fn)
1337395b92d5SPeter Maydell {
1338395b92d5SPeter Maydell     TCGv_ptr qd;
1339395b92d5SPeter Maydell     TCGv_i32 rn;
1340395b92d5SPeter Maydell 
1341395b92d5SPeter Maydell     /*
1342395b92d5SPeter Maydell      * Vector increment/decrement with wrap and duplicate (VIDUP, VDDUP).
1343395b92d5SPeter Maydell      * This fills the vector with elements of successively increasing
1344395b92d5SPeter Maydell      * or decreasing values, starting from Rn.
1345395b92d5SPeter Maydell      */
1346395b92d5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
1347395b92d5SPeter Maydell         return false;
1348395b92d5SPeter Maydell     }
1349395b92d5SPeter Maydell     if (a->size == MO_64) {
1350395b92d5SPeter Maydell         /* size 0b11 is another encoding */
1351395b92d5SPeter Maydell         return false;
1352395b92d5SPeter Maydell     }
1353395b92d5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1354395b92d5SPeter Maydell         return true;
1355395b92d5SPeter Maydell     }
1356395b92d5SPeter Maydell 
1357395b92d5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1358395b92d5SPeter Maydell     rn = load_reg(s, a->rn);
1359395b92d5SPeter Maydell     fn(rn, cpu_env, qd, rn, tcg_constant_i32(a->imm));
1360395b92d5SPeter Maydell     store_reg(s, a->rn, rn);
1361395b92d5SPeter Maydell     tcg_temp_free_ptr(qd);
1362395b92d5SPeter Maydell     mve_update_eci(s);
1363395b92d5SPeter Maydell     return true;
1364395b92d5SPeter Maydell }
1365395b92d5SPeter Maydell 
1366395b92d5SPeter Maydell static bool do_viwdup(DisasContext *s, arg_viwdup *a, MVEGenVIWDUPFn *fn)
1367395b92d5SPeter Maydell {
1368395b92d5SPeter Maydell     TCGv_ptr qd;
1369395b92d5SPeter Maydell     TCGv_i32 rn, rm;
1370395b92d5SPeter Maydell 
1371395b92d5SPeter Maydell     /*
1372395b92d5SPeter Maydell      * Vector increment/decrement with wrap and duplicate (VIWDUp, VDWDUP)
1373395b92d5SPeter Maydell      * This fills the vector with elements of successively increasing
1374395b92d5SPeter Maydell      * or decreasing values, starting from Rn. Rm specifies a point where
1375395b92d5SPeter Maydell      * the count wraps back around to 0. The updated offset is written back
1376395b92d5SPeter Maydell      * to Rn.
1377395b92d5SPeter Maydell      */
1378395b92d5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
1379395b92d5SPeter Maydell         return false;
1380395b92d5SPeter Maydell     }
1381395b92d5SPeter Maydell     if (!fn || a->rm == 13 || a->rm == 15) {
1382395b92d5SPeter Maydell         /*
1383395b92d5SPeter Maydell          * size 0b11 is another encoding; Rm == 13 is UNPREDICTABLE;
1384395b92d5SPeter Maydell          * Rm == 13 is VIWDUP, VDWDUP.
1385395b92d5SPeter Maydell          */
1386395b92d5SPeter Maydell         return false;
1387395b92d5SPeter Maydell     }
1388395b92d5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1389395b92d5SPeter Maydell         return true;
1390395b92d5SPeter Maydell     }
1391395b92d5SPeter Maydell 
1392395b92d5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1393395b92d5SPeter Maydell     rn = load_reg(s, a->rn);
1394395b92d5SPeter Maydell     rm = load_reg(s, a->rm);
1395395b92d5SPeter Maydell     fn(rn, cpu_env, qd, rn, rm, tcg_constant_i32(a->imm));
1396395b92d5SPeter Maydell     store_reg(s, a->rn, rn);
1397395b92d5SPeter Maydell     tcg_temp_free_ptr(qd);
1398395b92d5SPeter Maydell     tcg_temp_free_i32(rm);
1399395b92d5SPeter Maydell     mve_update_eci(s);
1400395b92d5SPeter Maydell     return true;
1401395b92d5SPeter Maydell }
1402395b92d5SPeter Maydell 
1403395b92d5SPeter Maydell static bool trans_VIDUP(DisasContext *s, arg_vidup *a)
1404395b92d5SPeter Maydell {
1405395b92d5SPeter Maydell     static MVEGenVIDUPFn * const fns[] = {
1406395b92d5SPeter Maydell         gen_helper_mve_vidupb,
1407395b92d5SPeter Maydell         gen_helper_mve_viduph,
1408395b92d5SPeter Maydell         gen_helper_mve_vidupw,
1409395b92d5SPeter Maydell         NULL,
1410395b92d5SPeter Maydell     };
1411395b92d5SPeter Maydell     return do_vidup(s, a, fns[a->size]);
1412395b92d5SPeter Maydell }
1413395b92d5SPeter Maydell 
1414395b92d5SPeter Maydell static bool trans_VDDUP(DisasContext *s, arg_vidup *a)
1415395b92d5SPeter Maydell {
1416395b92d5SPeter Maydell     static MVEGenVIDUPFn * const fns[] = {
1417395b92d5SPeter Maydell         gen_helper_mve_vidupb,
1418395b92d5SPeter Maydell         gen_helper_mve_viduph,
1419395b92d5SPeter Maydell         gen_helper_mve_vidupw,
1420395b92d5SPeter Maydell         NULL,
1421395b92d5SPeter Maydell     };
1422395b92d5SPeter Maydell     /* VDDUP is just like VIDUP but with a negative immediate */
1423395b92d5SPeter Maydell     a->imm = -a->imm;
1424395b92d5SPeter Maydell     return do_vidup(s, a, fns[a->size]);
1425395b92d5SPeter Maydell }
1426395b92d5SPeter Maydell 
1427395b92d5SPeter Maydell static bool trans_VIWDUP(DisasContext *s, arg_viwdup *a)
1428395b92d5SPeter Maydell {
1429395b92d5SPeter Maydell     static MVEGenVIWDUPFn * const fns[] = {
1430395b92d5SPeter Maydell         gen_helper_mve_viwdupb,
1431395b92d5SPeter Maydell         gen_helper_mve_viwduph,
1432395b92d5SPeter Maydell         gen_helper_mve_viwdupw,
1433395b92d5SPeter Maydell         NULL,
1434395b92d5SPeter Maydell     };
1435395b92d5SPeter Maydell     return do_viwdup(s, a, fns[a->size]);
1436395b92d5SPeter Maydell }
1437395b92d5SPeter Maydell 
1438395b92d5SPeter Maydell static bool trans_VDWDUP(DisasContext *s, arg_viwdup *a)
1439395b92d5SPeter Maydell {
1440395b92d5SPeter Maydell     static MVEGenVIWDUPFn * const fns[] = {
1441395b92d5SPeter Maydell         gen_helper_mve_vdwdupb,
1442395b92d5SPeter Maydell         gen_helper_mve_vdwduph,
1443395b92d5SPeter Maydell         gen_helper_mve_vdwdupw,
1444395b92d5SPeter Maydell         NULL,
1445395b92d5SPeter Maydell     };
1446395b92d5SPeter Maydell     return do_viwdup(s, a, fns[a->size]);
1447395b92d5SPeter Maydell }
1448eff5d9a9SPeter Maydell 
1449eff5d9a9SPeter Maydell static bool do_vcmp(DisasContext *s, arg_vcmp *a, MVEGenCmpFn *fn)
1450eff5d9a9SPeter Maydell {
1451eff5d9a9SPeter Maydell     TCGv_ptr qn, qm;
1452eff5d9a9SPeter Maydell 
1453eff5d9a9SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qm) ||
1454eff5d9a9SPeter Maydell         !fn) {
1455eff5d9a9SPeter Maydell         return false;
1456eff5d9a9SPeter Maydell     }
1457eff5d9a9SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1458eff5d9a9SPeter Maydell         return true;
1459eff5d9a9SPeter Maydell     }
1460eff5d9a9SPeter Maydell 
1461eff5d9a9SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1462eff5d9a9SPeter Maydell     qm = mve_qreg_ptr(a->qm);
1463eff5d9a9SPeter Maydell     fn(cpu_env, qn, qm);
1464eff5d9a9SPeter Maydell     tcg_temp_free_ptr(qn);
1465eff5d9a9SPeter Maydell     tcg_temp_free_ptr(qm);
1466eff5d9a9SPeter Maydell     if (a->mask) {
1467eff5d9a9SPeter Maydell         /* VPT */
1468eff5d9a9SPeter Maydell         gen_vpst(s, a->mask);
1469eff5d9a9SPeter Maydell     }
1470eff5d9a9SPeter Maydell     mve_update_eci(s);
1471eff5d9a9SPeter Maydell     return true;
1472eff5d9a9SPeter Maydell }
1473eff5d9a9SPeter Maydell 
1474cce81873SPeter Maydell static bool do_vcmp_scalar(DisasContext *s, arg_vcmp_scalar *a,
1475cce81873SPeter Maydell                            MVEGenScalarCmpFn *fn)
1476cce81873SPeter Maydell {
1477cce81873SPeter Maydell     TCGv_ptr qn;
1478cce81873SPeter Maydell     TCGv_i32 rm;
1479cce81873SPeter Maydell 
1480cce81873SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !fn || a->rm == 13) {
1481cce81873SPeter Maydell         return false;
1482cce81873SPeter Maydell     }
1483cce81873SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1484cce81873SPeter Maydell         return true;
1485cce81873SPeter Maydell     }
1486cce81873SPeter Maydell 
1487cce81873SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1488cce81873SPeter Maydell     if (a->rm == 15) {
1489cce81873SPeter Maydell         /* Encoding Rm=0b1111 means "constant zero" */
1490cce81873SPeter Maydell         rm = tcg_constant_i32(0);
1491cce81873SPeter Maydell     } else {
1492cce81873SPeter Maydell         rm = load_reg(s, a->rm);
1493cce81873SPeter Maydell     }
1494cce81873SPeter Maydell     fn(cpu_env, qn, rm);
1495cce81873SPeter Maydell     tcg_temp_free_ptr(qn);
1496cce81873SPeter Maydell     tcg_temp_free_i32(rm);
1497cce81873SPeter Maydell     if (a->mask) {
1498cce81873SPeter Maydell         /* VPT */
1499cce81873SPeter Maydell         gen_vpst(s, a->mask);
1500cce81873SPeter Maydell     }
1501cce81873SPeter Maydell     mve_update_eci(s);
1502cce81873SPeter Maydell     return true;
1503cce81873SPeter Maydell }
1504cce81873SPeter Maydell 
1505eff5d9a9SPeter Maydell #define DO_VCMP(INSN, FN)                                       \
1506eff5d9a9SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vcmp *a)      \
1507eff5d9a9SPeter Maydell     {                                                           \
1508eff5d9a9SPeter Maydell         static MVEGenCmpFn * const fns[] = {                    \
1509eff5d9a9SPeter Maydell             gen_helper_mve_##FN##b,                             \
1510eff5d9a9SPeter Maydell             gen_helper_mve_##FN##h,                             \
1511eff5d9a9SPeter Maydell             gen_helper_mve_##FN##w,                             \
1512eff5d9a9SPeter Maydell             NULL,                                               \
1513eff5d9a9SPeter Maydell         };                                                      \
1514eff5d9a9SPeter Maydell         return do_vcmp(s, a, fns[a->size]);                     \
1515cce81873SPeter Maydell     }                                                           \
1516cce81873SPeter Maydell     static bool trans_##INSN##_scalar(DisasContext *s,          \
1517cce81873SPeter Maydell                                       arg_vcmp_scalar *a)       \
1518cce81873SPeter Maydell     {                                                           \
1519cce81873SPeter Maydell         static MVEGenScalarCmpFn * const fns[] = {              \
1520cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarb,                      \
1521cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarh,                      \
1522cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarw,                      \
1523cce81873SPeter Maydell             NULL,                                               \
1524cce81873SPeter Maydell         };                                                      \
1525cce81873SPeter Maydell         return do_vcmp_scalar(s, a, fns[a->size]);              \
1526eff5d9a9SPeter Maydell     }
1527eff5d9a9SPeter Maydell 
1528eff5d9a9SPeter Maydell DO_VCMP(VCMPEQ, vcmpeq)
1529eff5d9a9SPeter Maydell DO_VCMP(VCMPNE, vcmpne)
1530eff5d9a9SPeter Maydell DO_VCMP(VCMPCS, vcmpcs)
1531eff5d9a9SPeter Maydell DO_VCMP(VCMPHI, vcmphi)
1532eff5d9a9SPeter Maydell DO_VCMP(VCMPGE, vcmpge)
1533eff5d9a9SPeter Maydell DO_VCMP(VCMPLT, vcmplt)
1534eff5d9a9SPeter Maydell DO_VCMP(VCMPGT, vcmpgt)
1535eff5d9a9SPeter Maydell DO_VCMP(VCMPLE, vcmple)
1536688ba4cfSPeter Maydell 
1537688ba4cfSPeter Maydell static bool do_vmaxv(DisasContext *s, arg_vmaxv *a, MVEGenVADDVFn fn)
1538688ba4cfSPeter Maydell {
1539688ba4cfSPeter Maydell     /*
1540688ba4cfSPeter Maydell      * MIN/MAX operations across a vector: compute the min or
1541688ba4cfSPeter Maydell      * max of the initial value in a general purpose register
1542688ba4cfSPeter Maydell      * and all the elements in the vector, and store it back
1543688ba4cfSPeter Maydell      * into the general purpose register.
1544688ba4cfSPeter Maydell      */
1545688ba4cfSPeter Maydell     TCGv_ptr qm;
1546688ba4cfSPeter Maydell     TCGv_i32 rda;
1547688ba4cfSPeter Maydell 
1548688ba4cfSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qm) ||
1549688ba4cfSPeter Maydell         !fn || a->rda == 13 || a->rda == 15) {
1550688ba4cfSPeter Maydell         /* Rda cases are UNPREDICTABLE */
1551688ba4cfSPeter Maydell         return false;
1552688ba4cfSPeter Maydell     }
1553688ba4cfSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1554688ba4cfSPeter Maydell         return true;
1555688ba4cfSPeter Maydell     }
1556688ba4cfSPeter Maydell 
1557688ba4cfSPeter Maydell     qm = mve_qreg_ptr(a->qm);
1558688ba4cfSPeter Maydell     rda = load_reg(s, a->rda);
1559688ba4cfSPeter Maydell     fn(rda, cpu_env, qm, rda);
1560688ba4cfSPeter Maydell     store_reg(s, a->rda, rda);
1561688ba4cfSPeter Maydell     tcg_temp_free_ptr(qm);
1562688ba4cfSPeter Maydell     mve_update_eci(s);
1563688ba4cfSPeter Maydell     return true;
1564688ba4cfSPeter Maydell }
1565688ba4cfSPeter Maydell 
1566688ba4cfSPeter Maydell #define DO_VMAXV(INSN, FN)                                      \
1567688ba4cfSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vmaxv *a)     \
1568688ba4cfSPeter Maydell     {                                                           \
1569688ba4cfSPeter Maydell         static MVEGenVADDVFn * const fns[] = {                  \
1570688ba4cfSPeter Maydell             gen_helper_mve_##FN##b,                             \
1571688ba4cfSPeter Maydell             gen_helper_mve_##FN##h,                             \
1572688ba4cfSPeter Maydell             gen_helper_mve_##FN##w,                             \
1573688ba4cfSPeter Maydell             NULL,                                               \
1574688ba4cfSPeter Maydell         };                                                      \
1575688ba4cfSPeter Maydell         return do_vmaxv(s, a, fns[a->size]);                    \
1576688ba4cfSPeter Maydell     }
1577688ba4cfSPeter Maydell 
1578688ba4cfSPeter Maydell DO_VMAXV(VMAXV_S, vmaxvs)
1579688ba4cfSPeter Maydell DO_VMAXV(VMAXV_U, vmaxvu)
1580688ba4cfSPeter Maydell DO_VMAXV(VMAXAV, vmaxav)
1581688ba4cfSPeter Maydell DO_VMAXV(VMINV_S, vminvs)
1582688ba4cfSPeter Maydell DO_VMAXV(VMINV_U, vminvu)
1583688ba4cfSPeter Maydell DO_VMAXV(VMINAV, vminav)
15847f061c0aSPeter Maydell 
15857f061c0aSPeter Maydell static bool do_vabav(DisasContext *s, arg_vabav *a, MVEGenVABAVFn *fn)
15867f061c0aSPeter Maydell {
15877f061c0aSPeter Maydell     /* Absolute difference accumulated across vector */
15887f061c0aSPeter Maydell     TCGv_ptr qn, qm;
15897f061c0aSPeter Maydell     TCGv_i32 rda;
15907f061c0aSPeter Maydell 
15917f061c0aSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
15927f061c0aSPeter Maydell         !mve_check_qreg_bank(s, a->qm | a->qn) ||
15937f061c0aSPeter Maydell         !fn || a->rda == 13 || a->rda == 15) {
15947f061c0aSPeter Maydell         /* Rda cases are UNPREDICTABLE */
15957f061c0aSPeter Maydell         return false;
15967f061c0aSPeter Maydell     }
15977f061c0aSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
15987f061c0aSPeter Maydell         return true;
15997f061c0aSPeter Maydell     }
16007f061c0aSPeter Maydell 
16017f061c0aSPeter Maydell     qm = mve_qreg_ptr(a->qm);
16027f061c0aSPeter Maydell     qn = mve_qreg_ptr(a->qn);
16037f061c0aSPeter Maydell     rda = load_reg(s, a->rda);
16047f061c0aSPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
16057f061c0aSPeter Maydell     store_reg(s, a->rda, rda);
16067f061c0aSPeter Maydell     tcg_temp_free_ptr(qm);
16077f061c0aSPeter Maydell     tcg_temp_free_ptr(qn);
16087f061c0aSPeter Maydell     mve_update_eci(s);
16097f061c0aSPeter Maydell     return true;
16107f061c0aSPeter Maydell }
16117f061c0aSPeter Maydell 
16127f061c0aSPeter Maydell #define DO_VABAV(INSN, FN)                                      \
16137f061c0aSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vabav *a)     \
16147f061c0aSPeter Maydell     {                                                           \
16157f061c0aSPeter Maydell         static MVEGenVABAVFn * const fns[] = {                  \
16167f061c0aSPeter Maydell             gen_helper_mve_##FN##b,                             \
16177f061c0aSPeter Maydell             gen_helper_mve_##FN##h,                             \
16187f061c0aSPeter Maydell             gen_helper_mve_##FN##w,                             \
16197f061c0aSPeter Maydell             NULL,                                               \
16207f061c0aSPeter Maydell         };                                                      \
16217f061c0aSPeter Maydell         return do_vabav(s, a, fns[a->size]);                    \
16227f061c0aSPeter Maydell     }
16237f061c0aSPeter Maydell 
16247f061c0aSPeter Maydell DO_VABAV(VABAV_S, vabavs)
16257f061c0aSPeter Maydell DO_VABAV(VABAV_U, vabavu)
16261241f148SPeter Maydell 
16271241f148SPeter Maydell static bool trans_VMOV_to_2gp(DisasContext *s, arg_VMOV_to_2gp *a)
16281241f148SPeter Maydell {
16291241f148SPeter Maydell     /*
16301241f148SPeter Maydell      * VMOV two 32-bit vector lanes to two general-purpose registers.
16311241f148SPeter Maydell      * This insn is not predicated but it is subject to beat-wise
16321241f148SPeter Maydell      * execution if it is not in an IT block. For us this means
16331241f148SPeter Maydell      * only that if PSR.ECI says we should not be executing the beat
16341241f148SPeter Maydell      * corresponding to the lane of the vector register being accessed
16351241f148SPeter Maydell      * then we should skip perfoming the move, and that we need to do
16361241f148SPeter Maydell      * the usual check for bad ECI state and advance of ECI state.
16371241f148SPeter Maydell      * (If PSR.ECI is non-zero then we cannot be in an IT block.)
16381241f148SPeter Maydell      */
16391241f148SPeter Maydell     TCGv_i32 tmp;
16401241f148SPeter Maydell     int vd;
16411241f148SPeter Maydell 
16421241f148SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd) ||
16431241f148SPeter Maydell         a->rt == 13 || a->rt == 15 || a->rt2 == 13 || a->rt2 == 15 ||
16441241f148SPeter Maydell         a->rt == a->rt2) {
16451241f148SPeter Maydell         /* Rt/Rt2 cases are UNPREDICTABLE */
16461241f148SPeter Maydell         return false;
16471241f148SPeter Maydell     }
16481241f148SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
16491241f148SPeter Maydell         return true;
16501241f148SPeter Maydell     }
16511241f148SPeter Maydell 
16521241f148SPeter Maydell     /* Convert Qreg index to Dreg for read_neon_element32() etc */
16531241f148SPeter Maydell     vd = a->qd * 2;
16541241f148SPeter Maydell 
16551241f148SPeter Maydell     if (!mve_skip_vmov(s, vd, a->idx, MO_32)) {
16561241f148SPeter Maydell         tmp = tcg_temp_new_i32();
16571241f148SPeter Maydell         read_neon_element32(tmp, vd, a->idx, MO_32);
16581241f148SPeter Maydell         store_reg(s, a->rt, tmp);
16591241f148SPeter Maydell     }
16601241f148SPeter Maydell     if (!mve_skip_vmov(s, vd + 1, a->idx, MO_32)) {
16611241f148SPeter Maydell         tmp = tcg_temp_new_i32();
16621241f148SPeter Maydell         read_neon_element32(tmp, vd + 1, a->idx, MO_32);
16631241f148SPeter Maydell         store_reg(s, a->rt2, tmp);
16641241f148SPeter Maydell     }
16651241f148SPeter Maydell 
16661241f148SPeter Maydell     mve_update_and_store_eci(s);
16671241f148SPeter Maydell     return true;
16681241f148SPeter Maydell }
16691241f148SPeter Maydell 
16701241f148SPeter Maydell static bool trans_VMOV_from_2gp(DisasContext *s, arg_VMOV_to_2gp *a)
16711241f148SPeter Maydell {
16721241f148SPeter Maydell     /*
16731241f148SPeter Maydell      * VMOV two general-purpose registers to two 32-bit vector lanes.
16741241f148SPeter Maydell      * This insn is not predicated but it is subject to beat-wise
16751241f148SPeter Maydell      * execution if it is not in an IT block. For us this means
16761241f148SPeter Maydell      * only that if PSR.ECI says we should not be executing the beat
16771241f148SPeter Maydell      * corresponding to the lane of the vector register being accessed
16781241f148SPeter Maydell      * then we should skip perfoming the move, and that we need to do
16791241f148SPeter Maydell      * the usual check for bad ECI state and advance of ECI state.
16801241f148SPeter Maydell      * (If PSR.ECI is non-zero then we cannot be in an IT block.)
16811241f148SPeter Maydell      */
16821241f148SPeter Maydell     TCGv_i32 tmp;
16831241f148SPeter Maydell     int vd;
16841241f148SPeter Maydell 
16851241f148SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd) ||
16861241f148SPeter Maydell         a->rt == 13 || a->rt == 15 || a->rt2 == 13 || a->rt2 == 15) {
16871241f148SPeter Maydell         /* Rt/Rt2 cases are UNPREDICTABLE */
16881241f148SPeter Maydell         return false;
16891241f148SPeter Maydell     }
16901241f148SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
16911241f148SPeter Maydell         return true;
16921241f148SPeter Maydell     }
16931241f148SPeter Maydell 
16941241f148SPeter Maydell     /* Convert Qreg idx to Dreg for read_neon_element32() etc */
16951241f148SPeter Maydell     vd = a->qd * 2;
16961241f148SPeter Maydell 
16971241f148SPeter Maydell     if (!mve_skip_vmov(s, vd, a->idx, MO_32)) {
16981241f148SPeter Maydell         tmp = load_reg(s, a->rt);
16991241f148SPeter Maydell         write_neon_element32(tmp, vd, a->idx, MO_32);
17001241f148SPeter Maydell         tcg_temp_free_i32(tmp);
17011241f148SPeter Maydell     }
17021241f148SPeter Maydell     if (!mve_skip_vmov(s, vd + 1, a->idx, MO_32)) {
17031241f148SPeter Maydell         tmp = load_reg(s, a->rt2);
17041241f148SPeter Maydell         write_neon_element32(tmp, vd + 1, a->idx, MO_32);
17051241f148SPeter Maydell         tcg_temp_free_i32(tmp);
17061241f148SPeter Maydell     }
17071241f148SPeter Maydell 
17081241f148SPeter Maydell     mve_update_and_store_eci(s);
17091241f148SPeter Maydell     return true;
17101241f148SPeter Maydell }
1711