xref: /qemu/target/arm/tcg/translate-mve.c (revision fea3958fa11c75b4f3f335ac0ce4cfc5cf0af7de)
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);
370f0f2bd5SPeter Maydell typedef void MVEGenOneOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
3868245e44SPeter Maydell typedef void MVEGenTwoOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr);
39e51896b3SPeter Maydell typedef void MVEGenTwoOpScalarFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
40f9ed6174SPeter Maydell typedef void MVEGenTwoOpShiftFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
41640cdf20SPeter Maydell typedef void MVEGenLongDualAccOpFn(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64);
426f060a63SPeter Maydell typedef void MVEGenVADDVFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32);
43eab84139SPeter Maydell typedef void MVEGenOneOpImmFn(TCGv_ptr, TCGv_ptr, TCGv_i64);
44395b92d5SPeter Maydell typedef void MVEGenVIDUPFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32, TCGv_i32);
45395b92d5SPeter Maydell typedef void MVEGenVIWDUPFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32);
46eff5d9a9SPeter Maydell typedef void MVEGenCmpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
47cce81873SPeter Maydell typedef void MVEGenScalarCmpFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
487f061c0aSPeter Maydell typedef void MVEGenVABAVFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
49f0ffff51SPeter Maydell typedef void MVEGenDualAccOpFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
50507b6a50SPeter Maydell 
51507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */
52507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg)
53507b6a50SPeter Maydell {
54507b6a50SPeter Maydell     return offsetof(CPUARMState, vfp.zregs[reg].d[0]);
55507b6a50SPeter Maydell }
56507b6a50SPeter Maydell 
57507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg)
58507b6a50SPeter Maydell {
59507b6a50SPeter Maydell     TCGv_ptr ret = tcg_temp_new_ptr();
60507b6a50SPeter Maydell     tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg));
61507b6a50SPeter Maydell     return ret;
62507b6a50SPeter Maydell }
63507b6a50SPeter Maydell 
64507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask)
65507b6a50SPeter Maydell {
66507b6a50SPeter Maydell     /*
67507b6a50SPeter Maydell      * Check whether Qregs are in range. For v8.1M only Q0..Q7
68507b6a50SPeter Maydell      * are supported, see VFPSmallRegisterBank().
69507b6a50SPeter Maydell      */
70507b6a50SPeter Maydell     return qmask < 8;
71507b6a50SPeter Maydell }
72507b6a50SPeter Maydell 
734f57ef95SPeter Maydell bool mve_eci_check(DisasContext *s)
74507b6a50SPeter Maydell {
75507b6a50SPeter Maydell     /*
76507b6a50SPeter Maydell      * This is a beatwise insn: check that ECI is valid (not a
77507b6a50SPeter Maydell      * reserved value) and note that we are handling it.
78507b6a50SPeter Maydell      * Return true if OK, false if we generated an exception.
79507b6a50SPeter Maydell      */
80507b6a50SPeter Maydell     s->eci_handled = true;
81507b6a50SPeter Maydell     switch (s->eci) {
82507b6a50SPeter Maydell     case ECI_NONE:
83507b6a50SPeter Maydell     case ECI_A0:
84507b6a50SPeter Maydell     case ECI_A0A1:
85507b6a50SPeter Maydell     case ECI_A0A1A2:
86507b6a50SPeter Maydell     case ECI_A0A1A2B0:
87507b6a50SPeter Maydell         return true;
88507b6a50SPeter Maydell     default:
89507b6a50SPeter Maydell         /* Reserved value: INVSTATE UsageFault */
90507b6a50SPeter Maydell         gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(),
91507b6a50SPeter Maydell                            default_exception_el(s));
92507b6a50SPeter Maydell         return false;
93507b6a50SPeter Maydell     }
94507b6a50SPeter Maydell }
95507b6a50SPeter Maydell 
96507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s)
97507b6a50SPeter Maydell {
98507b6a50SPeter Maydell     /*
99507b6a50SPeter Maydell      * The helper function will always update the CPUState field,
100507b6a50SPeter Maydell      * so we only need to update the DisasContext field.
101507b6a50SPeter Maydell      */
102507b6a50SPeter Maydell     if (s->eci) {
103507b6a50SPeter Maydell         s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE;
104507b6a50SPeter Maydell     }
105507b6a50SPeter Maydell }
106507b6a50SPeter Maydell 
1074f57ef95SPeter Maydell void mve_update_and_store_eci(DisasContext *s)
108387debdbSPeter Maydell {
109387debdbSPeter Maydell     /*
110387debdbSPeter Maydell      * For insns which don't call a helper function that will call
111387debdbSPeter Maydell      * mve_advance_vpt(), this version updates s->eci and also stores
112387debdbSPeter Maydell      * it out to the CPUState field.
113387debdbSPeter Maydell      */
114387debdbSPeter Maydell     if (s->eci) {
115387debdbSPeter Maydell         mve_update_eci(s);
116387debdbSPeter Maydell         store_cpu_field(tcg_constant_i32(s->eci << 4), condexec_bits);
117387debdbSPeter Maydell     }
118387debdbSPeter Maydell }
119387debdbSPeter Maydell 
1201d2386f7SPeter Maydell static bool mve_skip_first_beat(DisasContext *s)
1211d2386f7SPeter Maydell {
1221d2386f7SPeter Maydell     /* Return true if PSR.ECI says we must skip the first beat of this insn */
1231d2386f7SPeter Maydell     switch (s->eci) {
1241d2386f7SPeter Maydell     case ECI_NONE:
1251d2386f7SPeter Maydell         return false;
1261d2386f7SPeter Maydell     case ECI_A0:
1271d2386f7SPeter Maydell     case ECI_A0A1:
1281d2386f7SPeter Maydell     case ECI_A0A1A2:
1291d2386f7SPeter Maydell     case ECI_A0A1A2B0:
1301d2386f7SPeter Maydell         return true;
1311d2386f7SPeter Maydell     default:
1321d2386f7SPeter Maydell         g_assert_not_reached();
1331d2386f7SPeter Maydell     }
1341d2386f7SPeter Maydell }
1351d2386f7SPeter Maydell 
136d59ccc30SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn,
137d59ccc30SPeter Maydell                     unsigned msize)
138507b6a50SPeter Maydell {
139507b6a50SPeter Maydell     TCGv_i32 addr;
140507b6a50SPeter Maydell     uint32_t offset;
141507b6a50SPeter Maydell     TCGv_ptr qreg;
142507b6a50SPeter Maydell 
143507b6a50SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
144507b6a50SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
145507b6a50SPeter Maydell         !fn) {
146507b6a50SPeter Maydell         return false;
147507b6a50SPeter Maydell     }
148507b6a50SPeter Maydell 
149507b6a50SPeter Maydell     /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
150507b6a50SPeter Maydell     if (a->rn == 15 || (a->rn == 13 && a->w)) {
151507b6a50SPeter Maydell         return false;
152507b6a50SPeter Maydell     }
153507b6a50SPeter Maydell 
154507b6a50SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
155507b6a50SPeter Maydell         return true;
156507b6a50SPeter Maydell     }
157507b6a50SPeter Maydell 
158d59ccc30SPeter Maydell     offset = a->imm << msize;
159507b6a50SPeter Maydell     if (!a->a) {
160507b6a50SPeter Maydell         offset = -offset;
161507b6a50SPeter Maydell     }
162507b6a50SPeter Maydell     addr = load_reg(s, a->rn);
163507b6a50SPeter Maydell     if (a->p) {
164507b6a50SPeter Maydell         tcg_gen_addi_i32(addr, addr, offset);
165507b6a50SPeter Maydell     }
166507b6a50SPeter Maydell 
167507b6a50SPeter Maydell     qreg = mve_qreg_ptr(a->qd);
168507b6a50SPeter Maydell     fn(cpu_env, qreg, addr);
169507b6a50SPeter Maydell     tcg_temp_free_ptr(qreg);
170507b6a50SPeter Maydell 
171507b6a50SPeter Maydell     /*
172507b6a50SPeter Maydell      * Writeback always happens after the last beat of the insn,
173507b6a50SPeter Maydell      * regardless of predication
174507b6a50SPeter Maydell      */
175507b6a50SPeter Maydell     if (a->w) {
176507b6a50SPeter Maydell         if (!a->p) {
177507b6a50SPeter Maydell             tcg_gen_addi_i32(addr, addr, offset);
178507b6a50SPeter Maydell         }
179507b6a50SPeter Maydell         store_reg(s, a->rn, addr);
180507b6a50SPeter Maydell     } else {
181507b6a50SPeter Maydell         tcg_temp_free_i32(addr);
182507b6a50SPeter Maydell     }
183507b6a50SPeter Maydell     mve_update_eci(s);
184507b6a50SPeter Maydell     return true;
185507b6a50SPeter Maydell }
186507b6a50SPeter Maydell 
187507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a)
188507b6a50SPeter Maydell {
189507b6a50SPeter Maydell     static MVEGenLdStFn * const ldstfns[4][2] = {
190507b6a50SPeter Maydell         { gen_helper_mve_vstrb, gen_helper_mve_vldrb },
191507b6a50SPeter Maydell         { gen_helper_mve_vstrh, gen_helper_mve_vldrh },
192507b6a50SPeter Maydell         { gen_helper_mve_vstrw, gen_helper_mve_vldrw },
193507b6a50SPeter Maydell         { NULL, NULL }
194507b6a50SPeter Maydell     };
195d59ccc30SPeter Maydell     return do_ldst(s, a, ldstfns[a->size][a->l], a->size);
196507b6a50SPeter Maydell }
1972fc6b751SPeter Maydell 
198d59ccc30SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST, MSIZE)           \
1992fc6b751SPeter Maydell     static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a)   \
2002fc6b751SPeter Maydell     {                                                           \
2012fc6b751SPeter Maydell         static MVEGenLdStFn * const ldstfns[2][2] = {           \
2022fc6b751SPeter Maydell             { gen_helper_mve_##ST, gen_helper_mve_##SLD },      \
2032fc6b751SPeter Maydell             { NULL, gen_helper_mve_##ULD },                     \
2042fc6b751SPeter Maydell         };                                                      \
205d59ccc30SPeter Maydell         return do_ldst(s, a, ldstfns[a->u][a->l], MSIZE);       \
2062fc6b751SPeter Maydell     }
2072fc6b751SPeter Maydell 
208d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h, MO_8)
209d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w, MO_8)
210d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w, MO_16)
2110f0f2bd5SPeter Maydell 
212ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
213ab59362fSPeter Maydell {
214ab59362fSPeter Maydell     TCGv_ptr qd;
215ab59362fSPeter Maydell     TCGv_i32 rt;
216ab59362fSPeter Maydell 
217ab59362fSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
218ab59362fSPeter Maydell         !mve_check_qreg_bank(s, a->qd)) {
219ab59362fSPeter Maydell         return false;
220ab59362fSPeter Maydell     }
221ab59362fSPeter Maydell     if (a->rt == 13 || a->rt == 15) {
222ab59362fSPeter Maydell         /* UNPREDICTABLE; we choose to UNDEF */
223ab59362fSPeter Maydell         return false;
224ab59362fSPeter Maydell     }
225ab59362fSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
226ab59362fSPeter Maydell         return true;
227ab59362fSPeter Maydell     }
228ab59362fSPeter Maydell 
229ab59362fSPeter Maydell     qd = mve_qreg_ptr(a->qd);
230ab59362fSPeter Maydell     rt = load_reg(s, a->rt);
231ab59362fSPeter Maydell     tcg_gen_dup_i32(a->size, rt, rt);
232ab59362fSPeter Maydell     gen_helper_mve_vdup(cpu_env, qd, rt);
233ab59362fSPeter Maydell     tcg_temp_free_ptr(qd);
234ab59362fSPeter Maydell     tcg_temp_free_i32(rt);
235ab59362fSPeter Maydell     mve_update_eci(s);
236ab59362fSPeter Maydell     return true;
237ab59362fSPeter Maydell }
238ab59362fSPeter Maydell 
2390f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
2400f0f2bd5SPeter Maydell {
2410f0f2bd5SPeter Maydell     TCGv_ptr qd, qm;
2420f0f2bd5SPeter Maydell 
2430f0f2bd5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
2440f0f2bd5SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
2450f0f2bd5SPeter Maydell         !fn) {
2460f0f2bd5SPeter Maydell         return false;
2470f0f2bd5SPeter Maydell     }
2480f0f2bd5SPeter Maydell 
2490f0f2bd5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
2500f0f2bd5SPeter Maydell         return true;
2510f0f2bd5SPeter Maydell     }
2520f0f2bd5SPeter Maydell 
2530f0f2bd5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
2540f0f2bd5SPeter Maydell     qm = mve_qreg_ptr(a->qm);
2550f0f2bd5SPeter Maydell     fn(cpu_env, qd, qm);
2560f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qd);
2570f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qm);
2580f0f2bd5SPeter Maydell     mve_update_eci(s);
2590f0f2bd5SPeter Maydell     return true;
2600f0f2bd5SPeter Maydell }
2610f0f2bd5SPeter Maydell 
2620f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN)                                        \
2630f0f2bd5SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
2640f0f2bd5SPeter Maydell     {                                                           \
2650f0f2bd5SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
2660f0f2bd5SPeter Maydell             gen_helper_mve_##FN##b,                             \
2670f0f2bd5SPeter Maydell             gen_helper_mve_##FN##h,                             \
2680f0f2bd5SPeter Maydell             gen_helper_mve_##FN##w,                             \
2690f0f2bd5SPeter Maydell             NULL,                                               \
2700f0f2bd5SPeter Maydell         };                                                      \
2710f0f2bd5SPeter Maydell         return do_1op(s, a, fns[a->size]);                      \
2720f0f2bd5SPeter Maydell     }
2730f0f2bd5SPeter Maydell 
2740f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz)
2756437f1f7SPeter Maydell DO_1OP(VCLS, vcls)
27659c91773SPeter Maydell DO_1OP(VABS, vabs)
277399a8c76SPeter Maydell DO_1OP(VNEG, vneg)
278398e7cd3SPeter Maydell DO_1OP(VQABS, vqabs)
279398e7cd3SPeter Maydell DO_1OP(VQNEG, vqneg)
280d5c571eaSPeter Maydell DO_1OP(VMAXA, vmaxa)
281d5c571eaSPeter Maydell DO_1OP(VMINA, vmina)
282249b5309SPeter Maydell 
28354dc78a9SPeter Maydell /* Narrowing moves: only size 0 and 1 are valid */
28454dc78a9SPeter Maydell #define DO_VMOVN(INSN, FN) \
28554dc78a9SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
28654dc78a9SPeter Maydell     {                                                           \
28754dc78a9SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
28854dc78a9SPeter Maydell             gen_helper_mve_##FN##b,                             \
28954dc78a9SPeter Maydell             gen_helper_mve_##FN##h,                             \
29054dc78a9SPeter Maydell             NULL,                                               \
29154dc78a9SPeter Maydell             NULL,                                               \
29254dc78a9SPeter Maydell         };                                                      \
29354dc78a9SPeter Maydell         return do_1op(s, a, fns[a->size]);                      \
29454dc78a9SPeter Maydell     }
29554dc78a9SPeter Maydell 
29654dc78a9SPeter Maydell DO_VMOVN(VMOVNB, vmovnb)
29754dc78a9SPeter Maydell DO_VMOVN(VMOVNT, vmovnt)
29854dc78a9SPeter Maydell DO_VMOVN(VQMOVUNB, vqmovunb)
29954dc78a9SPeter Maydell DO_VMOVN(VQMOVUNT, vqmovunt)
30054dc78a9SPeter Maydell DO_VMOVN(VQMOVN_BS, vqmovnbs)
30154dc78a9SPeter Maydell DO_VMOVN(VQMOVN_TS, vqmovnts)
30254dc78a9SPeter Maydell DO_VMOVN(VQMOVN_BU, vqmovnbu)
30354dc78a9SPeter Maydell DO_VMOVN(VQMOVN_TU, vqmovntu)
30454dc78a9SPeter Maydell 
305249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a)
306249b5309SPeter Maydell {
307249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
308249b5309SPeter Maydell         gen_helper_mve_vrev16b,
309249b5309SPeter Maydell         NULL,
310249b5309SPeter Maydell         NULL,
311249b5309SPeter Maydell         NULL,
312249b5309SPeter Maydell     };
313249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
314249b5309SPeter Maydell }
315249b5309SPeter Maydell 
316249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a)
317249b5309SPeter Maydell {
318249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
319249b5309SPeter Maydell         gen_helper_mve_vrev32b,
320249b5309SPeter Maydell         gen_helper_mve_vrev32h,
321249b5309SPeter Maydell         NULL,
322249b5309SPeter Maydell         NULL,
323249b5309SPeter Maydell     };
324249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
325249b5309SPeter Maydell }
326249b5309SPeter Maydell 
327249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a)
328249b5309SPeter Maydell {
329249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
330249b5309SPeter Maydell         gen_helper_mve_vrev64b,
331249b5309SPeter Maydell         gen_helper_mve_vrev64h,
332249b5309SPeter Maydell         gen_helper_mve_vrev64w,
333249b5309SPeter Maydell         NULL,
334249b5309SPeter Maydell     };
335249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
336249b5309SPeter Maydell }
3378abd3c80SPeter Maydell 
3388abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a)
3398abd3c80SPeter Maydell {
3408abd3c80SPeter Maydell     return do_1op(s, a, gen_helper_mve_vmvn);
3418abd3c80SPeter Maydell }
34259c91773SPeter Maydell 
34359c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a)
34459c91773SPeter Maydell {
34559c91773SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
34659c91773SPeter Maydell         NULL,
34759c91773SPeter Maydell         gen_helper_mve_vfabsh,
34859c91773SPeter Maydell         gen_helper_mve_vfabss,
34959c91773SPeter Maydell         NULL,
35059c91773SPeter Maydell     };
35159c91773SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
35259c91773SPeter Maydell         return false;
35359c91773SPeter Maydell     }
35459c91773SPeter Maydell     return do_1op(s, a, fns[a->size]);
35559c91773SPeter Maydell }
356399a8c76SPeter Maydell 
357399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a)
358399a8c76SPeter Maydell {
359399a8c76SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
360399a8c76SPeter Maydell         NULL,
361399a8c76SPeter Maydell         gen_helper_mve_vfnegh,
362399a8c76SPeter Maydell         gen_helper_mve_vfnegs,
363399a8c76SPeter Maydell         NULL,
364399a8c76SPeter Maydell     };
365399a8c76SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
366399a8c76SPeter Maydell         return false;
367399a8c76SPeter Maydell     }
368399a8c76SPeter Maydell     return do_1op(s, a, fns[a->size]);
369399a8c76SPeter Maydell }
37068245e44SPeter Maydell 
37168245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
37268245e44SPeter Maydell {
37368245e44SPeter Maydell     TCGv_ptr qd, qn, qm;
37468245e44SPeter Maydell 
37568245e44SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
37668245e44SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) ||
37768245e44SPeter Maydell         !fn) {
37868245e44SPeter Maydell         return false;
37968245e44SPeter Maydell     }
38068245e44SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
38168245e44SPeter Maydell         return true;
38268245e44SPeter Maydell     }
38368245e44SPeter Maydell 
38468245e44SPeter Maydell     qd = mve_qreg_ptr(a->qd);
38568245e44SPeter Maydell     qn = mve_qreg_ptr(a->qn);
38668245e44SPeter Maydell     qm = mve_qreg_ptr(a->qm);
38768245e44SPeter Maydell     fn(cpu_env, qd, qn, qm);
38868245e44SPeter Maydell     tcg_temp_free_ptr(qd);
38968245e44SPeter Maydell     tcg_temp_free_ptr(qn);
39068245e44SPeter Maydell     tcg_temp_free_ptr(qm);
39168245e44SPeter Maydell     mve_update_eci(s);
39268245e44SPeter Maydell     return true;
39368245e44SPeter Maydell }
39468245e44SPeter Maydell 
39568245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER)                                  \
39668245e44SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
39768245e44SPeter Maydell     {                                                           \
39868245e44SPeter Maydell         return do_2op(s, a, HELPER);                            \
39968245e44SPeter Maydell     }
40068245e44SPeter Maydell 
40168245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand)
40268245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic)
40368245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr)
40468245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn)
40568245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor)
4069333fe4dSPeter Maydell 
407c386443bSPeter Maydell DO_LOGIC(VPSEL, gen_helper_mve_vpsel)
408c386443bSPeter Maydell 
4099333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \
4109333fe4dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
4119333fe4dSPeter Maydell     {                                                           \
4129333fe4dSPeter Maydell         static MVEGenTwoOpFn * const fns[] = {                  \
4139333fe4dSPeter Maydell             gen_helper_mve_##FN##b,                             \
4149333fe4dSPeter Maydell             gen_helper_mve_##FN##h,                             \
4159333fe4dSPeter Maydell             gen_helper_mve_##FN##w,                             \
4169333fe4dSPeter Maydell             NULL,                                               \
4179333fe4dSPeter Maydell         };                                                      \
4189333fe4dSPeter Maydell         return do_2op(s, a, fns[a->size]);                      \
4199333fe4dSPeter Maydell     }
4209333fe4dSPeter Maydell 
4219333fe4dSPeter Maydell DO_2OP(VADD, vadd)
4229333fe4dSPeter Maydell DO_2OP(VSUB, vsub)
4239333fe4dSPeter Maydell DO_2OP(VMUL, vmul)
424ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs)
425ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu)
426fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs)
427fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu)
428cd367ff3SPeter Maydell DO_2OP(VMAX_S, vmaxs)
429cd367ff3SPeter Maydell DO_2OP(VMAX_U, vmaxu)
430cd367ff3SPeter Maydell DO_2OP(VMIN_S, vmins)
431cd367ff3SPeter Maydell DO_2OP(VMIN_U, vminu)
432bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds)
433bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu)
434abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds)
435abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu)
436abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs)
437abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu)
438ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs)
439ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu)
440ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts)
441ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu)
442380caf6cSPeter Maydell DO_2OP(VQDMULH, vqdmulh)
443380caf6cSPeter Maydell DO_2OP(VQRDMULH, vqrdmulh)
444f741707bSPeter Maydell DO_2OP(VQADD_S, vqadds)
445f741707bSPeter Maydell DO_2OP(VQADD_U, vqaddu)
446f741707bSPeter Maydell DO_2OP(VQSUB_S, vqsubs)
447f741707bSPeter Maydell DO_2OP(VQSUB_U, vqsubu)
4480372cad8SPeter Maydell DO_2OP(VSHL_S, vshls)
4490372cad8SPeter Maydell DO_2OP(VSHL_U, vshlu)
450bb002345SPeter Maydell DO_2OP(VRSHL_S, vrshls)
451bb002345SPeter Maydell DO_2OP(VRSHL_U, vrshlu)
452483da661SPeter Maydell DO_2OP(VQSHL_S, vqshls)
453483da661SPeter Maydell DO_2OP(VQSHL_U, vqshlu)
4549dc868c4SPeter Maydell DO_2OP(VQRSHL_S, vqrshls)
4559dc868c4SPeter Maydell DO_2OP(VQRSHL_U, vqrshlu)
456fd677f80SPeter Maydell DO_2OP(VQDMLADH, vqdmladh)
457fd677f80SPeter Maydell DO_2OP(VQDMLADHX, vqdmladhx)
458fd677f80SPeter Maydell DO_2OP(VQRDMLADH, vqrdmladh)
459fd677f80SPeter Maydell DO_2OP(VQRDMLADHX, vqrdmladhx)
46092f11732SPeter Maydell DO_2OP(VQDMLSDH, vqdmlsdh)
46192f11732SPeter Maydell DO_2OP(VQDMLSDHX, vqdmlsdhx)
46292f11732SPeter Maydell DO_2OP(VQRDMLSDH, vqrdmlsdh)
46392f11732SPeter Maydell DO_2OP(VQRDMLSDHX, vqrdmlsdhx)
4641eb987a8SPeter Maydell DO_2OP(VRHADD_S, vrhadds)
4651eb987a8SPeter Maydell DO_2OP(VRHADD_U, vrhaddu)
46667ec113bSPeter Maydell /*
46767ec113bSPeter Maydell  * VCADD Qd == Qm at size MO_32 is UNPREDICTABLE; we choose not to diagnose
46867ec113bSPeter Maydell  * so we can reuse the DO_2OP macro. (Our implementation calculates the
4698625693aSPeter Maydell  * "expected" results in this case.) Similarly for VHCADD.
47067ec113bSPeter Maydell  */
47167ec113bSPeter Maydell DO_2OP(VCADD90, vcadd90)
47267ec113bSPeter Maydell DO_2OP(VCADD270, vcadd270)
4738625693aSPeter Maydell DO_2OP(VHCADD90, vhcadd90)
4748625693aSPeter Maydell DO_2OP(VHCADD270, vhcadd270)
4751d2386f7SPeter Maydell 
47643364321SPeter Maydell static bool trans_VQDMULLB(DisasContext *s, arg_2op *a)
47743364321SPeter Maydell {
47843364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
47943364321SPeter Maydell         NULL,
48043364321SPeter Maydell         gen_helper_mve_vqdmullbh,
48143364321SPeter Maydell         gen_helper_mve_vqdmullbw,
48243364321SPeter Maydell         NULL,
48343364321SPeter Maydell     };
48443364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
48543364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
48643364321SPeter Maydell         return false;
48743364321SPeter Maydell     }
48843364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
48943364321SPeter Maydell }
49043364321SPeter Maydell 
49143364321SPeter Maydell static bool trans_VQDMULLT(DisasContext *s, arg_2op *a)
49243364321SPeter Maydell {
49343364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
49443364321SPeter Maydell         NULL,
49543364321SPeter Maydell         gen_helper_mve_vqdmullth,
49643364321SPeter Maydell         gen_helper_mve_vqdmulltw,
49743364321SPeter Maydell         NULL,
49843364321SPeter Maydell     };
49943364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
50043364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
50143364321SPeter Maydell         return false;
50243364321SPeter Maydell     }
50343364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
50443364321SPeter Maydell }
50543364321SPeter Maydell 
506c1bd78cbSPeter Maydell static bool trans_VMULLP_B(DisasContext *s, arg_2op *a)
507c1bd78cbSPeter Maydell {
508c1bd78cbSPeter Maydell     /*
509c1bd78cbSPeter Maydell      * Note that a->size indicates the output size, ie VMULL.P8
510c1bd78cbSPeter Maydell      * is the 8x8->16 operation and a->size is MO_16; VMULL.P16
511c1bd78cbSPeter Maydell      * is the 16x16->32 operation and a->size is MO_32.
512c1bd78cbSPeter Maydell      */
513c1bd78cbSPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
514c1bd78cbSPeter Maydell         NULL,
515c1bd78cbSPeter Maydell         gen_helper_mve_vmullpbh,
516c1bd78cbSPeter Maydell         gen_helper_mve_vmullpbw,
517c1bd78cbSPeter Maydell         NULL,
518c1bd78cbSPeter Maydell     };
519c1bd78cbSPeter Maydell     return do_2op(s, a, fns[a->size]);
520c1bd78cbSPeter Maydell }
521c1bd78cbSPeter Maydell 
522c1bd78cbSPeter Maydell static bool trans_VMULLP_T(DisasContext *s, arg_2op *a)
523c1bd78cbSPeter Maydell {
524c1bd78cbSPeter Maydell     /* a->size is as for trans_VMULLP_B */
525c1bd78cbSPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
526c1bd78cbSPeter Maydell         NULL,
527c1bd78cbSPeter Maydell         gen_helper_mve_vmullpth,
528c1bd78cbSPeter Maydell         gen_helper_mve_vmullptw,
529c1bd78cbSPeter Maydell         NULL,
530c1bd78cbSPeter Maydell     };
531c1bd78cbSPeter Maydell     return do_2op(s, a, fns[a->size]);
532c1bd78cbSPeter Maydell }
533c1bd78cbSPeter Maydell 
53489bc4c4fSPeter Maydell /*
53589bc4c4fSPeter Maydell  * VADC and VSBC: these perform an add-with-carry or subtract-with-carry
53689bc4c4fSPeter Maydell  * of the 32-bit elements in each lane of the input vectors, where the
53789bc4c4fSPeter Maydell  * carry-out of each add is the carry-in of the next.  The initial carry
53889bc4c4fSPeter Maydell  * input is either fixed (0 for VADCI, 1 for VSBCI) or is from FPSCR.C
53989bc4c4fSPeter Maydell  * (for VADC and VSBC); the carry out at the end is written back to FPSCR.C.
54089bc4c4fSPeter Maydell  * These insns are subject to beat-wise execution.  Partial execution
54189bc4c4fSPeter Maydell  * of an I=1 (initial carry input fixed) insn which does not
54289bc4c4fSPeter Maydell  * execute the first beat must start with the current FPSCR.NZCV
54389bc4c4fSPeter Maydell  * value, not the fixed constant input.
54489bc4c4fSPeter Maydell  */
54589bc4c4fSPeter Maydell static bool trans_VADC(DisasContext *s, arg_2op *a)
54689bc4c4fSPeter Maydell {
54789bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadc);
54889bc4c4fSPeter Maydell }
54989bc4c4fSPeter Maydell 
55089bc4c4fSPeter Maydell static bool trans_VADCI(DisasContext *s, arg_2op *a)
55189bc4c4fSPeter Maydell {
55289bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
55389bc4c4fSPeter Maydell         return trans_VADC(s, a);
55489bc4c4fSPeter Maydell     }
55589bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadci);
55689bc4c4fSPeter Maydell }
55789bc4c4fSPeter Maydell 
55889bc4c4fSPeter Maydell static bool trans_VSBC(DisasContext *s, arg_2op *a)
55989bc4c4fSPeter Maydell {
56089bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbc);
56189bc4c4fSPeter Maydell }
56289bc4c4fSPeter Maydell 
56389bc4c4fSPeter Maydell static bool trans_VSBCI(DisasContext *s, arg_2op *a)
56489bc4c4fSPeter Maydell {
56589bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
56689bc4c4fSPeter Maydell         return trans_VSBC(s, a);
56789bc4c4fSPeter Maydell     }
56889bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbci);
56989bc4c4fSPeter Maydell }
57089bc4c4fSPeter Maydell 
571e51896b3SPeter Maydell static bool do_2op_scalar(DisasContext *s, arg_2scalar *a,
572e51896b3SPeter Maydell                           MVEGenTwoOpScalarFn fn)
573e51896b3SPeter Maydell {
574e51896b3SPeter Maydell     TCGv_ptr qd, qn;
575e51896b3SPeter Maydell     TCGv_i32 rm;
576e51896b3SPeter Maydell 
577e51896b3SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
578e51896b3SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn) ||
579e51896b3SPeter Maydell         !fn) {
580e51896b3SPeter Maydell         return false;
581e51896b3SPeter Maydell     }
582e51896b3SPeter Maydell     if (a->rm == 13 || a->rm == 15) {
583e51896b3SPeter Maydell         /* UNPREDICTABLE */
584e51896b3SPeter Maydell         return false;
585e51896b3SPeter Maydell     }
586e51896b3SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
587e51896b3SPeter Maydell         return true;
588e51896b3SPeter Maydell     }
589e51896b3SPeter Maydell 
590e51896b3SPeter Maydell     qd = mve_qreg_ptr(a->qd);
591e51896b3SPeter Maydell     qn = mve_qreg_ptr(a->qn);
592e51896b3SPeter Maydell     rm = load_reg(s, a->rm);
593e51896b3SPeter Maydell     fn(cpu_env, qd, qn, rm);
594e51896b3SPeter Maydell     tcg_temp_free_i32(rm);
595e51896b3SPeter Maydell     tcg_temp_free_ptr(qd);
596e51896b3SPeter Maydell     tcg_temp_free_ptr(qn);
597e51896b3SPeter Maydell     mve_update_eci(s);
598e51896b3SPeter Maydell     return true;
599e51896b3SPeter Maydell }
600e51896b3SPeter Maydell 
601e51896b3SPeter Maydell #define DO_2OP_SCALAR(INSN, FN) \
602e51896b3SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2scalar *a)   \
603e51896b3SPeter Maydell     {                                                           \
604e51896b3SPeter Maydell         static MVEGenTwoOpScalarFn * const fns[] = {            \
605e51896b3SPeter Maydell             gen_helper_mve_##FN##b,                             \
606e51896b3SPeter Maydell             gen_helper_mve_##FN##h,                             \
607e51896b3SPeter Maydell             gen_helper_mve_##FN##w,                             \
608e51896b3SPeter Maydell             NULL,                                               \
609e51896b3SPeter Maydell         };                                                      \
610e51896b3SPeter Maydell         return do_2op_scalar(s, a, fns[a->size]);               \
611e51896b3SPeter Maydell     }
612e51896b3SPeter Maydell 
613e51896b3SPeter Maydell DO_2OP_SCALAR(VADD_scalar, vadd_scalar)
61491a358fdSPeter Maydell DO_2OP_SCALAR(VSUB_scalar, vsub_scalar)
61591a358fdSPeter Maydell DO_2OP_SCALAR(VMUL_scalar, vmul_scalar)
616644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_S_scalar, vhadds_scalar)
617644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_U_scalar, vhaddu_scalar)
618644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_S_scalar, vhsubs_scalar)
619644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_U_scalar, vhsubu_scalar)
62039f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_S_scalar, vqadds_scalar)
62139f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_U_scalar, vqaddu_scalar)
62239f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_S_scalar, vqsubs_scalar)
62339f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_U_scalar, vqsubu_scalar)
62466c05767SPeter Maydell DO_2OP_SCALAR(VQDMULH_scalar, vqdmulh_scalar)
62566c05767SPeter Maydell DO_2OP_SCALAR(VQRDMULH_scalar, vqrdmulh_scalar)
626b050543bSPeter Maydell DO_2OP_SCALAR(VBRSR, vbrsr)
627c69e34c6SPeter Maydell DO_2OP_SCALAR(VMLA, vmla)
6286b895bf8SPeter Maydell DO_2OP_SCALAR(VMLAS, vmlas)
6298be9a250SPeter Maydell DO_2OP_SCALAR(VQDMLAH, vqdmlah)
6308be9a250SPeter Maydell DO_2OP_SCALAR(VQRDMLAH, vqrdmlah)
6318be9a250SPeter Maydell DO_2OP_SCALAR(VQDMLASH, vqdmlash)
6328be9a250SPeter Maydell DO_2OP_SCALAR(VQRDMLASH, vqrdmlash)
633e51896b3SPeter Maydell 
634a8890353SPeter Maydell static bool trans_VQDMULLB_scalar(DisasContext *s, arg_2scalar *a)
635a8890353SPeter Maydell {
636a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
637a8890353SPeter Maydell         NULL,
638a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarh,
639a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarw,
640a8890353SPeter Maydell         NULL,
641a8890353SPeter Maydell     };
642a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
643a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
644a8890353SPeter Maydell         return false;
645a8890353SPeter Maydell     }
646a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
647a8890353SPeter Maydell }
648a8890353SPeter Maydell 
649a8890353SPeter Maydell static bool trans_VQDMULLT_scalar(DisasContext *s, arg_2scalar *a)
650a8890353SPeter Maydell {
651a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
652a8890353SPeter Maydell         NULL,
653a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarh,
654a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarw,
655a8890353SPeter Maydell         NULL,
656a8890353SPeter Maydell     };
657a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
658a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
659a8890353SPeter Maydell         return false;
660a8890353SPeter Maydell     }
661a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
662a8890353SPeter Maydell }
663a8890353SPeter Maydell 
6641d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a,
665640cdf20SPeter Maydell                              MVEGenLongDualAccOpFn *fn)
6661d2386f7SPeter Maydell {
6671d2386f7SPeter Maydell     TCGv_ptr qn, qm;
6681d2386f7SPeter Maydell     TCGv_i64 rda;
6691d2386f7SPeter Maydell     TCGv_i32 rdalo, rdahi;
6701d2386f7SPeter Maydell 
6711d2386f7SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
6721d2386f7SPeter Maydell         !mve_check_qreg_bank(s, a->qn | a->qm) ||
6731d2386f7SPeter Maydell         !fn) {
6741d2386f7SPeter Maydell         return false;
6751d2386f7SPeter Maydell     }
6761d2386f7SPeter Maydell     /*
6771d2386f7SPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
6781d2386f7SPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
6791d2386f7SPeter Maydell      */
6801d2386f7SPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
6811d2386f7SPeter Maydell         return false;
6821d2386f7SPeter Maydell     }
6831d2386f7SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
6841d2386f7SPeter Maydell         return true;
6851d2386f7SPeter Maydell     }
6861d2386f7SPeter Maydell 
6871d2386f7SPeter Maydell     qn = mve_qreg_ptr(a->qn);
6881d2386f7SPeter Maydell     qm = mve_qreg_ptr(a->qm);
6891d2386f7SPeter Maydell 
6901d2386f7SPeter Maydell     /*
6911d2386f7SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
6921d2386f7SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
6931d2386f7SPeter Maydell      * beat must start with the current rda value, not 0.
6941d2386f7SPeter Maydell      */
6951d2386f7SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
6961d2386f7SPeter Maydell         rda = tcg_temp_new_i64();
6971d2386f7SPeter Maydell         rdalo = load_reg(s, a->rdalo);
6981d2386f7SPeter Maydell         rdahi = load_reg(s, a->rdahi);
6991d2386f7SPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
7001d2386f7SPeter Maydell         tcg_temp_free_i32(rdalo);
7011d2386f7SPeter Maydell         tcg_temp_free_i32(rdahi);
7021d2386f7SPeter Maydell     } else {
7031d2386f7SPeter Maydell         rda = tcg_const_i64(0);
7041d2386f7SPeter Maydell     }
7051d2386f7SPeter Maydell 
7061d2386f7SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
7071d2386f7SPeter Maydell     tcg_temp_free_ptr(qn);
7081d2386f7SPeter Maydell     tcg_temp_free_ptr(qm);
7091d2386f7SPeter Maydell 
7101d2386f7SPeter Maydell     rdalo = tcg_temp_new_i32();
7111d2386f7SPeter Maydell     rdahi = tcg_temp_new_i32();
7121d2386f7SPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
7131d2386f7SPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
7141d2386f7SPeter Maydell     store_reg(s, a->rdalo, rdalo);
7151d2386f7SPeter Maydell     store_reg(s, a->rdahi, rdahi);
7161d2386f7SPeter Maydell     tcg_temp_free_i64(rda);
7171d2386f7SPeter Maydell     mve_update_eci(s);
7181d2386f7SPeter Maydell     return true;
7191d2386f7SPeter Maydell }
7201d2386f7SPeter Maydell 
7211d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a)
7221d2386f7SPeter Maydell {
723640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
7241d2386f7SPeter Maydell         { NULL, NULL },
7251d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh },
7261d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw },
7271d2386f7SPeter Maydell         { NULL, NULL },
7281d2386f7SPeter Maydell     };
7291d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
7301d2386f7SPeter Maydell }
7311d2386f7SPeter Maydell 
7321d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a)
7331d2386f7SPeter Maydell {
734640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
7351d2386f7SPeter Maydell         { NULL, NULL },
7361d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuh, NULL },
7371d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuw, NULL },
7381d2386f7SPeter Maydell         { NULL, NULL },
7391d2386f7SPeter Maydell     };
7401d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
7411d2386f7SPeter Maydell }
742181cd971SPeter Maydell 
743181cd971SPeter Maydell static bool trans_VMLSLDAV(DisasContext *s, arg_vmlaldav *a)
744181cd971SPeter Maydell {
745640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
746181cd971SPeter Maydell         { NULL, NULL },
747181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh },
748181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw },
749181cd971SPeter Maydell         { NULL, NULL },
750181cd971SPeter Maydell     };
751181cd971SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
752181cd971SPeter Maydell }
75338548747SPeter Maydell 
75438548747SPeter Maydell static bool trans_VRMLALDAVH_S(DisasContext *s, arg_vmlaldav *a)
75538548747SPeter Maydell {
756640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
75738548747SPeter Maydell         gen_helper_mve_vrmlaldavhsw, gen_helper_mve_vrmlaldavhxsw,
75838548747SPeter Maydell     };
75938548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
76038548747SPeter Maydell }
76138548747SPeter Maydell 
76238548747SPeter Maydell static bool trans_VRMLALDAVH_U(DisasContext *s, arg_vmlaldav *a)
76338548747SPeter Maydell {
764640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
76538548747SPeter Maydell         gen_helper_mve_vrmlaldavhuw, NULL,
76638548747SPeter Maydell     };
76738548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
76838548747SPeter Maydell }
76938548747SPeter Maydell 
77038548747SPeter Maydell static bool trans_VRMLSLDAVH(DisasContext *s, arg_vmlaldav *a)
77138548747SPeter Maydell {
772640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
77338548747SPeter Maydell         gen_helper_mve_vrmlsldavhsw, gen_helper_mve_vrmlsldavhxsw,
77438548747SPeter Maydell     };
77538548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
77638548747SPeter Maydell }
777387debdbSPeter Maydell 
778f0ffff51SPeter Maydell static bool do_dual_acc(DisasContext *s, arg_vmladav *a, MVEGenDualAccOpFn *fn)
779f0ffff51SPeter Maydell {
780f0ffff51SPeter Maydell     TCGv_ptr qn, qm;
781f0ffff51SPeter Maydell     TCGv_i32 rda;
782f0ffff51SPeter Maydell 
783f0ffff51SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
784f0ffff51SPeter Maydell         !mve_check_qreg_bank(s, a->qn) ||
785f0ffff51SPeter Maydell         !fn) {
786f0ffff51SPeter Maydell         return false;
787f0ffff51SPeter Maydell     }
788f0ffff51SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
789f0ffff51SPeter Maydell         return true;
790f0ffff51SPeter Maydell     }
791f0ffff51SPeter Maydell 
792f0ffff51SPeter Maydell     qn = mve_qreg_ptr(a->qn);
793f0ffff51SPeter Maydell     qm = mve_qreg_ptr(a->qm);
794f0ffff51SPeter Maydell 
795f0ffff51SPeter Maydell     /*
796f0ffff51SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
797f0ffff51SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
798f0ffff51SPeter Maydell      * beat must start with the current rda value, not 0.
799f0ffff51SPeter Maydell      */
800f0ffff51SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
801f0ffff51SPeter Maydell         rda = load_reg(s, a->rda);
802f0ffff51SPeter Maydell     } else {
803f0ffff51SPeter Maydell         rda = tcg_const_i32(0);
804f0ffff51SPeter Maydell     }
805f0ffff51SPeter Maydell 
806f0ffff51SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
807f0ffff51SPeter Maydell     store_reg(s, a->rda, rda);
808f0ffff51SPeter Maydell     tcg_temp_free_ptr(qn);
809f0ffff51SPeter Maydell     tcg_temp_free_ptr(qm);
810f0ffff51SPeter Maydell 
811f0ffff51SPeter Maydell     mve_update_eci(s);
812f0ffff51SPeter Maydell     return true;
813f0ffff51SPeter Maydell }
814f0ffff51SPeter Maydell 
815f0ffff51SPeter Maydell #define DO_DUAL_ACC(INSN, FN)                                           \
816f0ffff51SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vmladav *a)           \
817f0ffff51SPeter Maydell     {                                                                   \
818f0ffff51SPeter Maydell         static MVEGenDualAccOpFn * const fns[4][2] = {                  \
819f0ffff51SPeter Maydell             { gen_helper_mve_##FN##b, gen_helper_mve_##FN##xb },        \
820f0ffff51SPeter Maydell             { gen_helper_mve_##FN##h, gen_helper_mve_##FN##xh },        \
821f0ffff51SPeter Maydell             { gen_helper_mve_##FN##w, gen_helper_mve_##FN##xw },        \
822f0ffff51SPeter Maydell             { NULL, NULL },                                             \
823f0ffff51SPeter Maydell         };                                                              \
824f0ffff51SPeter Maydell         return do_dual_acc(s, a, fns[a->size][a->x]);                   \
825f0ffff51SPeter Maydell     }
826f0ffff51SPeter Maydell 
827f0ffff51SPeter Maydell DO_DUAL_ACC(VMLADAV_S, vmladavs)
828f0ffff51SPeter Maydell DO_DUAL_ACC(VMLSDAV, vmlsdav)
829f0ffff51SPeter Maydell 
830f0ffff51SPeter Maydell static bool trans_VMLADAV_U(DisasContext *s, arg_vmladav *a)
831f0ffff51SPeter Maydell {
832f0ffff51SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
833f0ffff51SPeter Maydell         { gen_helper_mve_vmladavub, NULL },
834f0ffff51SPeter Maydell         { gen_helper_mve_vmladavuh, NULL },
835f0ffff51SPeter Maydell         { gen_helper_mve_vmladavuw, NULL },
836f0ffff51SPeter Maydell         { NULL, NULL },
837f0ffff51SPeter Maydell     };
838f0ffff51SPeter Maydell     return do_dual_acc(s, a, fns[a->size][a->x]);
839f0ffff51SPeter Maydell }
840f0ffff51SPeter Maydell 
84155251786SPeter Maydell static void gen_vpst(DisasContext *s, uint32_t mask)
842387debdbSPeter Maydell {
843387debdbSPeter Maydell     /*
844387debdbSPeter Maydell      * Set the VPR mask fields. We take advantage of MASK01 and MASK23
845387debdbSPeter Maydell      * being adjacent fields in the register.
846387debdbSPeter Maydell      *
84755251786SPeter Maydell      * Updating the masks is not predicated, but it is subject to beat-wise
848387debdbSPeter Maydell      * execution, and the mask is updated on the odd-numbered beats.
849387debdbSPeter Maydell      * So if PSR.ECI says we should skip beat 1, we mustn't update the
850387debdbSPeter Maydell      * 01 mask field.
851387debdbSPeter Maydell      */
85255251786SPeter Maydell     TCGv_i32 vpr = load_cpu_field(v7m.vpr);
853387debdbSPeter Maydell     switch (s->eci) {
854387debdbSPeter Maydell     case ECI_NONE:
855387debdbSPeter Maydell     case ECI_A0:
856387debdbSPeter Maydell         /* Update both 01 and 23 fields */
857387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
85855251786SPeter Maydell                             tcg_constant_i32(mask | (mask << 4)),
859387debdbSPeter Maydell                             R_V7M_VPR_MASK01_SHIFT,
860387debdbSPeter Maydell                             R_V7M_VPR_MASK01_LENGTH + R_V7M_VPR_MASK23_LENGTH);
861387debdbSPeter Maydell         break;
862387debdbSPeter Maydell     case ECI_A0A1:
863387debdbSPeter Maydell     case ECI_A0A1A2:
864387debdbSPeter Maydell     case ECI_A0A1A2B0:
865387debdbSPeter Maydell         /* Update only the 23 mask field */
866387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
86755251786SPeter Maydell                             tcg_constant_i32(mask),
868387debdbSPeter Maydell                             R_V7M_VPR_MASK23_SHIFT, R_V7M_VPR_MASK23_LENGTH);
869387debdbSPeter Maydell         break;
870387debdbSPeter Maydell     default:
871387debdbSPeter Maydell         g_assert_not_reached();
872387debdbSPeter Maydell     }
873387debdbSPeter Maydell     store_cpu_field(vpr, v7m.vpr);
87455251786SPeter Maydell }
87555251786SPeter Maydell 
87655251786SPeter Maydell static bool trans_VPST(DisasContext *s, arg_VPST *a)
87755251786SPeter Maydell {
87855251786SPeter Maydell     /* mask == 0 is a "related encoding" */
87955251786SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !a->mask) {
88055251786SPeter Maydell         return false;
88155251786SPeter Maydell     }
88255251786SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
88355251786SPeter Maydell         return true;
88455251786SPeter Maydell     }
88555251786SPeter Maydell     gen_vpst(s, a->mask);
886387debdbSPeter Maydell     mve_update_and_store_eci(s);
887387debdbSPeter Maydell     return true;
888387debdbSPeter Maydell }
8896f060a63SPeter Maydell 
890*fea3958fSPeter Maydell static bool trans_VPNOT(DisasContext *s, arg_VPNOT *a)
891*fea3958fSPeter Maydell {
892*fea3958fSPeter Maydell     /*
893*fea3958fSPeter Maydell      * Invert the predicate in VPR.P0. We have call out to
894*fea3958fSPeter Maydell      * a helper because this insn itself is beatwise and can
895*fea3958fSPeter Maydell      * be predicated.
896*fea3958fSPeter Maydell      */
897*fea3958fSPeter Maydell     if (!dc_isar_feature(aa32_mve, s)) {
898*fea3958fSPeter Maydell         return false;
899*fea3958fSPeter Maydell     }
900*fea3958fSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
901*fea3958fSPeter Maydell         return true;
902*fea3958fSPeter Maydell     }
903*fea3958fSPeter Maydell 
904*fea3958fSPeter Maydell     gen_helper_mve_vpnot(cpu_env);
905*fea3958fSPeter Maydell     mve_update_eci(s);
906*fea3958fSPeter Maydell     return true;
907*fea3958fSPeter Maydell }
908*fea3958fSPeter Maydell 
9096f060a63SPeter Maydell static bool trans_VADDV(DisasContext *s, arg_VADDV *a)
9106f060a63SPeter Maydell {
9116f060a63SPeter Maydell     /* VADDV: vector add across vector */
9126f060a63SPeter Maydell     static MVEGenVADDVFn * const fns[4][2] = {
9136f060a63SPeter Maydell         { gen_helper_mve_vaddvsb, gen_helper_mve_vaddvub },
9146f060a63SPeter Maydell         { gen_helper_mve_vaddvsh, gen_helper_mve_vaddvuh },
9156f060a63SPeter Maydell         { gen_helper_mve_vaddvsw, gen_helper_mve_vaddvuw },
9166f060a63SPeter Maydell         { NULL, NULL }
9176f060a63SPeter Maydell     };
9186f060a63SPeter Maydell     TCGv_ptr qm;
9196f060a63SPeter Maydell     TCGv_i32 rda;
9206f060a63SPeter Maydell 
9216f060a63SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
9226f060a63SPeter Maydell         a->size == 3) {
9236f060a63SPeter Maydell         return false;
9246f060a63SPeter Maydell     }
9256f060a63SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
9266f060a63SPeter Maydell         return true;
9276f060a63SPeter Maydell     }
9286f060a63SPeter Maydell 
9296f060a63SPeter Maydell     /*
9306f060a63SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
9316f060a63SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
9326f060a63SPeter Maydell      * beat must start with the current value of Rda, not zero.
9336f060a63SPeter Maydell      */
9346f060a63SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
9356f060a63SPeter Maydell         /* Accumulate input from Rda */
9366f060a63SPeter Maydell         rda = load_reg(s, a->rda);
9376f060a63SPeter Maydell     } else {
9386f060a63SPeter Maydell         /* Accumulate starting at zero */
9396f060a63SPeter Maydell         rda = tcg_const_i32(0);
9406f060a63SPeter Maydell     }
9416f060a63SPeter Maydell 
9426f060a63SPeter Maydell     qm = mve_qreg_ptr(a->qm);
9436f060a63SPeter Maydell     fns[a->size][a->u](rda, cpu_env, qm, rda);
9446f060a63SPeter Maydell     store_reg(s, a->rda, rda);
9456f060a63SPeter Maydell     tcg_temp_free_ptr(qm);
9466f060a63SPeter Maydell 
9476f060a63SPeter Maydell     mve_update_eci(s);
9486f060a63SPeter Maydell     return true;
9496f060a63SPeter Maydell }
950eab84139SPeter Maydell 
951d43ebd9dSPeter Maydell static bool trans_VADDLV(DisasContext *s, arg_VADDLV *a)
952d43ebd9dSPeter Maydell {
953d43ebd9dSPeter Maydell     /*
954d43ebd9dSPeter Maydell      * Vector Add Long Across Vector: accumulate the 32-bit
955d43ebd9dSPeter Maydell      * elements of the vector into a 64-bit result stored in
956d43ebd9dSPeter Maydell      * a pair of general-purpose registers.
957d43ebd9dSPeter Maydell      * No need to check Qm's bank: it is only 3 bits in decode.
958d43ebd9dSPeter Maydell      */
959d43ebd9dSPeter Maydell     TCGv_ptr qm;
960d43ebd9dSPeter Maydell     TCGv_i64 rda;
961d43ebd9dSPeter Maydell     TCGv_i32 rdalo, rdahi;
962d43ebd9dSPeter Maydell 
963d43ebd9dSPeter Maydell     if (!dc_isar_feature(aa32_mve, s)) {
964d43ebd9dSPeter Maydell         return false;
965d43ebd9dSPeter Maydell     }
966d43ebd9dSPeter Maydell     /*
967d43ebd9dSPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
968d43ebd9dSPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
969d43ebd9dSPeter Maydell      */
970d43ebd9dSPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
971d43ebd9dSPeter Maydell         return false;
972d43ebd9dSPeter Maydell     }
973d43ebd9dSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
974d43ebd9dSPeter Maydell         return true;
975d43ebd9dSPeter Maydell     }
976d43ebd9dSPeter Maydell 
977d43ebd9dSPeter Maydell     /*
978d43ebd9dSPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
979d43ebd9dSPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
980d43ebd9dSPeter Maydell      * beat must start with the current value of RdaHi:RdaLo, not zero.
981d43ebd9dSPeter Maydell      */
982d43ebd9dSPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
983d43ebd9dSPeter Maydell         /* Accumulate input from RdaHi:RdaLo */
984d43ebd9dSPeter Maydell         rda = tcg_temp_new_i64();
985d43ebd9dSPeter Maydell         rdalo = load_reg(s, a->rdalo);
986d43ebd9dSPeter Maydell         rdahi = load_reg(s, a->rdahi);
987d43ebd9dSPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
988d43ebd9dSPeter Maydell         tcg_temp_free_i32(rdalo);
989d43ebd9dSPeter Maydell         tcg_temp_free_i32(rdahi);
990d43ebd9dSPeter Maydell     } else {
991d43ebd9dSPeter Maydell         /* Accumulate starting at zero */
992d43ebd9dSPeter Maydell         rda = tcg_const_i64(0);
993d43ebd9dSPeter Maydell     }
994d43ebd9dSPeter Maydell 
995d43ebd9dSPeter Maydell     qm = mve_qreg_ptr(a->qm);
996d43ebd9dSPeter Maydell     if (a->u) {
997d43ebd9dSPeter Maydell         gen_helper_mve_vaddlv_u(rda, cpu_env, qm, rda);
998d43ebd9dSPeter Maydell     } else {
999d43ebd9dSPeter Maydell         gen_helper_mve_vaddlv_s(rda, cpu_env, qm, rda);
1000d43ebd9dSPeter Maydell     }
1001d43ebd9dSPeter Maydell     tcg_temp_free_ptr(qm);
1002d43ebd9dSPeter Maydell 
1003d43ebd9dSPeter Maydell     rdalo = tcg_temp_new_i32();
1004d43ebd9dSPeter Maydell     rdahi = tcg_temp_new_i32();
1005d43ebd9dSPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
1006d43ebd9dSPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
1007d43ebd9dSPeter Maydell     store_reg(s, a->rdalo, rdalo);
1008d43ebd9dSPeter Maydell     store_reg(s, a->rdahi, rdahi);
1009d43ebd9dSPeter Maydell     tcg_temp_free_i64(rda);
1010d43ebd9dSPeter Maydell     mve_update_eci(s);
1011d43ebd9dSPeter Maydell     return true;
1012d43ebd9dSPeter Maydell }
1013d43ebd9dSPeter Maydell 
1014eab84139SPeter Maydell static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
1015eab84139SPeter Maydell {
1016eab84139SPeter Maydell     TCGv_ptr qd;
1017eab84139SPeter Maydell     uint64_t imm;
1018eab84139SPeter Maydell 
1019eab84139SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
1020eab84139SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
1021eab84139SPeter Maydell         !fn) {
1022eab84139SPeter Maydell         return false;
1023eab84139SPeter Maydell     }
1024eab84139SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1025eab84139SPeter Maydell         return true;
1026eab84139SPeter Maydell     }
1027eab84139SPeter Maydell 
1028eab84139SPeter Maydell     imm = asimd_imm_const(a->imm, a->cmode, a->op);
1029eab84139SPeter Maydell 
1030eab84139SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1031eab84139SPeter Maydell     fn(cpu_env, qd, tcg_constant_i64(imm));
1032eab84139SPeter Maydell     tcg_temp_free_ptr(qd);
1033eab84139SPeter Maydell     mve_update_eci(s);
1034eab84139SPeter Maydell     return true;
1035eab84139SPeter Maydell }
1036eab84139SPeter Maydell 
1037eab84139SPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
1038eab84139SPeter Maydell {
1039eab84139SPeter Maydell     /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
1040eab84139SPeter Maydell     MVEGenOneOpImmFn *fn;
1041eab84139SPeter Maydell 
1042eab84139SPeter Maydell     if ((a->cmode & 1) && a->cmode < 12) {
1043eab84139SPeter Maydell         if (a->op) {
1044eab84139SPeter Maydell             /*
1045eab84139SPeter Maydell              * For op=1, the immediate will be inverted by asimd_imm_const(),
1046eab84139SPeter Maydell              * so the VBIC becomes a logical AND operation.
1047eab84139SPeter Maydell              */
1048eab84139SPeter Maydell             fn = gen_helper_mve_vandi;
1049eab84139SPeter Maydell         } else {
1050eab84139SPeter Maydell             fn = gen_helper_mve_vorri;
1051eab84139SPeter Maydell         }
1052eab84139SPeter Maydell     } else {
1053eab84139SPeter Maydell         /* There is one unallocated cmode/op combination in this space */
1054eab84139SPeter Maydell         if (a->cmode == 15 && a->op == 1) {
1055eab84139SPeter Maydell             return false;
1056eab84139SPeter Maydell         }
1057eab84139SPeter Maydell         /* asimd_imm_const() sorts out VMVNI vs VMOVI for us */
1058eab84139SPeter Maydell         fn = gen_helper_mve_vmovi;
1059eab84139SPeter Maydell     }
1060eab84139SPeter Maydell     return do_1imm(s, a, fn);
1061eab84139SPeter Maydell }
1062f9ed6174SPeter Maydell 
1063f9ed6174SPeter Maydell static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
1064f9ed6174SPeter Maydell                       bool negateshift)
1065f9ed6174SPeter Maydell {
1066f9ed6174SPeter Maydell     TCGv_ptr qd, qm;
1067f9ed6174SPeter Maydell     int shift = a->shift;
1068f9ed6174SPeter Maydell 
1069f9ed6174SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
1070f9ed6174SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
1071f9ed6174SPeter Maydell         !fn) {
1072f9ed6174SPeter Maydell         return false;
1073f9ed6174SPeter Maydell     }
1074f9ed6174SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1075f9ed6174SPeter Maydell         return true;
1076f9ed6174SPeter Maydell     }
1077f9ed6174SPeter Maydell 
1078f9ed6174SPeter Maydell     /*
1079f9ed6174SPeter Maydell      * When we handle a right shift insn using a left-shift helper
1080f9ed6174SPeter Maydell      * which permits a negative shift count to indicate a right-shift,
1081f9ed6174SPeter Maydell      * we must negate the shift count.
1082f9ed6174SPeter Maydell      */
1083f9ed6174SPeter Maydell     if (negateshift) {
1084f9ed6174SPeter Maydell         shift = -shift;
1085f9ed6174SPeter Maydell     }
1086f9ed6174SPeter Maydell 
1087f9ed6174SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1088f9ed6174SPeter Maydell     qm = mve_qreg_ptr(a->qm);
1089f9ed6174SPeter Maydell     fn(cpu_env, qd, qm, tcg_constant_i32(shift));
1090f9ed6174SPeter Maydell     tcg_temp_free_ptr(qd);
1091f9ed6174SPeter Maydell     tcg_temp_free_ptr(qm);
1092f9ed6174SPeter Maydell     mve_update_eci(s);
1093f9ed6174SPeter Maydell     return true;
1094f9ed6174SPeter Maydell }
1095f9ed6174SPeter Maydell 
1096f9ed6174SPeter Maydell #define DO_2SHIFT(INSN, FN, NEGATESHIFT)                         \
1097f9ed6174SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1098f9ed6174SPeter Maydell     {                                                           \
1099f9ed6174SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1100f9ed6174SPeter Maydell             gen_helper_mve_##FN##b,                             \
1101f9ed6174SPeter Maydell             gen_helper_mve_##FN##h,                             \
1102f9ed6174SPeter Maydell             gen_helper_mve_##FN##w,                             \
1103f9ed6174SPeter Maydell             NULL,                                               \
1104f9ed6174SPeter Maydell         };                                                      \
1105f9ed6174SPeter Maydell         return do_2shift(s, a, fns[a->size], NEGATESHIFT);      \
1106f9ed6174SPeter Maydell     }
1107f9ed6174SPeter Maydell 
1108f9ed6174SPeter Maydell DO_2SHIFT(VSHLI, vshli_u, false)
1109f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_S, vqshli_s, false)
1110f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_U, vqshli_u, false)
1111f9ed6174SPeter Maydell DO_2SHIFT(VQSHLUI, vqshlui_s, false)
11123394116fSPeter Maydell /* These right shifts use a left-shift helper with negated shift count */
11133394116fSPeter Maydell DO_2SHIFT(VSHRI_S, vshli_s, true)
11143394116fSPeter Maydell DO_2SHIFT(VSHRI_U, vshli_u, true)
11153394116fSPeter Maydell DO_2SHIFT(VRSHRI_S, vrshli_s, true)
11163394116fSPeter Maydell DO_2SHIFT(VRSHRI_U, vrshli_u, true)
1117c2262707SPeter Maydell 
1118a78b25faSPeter Maydell DO_2SHIFT(VSRI, vsri, false)
1119a78b25faSPeter Maydell DO_2SHIFT(VSLI, vsli, false)
1120a78b25faSPeter Maydell 
11211b15a97dSPeter Maydell static bool do_2shift_scalar(DisasContext *s, arg_shl_scalar *a,
11221b15a97dSPeter Maydell                              MVEGenTwoOpShiftFn *fn)
11231b15a97dSPeter Maydell {
11241b15a97dSPeter Maydell     TCGv_ptr qda;
11251b15a97dSPeter Maydell     TCGv_i32 rm;
11261b15a97dSPeter Maydell 
11271b15a97dSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
11281b15a97dSPeter Maydell         !mve_check_qreg_bank(s, a->qda) ||
11291b15a97dSPeter Maydell         a->rm == 13 || a->rm == 15 || !fn) {
11301b15a97dSPeter Maydell         /* Rm cases are UNPREDICTABLE */
11311b15a97dSPeter Maydell         return false;
11321b15a97dSPeter Maydell     }
11331b15a97dSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
11341b15a97dSPeter Maydell         return true;
11351b15a97dSPeter Maydell     }
11361b15a97dSPeter Maydell 
11371b15a97dSPeter Maydell     qda = mve_qreg_ptr(a->qda);
11381b15a97dSPeter Maydell     rm = load_reg(s, a->rm);
11391b15a97dSPeter Maydell     fn(cpu_env, qda, qda, rm);
11401b15a97dSPeter Maydell     tcg_temp_free_ptr(qda);
11411b15a97dSPeter Maydell     tcg_temp_free_i32(rm);
11421b15a97dSPeter Maydell     mve_update_eci(s);
11431b15a97dSPeter Maydell     return true;
11441b15a97dSPeter Maydell }
11451b15a97dSPeter Maydell 
11461b15a97dSPeter Maydell #define DO_2SHIFT_SCALAR(INSN, FN)                                      \
11471b15a97dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_shl_scalar *a)        \
11481b15a97dSPeter Maydell     {                                                                   \
11491b15a97dSPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {                     \
11501b15a97dSPeter Maydell             gen_helper_mve_##FN##b,                                     \
11511b15a97dSPeter Maydell             gen_helper_mve_##FN##h,                                     \
11521b15a97dSPeter Maydell             gen_helper_mve_##FN##w,                                     \
11531b15a97dSPeter Maydell             NULL,                                                       \
11541b15a97dSPeter Maydell         };                                                              \
11551b15a97dSPeter Maydell         return do_2shift_scalar(s, a, fns[a->size]);                    \
11561b15a97dSPeter Maydell     }
11571b15a97dSPeter Maydell 
11581b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VSHL_S_scalar, vshli_s)
11591b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VSHL_U_scalar, vshli_u)
11601b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VRSHL_S_scalar, vrshli_s)
11611b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VRSHL_U_scalar, vrshli_u)
11621b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQSHL_S_scalar, vqshli_s)
11631b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQSHL_U_scalar, vqshli_u)
11641b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQRSHL_S_scalar, vqrshli_s)
11651b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQRSHL_U_scalar, vqrshli_u)
11661b15a97dSPeter Maydell 
1167c2262707SPeter Maydell #define DO_VSHLL(INSN, FN)                                      \
1168c2262707SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1169c2262707SPeter Maydell     {                                                           \
1170c2262707SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1171c2262707SPeter Maydell             gen_helper_mve_##FN##b,                             \
1172c2262707SPeter Maydell             gen_helper_mve_##FN##h,                             \
1173c2262707SPeter Maydell         };                                                      \
1174c2262707SPeter Maydell         return do_2shift(s, a, fns[a->size], false);            \
1175c2262707SPeter Maydell     }
1176c2262707SPeter Maydell 
1177c2262707SPeter Maydell DO_VSHLL(VSHLL_BS, vshllbs)
1178c2262707SPeter Maydell DO_VSHLL(VSHLL_BU, vshllbu)
1179c2262707SPeter Maydell DO_VSHLL(VSHLL_TS, vshllts)
1180c2262707SPeter Maydell DO_VSHLL(VSHLL_TU, vshlltu)
1181162e2655SPeter Maydell 
1182162e2655SPeter Maydell #define DO_2SHIFT_N(INSN, FN)                                   \
1183162e2655SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1184162e2655SPeter Maydell     {                                                           \
1185162e2655SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1186162e2655SPeter Maydell             gen_helper_mve_##FN##b,                             \
1187162e2655SPeter Maydell             gen_helper_mve_##FN##h,                             \
1188162e2655SPeter Maydell         };                                                      \
1189162e2655SPeter Maydell         return do_2shift(s, a, fns[a->size], false);            \
1190162e2655SPeter Maydell     }
1191162e2655SPeter Maydell 
1192162e2655SPeter Maydell DO_2SHIFT_N(VSHRNB, vshrnb)
1193162e2655SPeter Maydell DO_2SHIFT_N(VSHRNT, vshrnt)
1194162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNB, vrshrnb)
1195162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNT, vrshrnt)
1196d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_S, vqshrnb_s)
1197d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_S, vqshrnt_s)
1198d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_U, vqshrnb_u)
1199d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_U, vqshrnt_u)
1200d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNB, vqshrunb)
1201d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNT, vqshrunt)
1202d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_S, vqrshrnb_s)
1203d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_S, vqrshrnt_s)
1204d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_U, vqrshrnb_u)
1205d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_U, vqrshrnt_u)
1206d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNB, vqrshrunb)
1207d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNT, vqrshrunt)
12082e6a4ce0SPeter Maydell 
12092e6a4ce0SPeter Maydell static bool trans_VSHLC(DisasContext *s, arg_VSHLC *a)
12102e6a4ce0SPeter Maydell {
12112e6a4ce0SPeter Maydell     /*
12122e6a4ce0SPeter Maydell      * Whole Vector Left Shift with Carry. The carry is taken
12132e6a4ce0SPeter Maydell      * from a general purpose register and written back there.
12142e6a4ce0SPeter Maydell      * An imm of 0 means "shift by 32".
12152e6a4ce0SPeter Maydell      */
12162e6a4ce0SPeter Maydell     TCGv_ptr qd;
12172e6a4ce0SPeter Maydell     TCGv_i32 rdm;
12182e6a4ce0SPeter Maydell 
12192e6a4ce0SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
12202e6a4ce0SPeter Maydell         return false;
12212e6a4ce0SPeter Maydell     }
12222e6a4ce0SPeter Maydell     if (a->rdm == 13 || a->rdm == 15) {
12232e6a4ce0SPeter Maydell         /* CONSTRAINED UNPREDICTABLE: we UNDEF */
12242e6a4ce0SPeter Maydell         return false;
12252e6a4ce0SPeter Maydell     }
12262e6a4ce0SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
12272e6a4ce0SPeter Maydell         return true;
12282e6a4ce0SPeter Maydell     }
12292e6a4ce0SPeter Maydell 
12302e6a4ce0SPeter Maydell     qd = mve_qreg_ptr(a->qd);
12312e6a4ce0SPeter Maydell     rdm = load_reg(s, a->rdm);
12322e6a4ce0SPeter Maydell     gen_helper_mve_vshlc(rdm, cpu_env, qd, rdm, tcg_constant_i32(a->imm));
12332e6a4ce0SPeter Maydell     store_reg(s, a->rdm, rdm);
12342e6a4ce0SPeter Maydell     tcg_temp_free_ptr(qd);
12352e6a4ce0SPeter Maydell     mve_update_eci(s);
12362e6a4ce0SPeter Maydell     return true;
12372e6a4ce0SPeter Maydell }
1238395b92d5SPeter Maydell 
1239395b92d5SPeter Maydell static bool do_vidup(DisasContext *s, arg_vidup *a, MVEGenVIDUPFn *fn)
1240395b92d5SPeter Maydell {
1241395b92d5SPeter Maydell     TCGv_ptr qd;
1242395b92d5SPeter Maydell     TCGv_i32 rn;
1243395b92d5SPeter Maydell 
1244395b92d5SPeter Maydell     /*
1245395b92d5SPeter Maydell      * Vector increment/decrement with wrap and duplicate (VIDUP, VDDUP).
1246395b92d5SPeter Maydell      * This fills the vector with elements of successively increasing
1247395b92d5SPeter Maydell      * or decreasing values, starting from Rn.
1248395b92d5SPeter Maydell      */
1249395b92d5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
1250395b92d5SPeter Maydell         return false;
1251395b92d5SPeter Maydell     }
1252395b92d5SPeter Maydell     if (a->size == MO_64) {
1253395b92d5SPeter Maydell         /* size 0b11 is another encoding */
1254395b92d5SPeter Maydell         return false;
1255395b92d5SPeter Maydell     }
1256395b92d5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1257395b92d5SPeter Maydell         return true;
1258395b92d5SPeter Maydell     }
1259395b92d5SPeter Maydell 
1260395b92d5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1261395b92d5SPeter Maydell     rn = load_reg(s, a->rn);
1262395b92d5SPeter Maydell     fn(rn, cpu_env, qd, rn, tcg_constant_i32(a->imm));
1263395b92d5SPeter Maydell     store_reg(s, a->rn, rn);
1264395b92d5SPeter Maydell     tcg_temp_free_ptr(qd);
1265395b92d5SPeter Maydell     mve_update_eci(s);
1266395b92d5SPeter Maydell     return true;
1267395b92d5SPeter Maydell }
1268395b92d5SPeter Maydell 
1269395b92d5SPeter Maydell static bool do_viwdup(DisasContext *s, arg_viwdup *a, MVEGenVIWDUPFn *fn)
1270395b92d5SPeter Maydell {
1271395b92d5SPeter Maydell     TCGv_ptr qd;
1272395b92d5SPeter Maydell     TCGv_i32 rn, rm;
1273395b92d5SPeter Maydell 
1274395b92d5SPeter Maydell     /*
1275395b92d5SPeter Maydell      * Vector increment/decrement with wrap and duplicate (VIWDUp, VDWDUP)
1276395b92d5SPeter Maydell      * This fills the vector with elements of successively increasing
1277395b92d5SPeter Maydell      * or decreasing values, starting from Rn. Rm specifies a point where
1278395b92d5SPeter Maydell      * the count wraps back around to 0. The updated offset is written back
1279395b92d5SPeter Maydell      * to Rn.
1280395b92d5SPeter Maydell      */
1281395b92d5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
1282395b92d5SPeter Maydell         return false;
1283395b92d5SPeter Maydell     }
1284395b92d5SPeter Maydell     if (!fn || a->rm == 13 || a->rm == 15) {
1285395b92d5SPeter Maydell         /*
1286395b92d5SPeter Maydell          * size 0b11 is another encoding; Rm == 13 is UNPREDICTABLE;
1287395b92d5SPeter Maydell          * Rm == 13 is VIWDUP, VDWDUP.
1288395b92d5SPeter Maydell          */
1289395b92d5SPeter Maydell         return false;
1290395b92d5SPeter Maydell     }
1291395b92d5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1292395b92d5SPeter Maydell         return true;
1293395b92d5SPeter Maydell     }
1294395b92d5SPeter Maydell 
1295395b92d5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1296395b92d5SPeter Maydell     rn = load_reg(s, a->rn);
1297395b92d5SPeter Maydell     rm = load_reg(s, a->rm);
1298395b92d5SPeter Maydell     fn(rn, cpu_env, qd, rn, rm, tcg_constant_i32(a->imm));
1299395b92d5SPeter Maydell     store_reg(s, a->rn, rn);
1300395b92d5SPeter Maydell     tcg_temp_free_ptr(qd);
1301395b92d5SPeter Maydell     tcg_temp_free_i32(rm);
1302395b92d5SPeter Maydell     mve_update_eci(s);
1303395b92d5SPeter Maydell     return true;
1304395b92d5SPeter Maydell }
1305395b92d5SPeter Maydell 
1306395b92d5SPeter Maydell static bool trans_VIDUP(DisasContext *s, arg_vidup *a)
1307395b92d5SPeter Maydell {
1308395b92d5SPeter Maydell     static MVEGenVIDUPFn * const fns[] = {
1309395b92d5SPeter Maydell         gen_helper_mve_vidupb,
1310395b92d5SPeter Maydell         gen_helper_mve_viduph,
1311395b92d5SPeter Maydell         gen_helper_mve_vidupw,
1312395b92d5SPeter Maydell         NULL,
1313395b92d5SPeter Maydell     };
1314395b92d5SPeter Maydell     return do_vidup(s, a, fns[a->size]);
1315395b92d5SPeter Maydell }
1316395b92d5SPeter Maydell 
1317395b92d5SPeter Maydell static bool trans_VDDUP(DisasContext *s, arg_vidup *a)
1318395b92d5SPeter Maydell {
1319395b92d5SPeter Maydell     static MVEGenVIDUPFn * const fns[] = {
1320395b92d5SPeter Maydell         gen_helper_mve_vidupb,
1321395b92d5SPeter Maydell         gen_helper_mve_viduph,
1322395b92d5SPeter Maydell         gen_helper_mve_vidupw,
1323395b92d5SPeter Maydell         NULL,
1324395b92d5SPeter Maydell     };
1325395b92d5SPeter Maydell     /* VDDUP is just like VIDUP but with a negative immediate */
1326395b92d5SPeter Maydell     a->imm = -a->imm;
1327395b92d5SPeter Maydell     return do_vidup(s, a, fns[a->size]);
1328395b92d5SPeter Maydell }
1329395b92d5SPeter Maydell 
1330395b92d5SPeter Maydell static bool trans_VIWDUP(DisasContext *s, arg_viwdup *a)
1331395b92d5SPeter Maydell {
1332395b92d5SPeter Maydell     static MVEGenVIWDUPFn * const fns[] = {
1333395b92d5SPeter Maydell         gen_helper_mve_viwdupb,
1334395b92d5SPeter Maydell         gen_helper_mve_viwduph,
1335395b92d5SPeter Maydell         gen_helper_mve_viwdupw,
1336395b92d5SPeter Maydell         NULL,
1337395b92d5SPeter Maydell     };
1338395b92d5SPeter Maydell     return do_viwdup(s, a, fns[a->size]);
1339395b92d5SPeter Maydell }
1340395b92d5SPeter Maydell 
1341395b92d5SPeter Maydell static bool trans_VDWDUP(DisasContext *s, arg_viwdup *a)
1342395b92d5SPeter Maydell {
1343395b92d5SPeter Maydell     static MVEGenVIWDUPFn * const fns[] = {
1344395b92d5SPeter Maydell         gen_helper_mve_vdwdupb,
1345395b92d5SPeter Maydell         gen_helper_mve_vdwduph,
1346395b92d5SPeter Maydell         gen_helper_mve_vdwdupw,
1347395b92d5SPeter Maydell         NULL,
1348395b92d5SPeter Maydell     };
1349395b92d5SPeter Maydell     return do_viwdup(s, a, fns[a->size]);
1350395b92d5SPeter Maydell }
1351eff5d9a9SPeter Maydell 
1352eff5d9a9SPeter Maydell static bool do_vcmp(DisasContext *s, arg_vcmp *a, MVEGenCmpFn *fn)
1353eff5d9a9SPeter Maydell {
1354eff5d9a9SPeter Maydell     TCGv_ptr qn, qm;
1355eff5d9a9SPeter Maydell 
1356eff5d9a9SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qm) ||
1357eff5d9a9SPeter Maydell         !fn) {
1358eff5d9a9SPeter Maydell         return false;
1359eff5d9a9SPeter Maydell     }
1360eff5d9a9SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1361eff5d9a9SPeter Maydell         return true;
1362eff5d9a9SPeter Maydell     }
1363eff5d9a9SPeter Maydell 
1364eff5d9a9SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1365eff5d9a9SPeter Maydell     qm = mve_qreg_ptr(a->qm);
1366eff5d9a9SPeter Maydell     fn(cpu_env, qn, qm);
1367eff5d9a9SPeter Maydell     tcg_temp_free_ptr(qn);
1368eff5d9a9SPeter Maydell     tcg_temp_free_ptr(qm);
1369eff5d9a9SPeter Maydell     if (a->mask) {
1370eff5d9a9SPeter Maydell         /* VPT */
1371eff5d9a9SPeter Maydell         gen_vpst(s, a->mask);
1372eff5d9a9SPeter Maydell     }
1373eff5d9a9SPeter Maydell     mve_update_eci(s);
1374eff5d9a9SPeter Maydell     return true;
1375eff5d9a9SPeter Maydell }
1376eff5d9a9SPeter Maydell 
1377cce81873SPeter Maydell static bool do_vcmp_scalar(DisasContext *s, arg_vcmp_scalar *a,
1378cce81873SPeter Maydell                            MVEGenScalarCmpFn *fn)
1379cce81873SPeter Maydell {
1380cce81873SPeter Maydell     TCGv_ptr qn;
1381cce81873SPeter Maydell     TCGv_i32 rm;
1382cce81873SPeter Maydell 
1383cce81873SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !fn || a->rm == 13) {
1384cce81873SPeter Maydell         return false;
1385cce81873SPeter Maydell     }
1386cce81873SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1387cce81873SPeter Maydell         return true;
1388cce81873SPeter Maydell     }
1389cce81873SPeter Maydell 
1390cce81873SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1391cce81873SPeter Maydell     if (a->rm == 15) {
1392cce81873SPeter Maydell         /* Encoding Rm=0b1111 means "constant zero" */
1393cce81873SPeter Maydell         rm = tcg_constant_i32(0);
1394cce81873SPeter Maydell     } else {
1395cce81873SPeter Maydell         rm = load_reg(s, a->rm);
1396cce81873SPeter Maydell     }
1397cce81873SPeter Maydell     fn(cpu_env, qn, rm);
1398cce81873SPeter Maydell     tcg_temp_free_ptr(qn);
1399cce81873SPeter Maydell     tcg_temp_free_i32(rm);
1400cce81873SPeter Maydell     if (a->mask) {
1401cce81873SPeter Maydell         /* VPT */
1402cce81873SPeter Maydell         gen_vpst(s, a->mask);
1403cce81873SPeter Maydell     }
1404cce81873SPeter Maydell     mve_update_eci(s);
1405cce81873SPeter Maydell     return true;
1406cce81873SPeter Maydell }
1407cce81873SPeter Maydell 
1408eff5d9a9SPeter Maydell #define DO_VCMP(INSN, FN)                                       \
1409eff5d9a9SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vcmp *a)      \
1410eff5d9a9SPeter Maydell     {                                                           \
1411eff5d9a9SPeter Maydell         static MVEGenCmpFn * const fns[] = {                    \
1412eff5d9a9SPeter Maydell             gen_helper_mve_##FN##b,                             \
1413eff5d9a9SPeter Maydell             gen_helper_mve_##FN##h,                             \
1414eff5d9a9SPeter Maydell             gen_helper_mve_##FN##w,                             \
1415eff5d9a9SPeter Maydell             NULL,                                               \
1416eff5d9a9SPeter Maydell         };                                                      \
1417eff5d9a9SPeter Maydell         return do_vcmp(s, a, fns[a->size]);                     \
1418cce81873SPeter Maydell     }                                                           \
1419cce81873SPeter Maydell     static bool trans_##INSN##_scalar(DisasContext *s,          \
1420cce81873SPeter Maydell                                       arg_vcmp_scalar *a)       \
1421cce81873SPeter Maydell     {                                                           \
1422cce81873SPeter Maydell         static MVEGenScalarCmpFn * const fns[] = {              \
1423cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarb,                      \
1424cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarh,                      \
1425cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarw,                      \
1426cce81873SPeter Maydell             NULL,                                               \
1427cce81873SPeter Maydell         };                                                      \
1428cce81873SPeter Maydell         return do_vcmp_scalar(s, a, fns[a->size]);              \
1429eff5d9a9SPeter Maydell     }
1430eff5d9a9SPeter Maydell 
1431eff5d9a9SPeter Maydell DO_VCMP(VCMPEQ, vcmpeq)
1432eff5d9a9SPeter Maydell DO_VCMP(VCMPNE, vcmpne)
1433eff5d9a9SPeter Maydell DO_VCMP(VCMPCS, vcmpcs)
1434eff5d9a9SPeter Maydell DO_VCMP(VCMPHI, vcmphi)
1435eff5d9a9SPeter Maydell DO_VCMP(VCMPGE, vcmpge)
1436eff5d9a9SPeter Maydell DO_VCMP(VCMPLT, vcmplt)
1437eff5d9a9SPeter Maydell DO_VCMP(VCMPGT, vcmpgt)
1438eff5d9a9SPeter Maydell DO_VCMP(VCMPLE, vcmple)
1439688ba4cfSPeter Maydell 
1440688ba4cfSPeter Maydell static bool do_vmaxv(DisasContext *s, arg_vmaxv *a, MVEGenVADDVFn fn)
1441688ba4cfSPeter Maydell {
1442688ba4cfSPeter Maydell     /*
1443688ba4cfSPeter Maydell      * MIN/MAX operations across a vector: compute the min or
1444688ba4cfSPeter Maydell      * max of the initial value in a general purpose register
1445688ba4cfSPeter Maydell      * and all the elements in the vector, and store it back
1446688ba4cfSPeter Maydell      * into the general purpose register.
1447688ba4cfSPeter Maydell      */
1448688ba4cfSPeter Maydell     TCGv_ptr qm;
1449688ba4cfSPeter Maydell     TCGv_i32 rda;
1450688ba4cfSPeter Maydell 
1451688ba4cfSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qm) ||
1452688ba4cfSPeter Maydell         !fn || a->rda == 13 || a->rda == 15) {
1453688ba4cfSPeter Maydell         /* Rda cases are UNPREDICTABLE */
1454688ba4cfSPeter Maydell         return false;
1455688ba4cfSPeter Maydell     }
1456688ba4cfSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1457688ba4cfSPeter Maydell         return true;
1458688ba4cfSPeter Maydell     }
1459688ba4cfSPeter Maydell 
1460688ba4cfSPeter Maydell     qm = mve_qreg_ptr(a->qm);
1461688ba4cfSPeter Maydell     rda = load_reg(s, a->rda);
1462688ba4cfSPeter Maydell     fn(rda, cpu_env, qm, rda);
1463688ba4cfSPeter Maydell     store_reg(s, a->rda, rda);
1464688ba4cfSPeter Maydell     tcg_temp_free_ptr(qm);
1465688ba4cfSPeter Maydell     mve_update_eci(s);
1466688ba4cfSPeter Maydell     return true;
1467688ba4cfSPeter Maydell }
1468688ba4cfSPeter Maydell 
1469688ba4cfSPeter Maydell #define DO_VMAXV(INSN, FN)                                      \
1470688ba4cfSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vmaxv *a)     \
1471688ba4cfSPeter Maydell     {                                                           \
1472688ba4cfSPeter Maydell         static MVEGenVADDVFn * const fns[] = {                  \
1473688ba4cfSPeter Maydell             gen_helper_mve_##FN##b,                             \
1474688ba4cfSPeter Maydell             gen_helper_mve_##FN##h,                             \
1475688ba4cfSPeter Maydell             gen_helper_mve_##FN##w,                             \
1476688ba4cfSPeter Maydell             NULL,                                               \
1477688ba4cfSPeter Maydell         };                                                      \
1478688ba4cfSPeter Maydell         return do_vmaxv(s, a, fns[a->size]);                    \
1479688ba4cfSPeter Maydell     }
1480688ba4cfSPeter Maydell 
1481688ba4cfSPeter Maydell DO_VMAXV(VMAXV_S, vmaxvs)
1482688ba4cfSPeter Maydell DO_VMAXV(VMAXV_U, vmaxvu)
1483688ba4cfSPeter Maydell DO_VMAXV(VMAXAV, vmaxav)
1484688ba4cfSPeter Maydell DO_VMAXV(VMINV_S, vminvs)
1485688ba4cfSPeter Maydell DO_VMAXV(VMINV_U, vminvu)
1486688ba4cfSPeter Maydell DO_VMAXV(VMINAV, vminav)
14877f061c0aSPeter Maydell 
14887f061c0aSPeter Maydell static bool do_vabav(DisasContext *s, arg_vabav *a, MVEGenVABAVFn *fn)
14897f061c0aSPeter Maydell {
14907f061c0aSPeter Maydell     /* Absolute difference accumulated across vector */
14917f061c0aSPeter Maydell     TCGv_ptr qn, qm;
14927f061c0aSPeter Maydell     TCGv_i32 rda;
14937f061c0aSPeter Maydell 
14947f061c0aSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
14957f061c0aSPeter Maydell         !mve_check_qreg_bank(s, a->qm | a->qn) ||
14967f061c0aSPeter Maydell         !fn || a->rda == 13 || a->rda == 15) {
14977f061c0aSPeter Maydell         /* Rda cases are UNPREDICTABLE */
14987f061c0aSPeter Maydell         return false;
14997f061c0aSPeter Maydell     }
15007f061c0aSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
15017f061c0aSPeter Maydell         return true;
15027f061c0aSPeter Maydell     }
15037f061c0aSPeter Maydell 
15047f061c0aSPeter Maydell     qm = mve_qreg_ptr(a->qm);
15057f061c0aSPeter Maydell     qn = mve_qreg_ptr(a->qn);
15067f061c0aSPeter Maydell     rda = load_reg(s, a->rda);
15077f061c0aSPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
15087f061c0aSPeter Maydell     store_reg(s, a->rda, rda);
15097f061c0aSPeter Maydell     tcg_temp_free_ptr(qm);
15107f061c0aSPeter Maydell     tcg_temp_free_ptr(qn);
15117f061c0aSPeter Maydell     mve_update_eci(s);
15127f061c0aSPeter Maydell     return true;
15137f061c0aSPeter Maydell }
15147f061c0aSPeter Maydell 
15157f061c0aSPeter Maydell #define DO_VABAV(INSN, FN)                                      \
15167f061c0aSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vabav *a)     \
15177f061c0aSPeter Maydell     {                                                           \
15187f061c0aSPeter Maydell         static MVEGenVABAVFn * const fns[] = {                  \
15197f061c0aSPeter Maydell             gen_helper_mve_##FN##b,                             \
15207f061c0aSPeter Maydell             gen_helper_mve_##FN##h,                             \
15217f061c0aSPeter Maydell             gen_helper_mve_##FN##w,                             \
15227f061c0aSPeter Maydell             NULL,                                               \
15237f061c0aSPeter Maydell         };                                                      \
15247f061c0aSPeter Maydell         return do_vabav(s, a, fns[a->size]);                    \
15257f061c0aSPeter Maydell     }
15267f061c0aSPeter Maydell 
15277f061c0aSPeter Maydell DO_VABAV(VABAV_S, vabavs)
15287f061c0aSPeter Maydell DO_VABAV(VABAV_U, vabavu)
15291241f148SPeter Maydell 
15301241f148SPeter Maydell static bool trans_VMOV_to_2gp(DisasContext *s, arg_VMOV_to_2gp *a)
15311241f148SPeter Maydell {
15321241f148SPeter Maydell     /*
15331241f148SPeter Maydell      * VMOV two 32-bit vector lanes to two general-purpose registers.
15341241f148SPeter Maydell      * This insn is not predicated but it is subject to beat-wise
15351241f148SPeter Maydell      * execution if it is not in an IT block. For us this means
15361241f148SPeter Maydell      * only that if PSR.ECI says we should not be executing the beat
15371241f148SPeter Maydell      * corresponding to the lane of the vector register being accessed
15381241f148SPeter Maydell      * then we should skip perfoming the move, and that we need to do
15391241f148SPeter Maydell      * the usual check for bad ECI state and advance of ECI state.
15401241f148SPeter Maydell      * (If PSR.ECI is non-zero then we cannot be in an IT block.)
15411241f148SPeter Maydell      */
15421241f148SPeter Maydell     TCGv_i32 tmp;
15431241f148SPeter Maydell     int vd;
15441241f148SPeter Maydell 
15451241f148SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd) ||
15461241f148SPeter Maydell         a->rt == 13 || a->rt == 15 || a->rt2 == 13 || a->rt2 == 15 ||
15471241f148SPeter Maydell         a->rt == a->rt2) {
15481241f148SPeter Maydell         /* Rt/Rt2 cases are UNPREDICTABLE */
15491241f148SPeter Maydell         return false;
15501241f148SPeter Maydell     }
15511241f148SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
15521241f148SPeter Maydell         return true;
15531241f148SPeter Maydell     }
15541241f148SPeter Maydell 
15551241f148SPeter Maydell     /* Convert Qreg index to Dreg for read_neon_element32() etc */
15561241f148SPeter Maydell     vd = a->qd * 2;
15571241f148SPeter Maydell 
15581241f148SPeter Maydell     if (!mve_skip_vmov(s, vd, a->idx, MO_32)) {
15591241f148SPeter Maydell         tmp = tcg_temp_new_i32();
15601241f148SPeter Maydell         read_neon_element32(tmp, vd, a->idx, MO_32);
15611241f148SPeter Maydell         store_reg(s, a->rt, tmp);
15621241f148SPeter Maydell     }
15631241f148SPeter Maydell     if (!mve_skip_vmov(s, vd + 1, a->idx, MO_32)) {
15641241f148SPeter Maydell         tmp = tcg_temp_new_i32();
15651241f148SPeter Maydell         read_neon_element32(tmp, vd + 1, a->idx, MO_32);
15661241f148SPeter Maydell         store_reg(s, a->rt2, tmp);
15671241f148SPeter Maydell     }
15681241f148SPeter Maydell 
15691241f148SPeter Maydell     mve_update_and_store_eci(s);
15701241f148SPeter Maydell     return true;
15711241f148SPeter Maydell }
15721241f148SPeter Maydell 
15731241f148SPeter Maydell static bool trans_VMOV_from_2gp(DisasContext *s, arg_VMOV_to_2gp *a)
15741241f148SPeter Maydell {
15751241f148SPeter Maydell     /*
15761241f148SPeter Maydell      * VMOV two general-purpose registers to two 32-bit vector lanes.
15771241f148SPeter Maydell      * This insn is not predicated but it is subject to beat-wise
15781241f148SPeter Maydell      * execution if it is not in an IT block. For us this means
15791241f148SPeter Maydell      * only that if PSR.ECI says we should not be executing the beat
15801241f148SPeter Maydell      * corresponding to the lane of the vector register being accessed
15811241f148SPeter Maydell      * then we should skip perfoming the move, and that we need to do
15821241f148SPeter Maydell      * the usual check for bad ECI state and advance of ECI state.
15831241f148SPeter Maydell      * (If PSR.ECI is non-zero then we cannot be in an IT block.)
15841241f148SPeter Maydell      */
15851241f148SPeter Maydell     TCGv_i32 tmp;
15861241f148SPeter Maydell     int vd;
15871241f148SPeter Maydell 
15881241f148SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd) ||
15891241f148SPeter Maydell         a->rt == 13 || a->rt == 15 || a->rt2 == 13 || a->rt2 == 15) {
15901241f148SPeter Maydell         /* Rt/Rt2 cases are UNPREDICTABLE */
15911241f148SPeter Maydell         return false;
15921241f148SPeter Maydell     }
15931241f148SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
15941241f148SPeter Maydell         return true;
15951241f148SPeter Maydell     }
15961241f148SPeter Maydell 
15971241f148SPeter Maydell     /* Convert Qreg idx to Dreg for read_neon_element32() etc */
15981241f148SPeter Maydell     vd = a->qd * 2;
15991241f148SPeter Maydell 
16001241f148SPeter Maydell     if (!mve_skip_vmov(s, vd, a->idx, MO_32)) {
16011241f148SPeter Maydell         tmp = load_reg(s, a->rt);
16021241f148SPeter Maydell         write_neon_element32(tmp, vd, a->idx, MO_32);
16031241f148SPeter Maydell         tcg_temp_free_i32(tmp);
16041241f148SPeter Maydell     }
16051241f148SPeter Maydell     if (!mve_skip_vmov(s, vd + 1, a->idx, MO_32)) {
16061241f148SPeter Maydell         tmp = load_reg(s, a->rt2);
16071241f148SPeter Maydell         write_neon_element32(tmp, vd + 1, a->idx, MO_32);
16081241f148SPeter Maydell         tcg_temp_free_i32(tmp);
16091241f148SPeter Maydell     }
16101241f148SPeter Maydell 
16111241f148SPeter Maydell     mve_update_and_store_eci(s);
16121241f148SPeter Maydell     return true;
16131241f148SPeter Maydell }
1614