xref: /qemu/target/arm/tcg/translate-mve.c (revision c69e34c6debfb567f6118b59e6efa96a20765dda)
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)
278249b5309SPeter Maydell 
27954dc78a9SPeter Maydell /* Narrowing moves: only size 0 and 1 are valid */
28054dc78a9SPeter Maydell #define DO_VMOVN(INSN, FN) \
28154dc78a9SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
28254dc78a9SPeter Maydell     {                                                           \
28354dc78a9SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
28454dc78a9SPeter Maydell             gen_helper_mve_##FN##b,                             \
28554dc78a9SPeter Maydell             gen_helper_mve_##FN##h,                             \
28654dc78a9SPeter Maydell             NULL,                                               \
28754dc78a9SPeter Maydell             NULL,                                               \
28854dc78a9SPeter Maydell         };                                                      \
28954dc78a9SPeter Maydell         return do_1op(s, a, fns[a->size]);                      \
29054dc78a9SPeter Maydell     }
29154dc78a9SPeter Maydell 
29254dc78a9SPeter Maydell DO_VMOVN(VMOVNB, vmovnb)
29354dc78a9SPeter Maydell DO_VMOVN(VMOVNT, vmovnt)
29454dc78a9SPeter Maydell DO_VMOVN(VQMOVUNB, vqmovunb)
29554dc78a9SPeter Maydell DO_VMOVN(VQMOVUNT, vqmovunt)
29654dc78a9SPeter Maydell DO_VMOVN(VQMOVN_BS, vqmovnbs)
29754dc78a9SPeter Maydell DO_VMOVN(VQMOVN_TS, vqmovnts)
29854dc78a9SPeter Maydell DO_VMOVN(VQMOVN_BU, vqmovnbu)
29954dc78a9SPeter Maydell DO_VMOVN(VQMOVN_TU, vqmovntu)
30054dc78a9SPeter Maydell 
301249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a)
302249b5309SPeter Maydell {
303249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
304249b5309SPeter Maydell         gen_helper_mve_vrev16b,
305249b5309SPeter Maydell         NULL,
306249b5309SPeter Maydell         NULL,
307249b5309SPeter Maydell         NULL,
308249b5309SPeter Maydell     };
309249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
310249b5309SPeter Maydell }
311249b5309SPeter Maydell 
312249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a)
313249b5309SPeter Maydell {
314249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
315249b5309SPeter Maydell         gen_helper_mve_vrev32b,
316249b5309SPeter Maydell         gen_helper_mve_vrev32h,
317249b5309SPeter Maydell         NULL,
318249b5309SPeter Maydell         NULL,
319249b5309SPeter Maydell     };
320249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
321249b5309SPeter Maydell }
322249b5309SPeter Maydell 
323249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a)
324249b5309SPeter Maydell {
325249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
326249b5309SPeter Maydell         gen_helper_mve_vrev64b,
327249b5309SPeter Maydell         gen_helper_mve_vrev64h,
328249b5309SPeter Maydell         gen_helper_mve_vrev64w,
329249b5309SPeter Maydell         NULL,
330249b5309SPeter Maydell     };
331249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
332249b5309SPeter Maydell }
3338abd3c80SPeter Maydell 
3348abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a)
3358abd3c80SPeter Maydell {
3368abd3c80SPeter Maydell     return do_1op(s, a, gen_helper_mve_vmvn);
3378abd3c80SPeter Maydell }
33859c91773SPeter Maydell 
33959c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a)
34059c91773SPeter Maydell {
34159c91773SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
34259c91773SPeter Maydell         NULL,
34359c91773SPeter Maydell         gen_helper_mve_vfabsh,
34459c91773SPeter Maydell         gen_helper_mve_vfabss,
34559c91773SPeter Maydell         NULL,
34659c91773SPeter Maydell     };
34759c91773SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
34859c91773SPeter Maydell         return false;
34959c91773SPeter Maydell     }
35059c91773SPeter Maydell     return do_1op(s, a, fns[a->size]);
35159c91773SPeter Maydell }
352399a8c76SPeter Maydell 
353399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a)
354399a8c76SPeter Maydell {
355399a8c76SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
356399a8c76SPeter Maydell         NULL,
357399a8c76SPeter Maydell         gen_helper_mve_vfnegh,
358399a8c76SPeter Maydell         gen_helper_mve_vfnegs,
359399a8c76SPeter Maydell         NULL,
360399a8c76SPeter Maydell     };
361399a8c76SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
362399a8c76SPeter Maydell         return false;
363399a8c76SPeter Maydell     }
364399a8c76SPeter Maydell     return do_1op(s, a, fns[a->size]);
365399a8c76SPeter Maydell }
36668245e44SPeter Maydell 
36768245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
36868245e44SPeter Maydell {
36968245e44SPeter Maydell     TCGv_ptr qd, qn, qm;
37068245e44SPeter Maydell 
37168245e44SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
37268245e44SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) ||
37368245e44SPeter Maydell         !fn) {
37468245e44SPeter Maydell         return false;
37568245e44SPeter Maydell     }
37668245e44SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
37768245e44SPeter Maydell         return true;
37868245e44SPeter Maydell     }
37968245e44SPeter Maydell 
38068245e44SPeter Maydell     qd = mve_qreg_ptr(a->qd);
38168245e44SPeter Maydell     qn = mve_qreg_ptr(a->qn);
38268245e44SPeter Maydell     qm = mve_qreg_ptr(a->qm);
38368245e44SPeter Maydell     fn(cpu_env, qd, qn, qm);
38468245e44SPeter Maydell     tcg_temp_free_ptr(qd);
38568245e44SPeter Maydell     tcg_temp_free_ptr(qn);
38668245e44SPeter Maydell     tcg_temp_free_ptr(qm);
38768245e44SPeter Maydell     mve_update_eci(s);
38868245e44SPeter Maydell     return true;
38968245e44SPeter Maydell }
39068245e44SPeter Maydell 
39168245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER)                                  \
39268245e44SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
39368245e44SPeter Maydell     {                                                           \
39468245e44SPeter Maydell         return do_2op(s, a, HELPER);                            \
39568245e44SPeter Maydell     }
39668245e44SPeter Maydell 
39768245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand)
39868245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic)
39968245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr)
40068245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn)
40168245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor)
4029333fe4dSPeter Maydell 
403c386443bSPeter Maydell DO_LOGIC(VPSEL, gen_helper_mve_vpsel)
404c386443bSPeter Maydell 
4059333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \
4069333fe4dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
4079333fe4dSPeter Maydell     {                                                           \
4089333fe4dSPeter Maydell         static MVEGenTwoOpFn * const fns[] = {                  \
4099333fe4dSPeter Maydell             gen_helper_mve_##FN##b,                             \
4109333fe4dSPeter Maydell             gen_helper_mve_##FN##h,                             \
4119333fe4dSPeter Maydell             gen_helper_mve_##FN##w,                             \
4129333fe4dSPeter Maydell             NULL,                                               \
4139333fe4dSPeter Maydell         };                                                      \
4149333fe4dSPeter Maydell         return do_2op(s, a, fns[a->size]);                      \
4159333fe4dSPeter Maydell     }
4169333fe4dSPeter Maydell 
4179333fe4dSPeter Maydell DO_2OP(VADD, vadd)
4189333fe4dSPeter Maydell DO_2OP(VSUB, vsub)
4199333fe4dSPeter Maydell DO_2OP(VMUL, vmul)
420ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs)
421ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu)
422fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs)
423fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu)
424cd367ff3SPeter Maydell DO_2OP(VMAX_S, vmaxs)
425cd367ff3SPeter Maydell DO_2OP(VMAX_U, vmaxu)
426cd367ff3SPeter Maydell DO_2OP(VMIN_S, vmins)
427cd367ff3SPeter Maydell DO_2OP(VMIN_U, vminu)
428bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds)
429bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu)
430abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds)
431abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu)
432abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs)
433abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu)
434ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs)
435ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu)
436ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts)
437ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu)
438380caf6cSPeter Maydell DO_2OP(VQDMULH, vqdmulh)
439380caf6cSPeter Maydell DO_2OP(VQRDMULH, vqrdmulh)
440f741707bSPeter Maydell DO_2OP(VQADD_S, vqadds)
441f741707bSPeter Maydell DO_2OP(VQADD_U, vqaddu)
442f741707bSPeter Maydell DO_2OP(VQSUB_S, vqsubs)
443f741707bSPeter Maydell DO_2OP(VQSUB_U, vqsubu)
4440372cad8SPeter Maydell DO_2OP(VSHL_S, vshls)
4450372cad8SPeter Maydell DO_2OP(VSHL_U, vshlu)
446bb002345SPeter Maydell DO_2OP(VRSHL_S, vrshls)
447bb002345SPeter Maydell DO_2OP(VRSHL_U, vrshlu)
448483da661SPeter Maydell DO_2OP(VQSHL_S, vqshls)
449483da661SPeter Maydell DO_2OP(VQSHL_U, vqshlu)
4509dc868c4SPeter Maydell DO_2OP(VQRSHL_S, vqrshls)
4519dc868c4SPeter Maydell DO_2OP(VQRSHL_U, vqrshlu)
452fd677f80SPeter Maydell DO_2OP(VQDMLADH, vqdmladh)
453fd677f80SPeter Maydell DO_2OP(VQDMLADHX, vqdmladhx)
454fd677f80SPeter Maydell DO_2OP(VQRDMLADH, vqrdmladh)
455fd677f80SPeter Maydell DO_2OP(VQRDMLADHX, vqrdmladhx)
45692f11732SPeter Maydell DO_2OP(VQDMLSDH, vqdmlsdh)
45792f11732SPeter Maydell DO_2OP(VQDMLSDHX, vqdmlsdhx)
45892f11732SPeter Maydell DO_2OP(VQRDMLSDH, vqrdmlsdh)
45992f11732SPeter Maydell DO_2OP(VQRDMLSDHX, vqrdmlsdhx)
4601eb987a8SPeter Maydell DO_2OP(VRHADD_S, vrhadds)
4611eb987a8SPeter Maydell DO_2OP(VRHADD_U, vrhaddu)
46267ec113bSPeter Maydell /*
46367ec113bSPeter Maydell  * VCADD Qd == Qm at size MO_32 is UNPREDICTABLE; we choose not to diagnose
46467ec113bSPeter Maydell  * so we can reuse the DO_2OP macro. (Our implementation calculates the
4658625693aSPeter Maydell  * "expected" results in this case.) Similarly for VHCADD.
46667ec113bSPeter Maydell  */
46767ec113bSPeter Maydell DO_2OP(VCADD90, vcadd90)
46867ec113bSPeter Maydell DO_2OP(VCADD270, vcadd270)
4698625693aSPeter Maydell DO_2OP(VHCADD90, vhcadd90)
4708625693aSPeter Maydell DO_2OP(VHCADD270, vhcadd270)
4711d2386f7SPeter Maydell 
47243364321SPeter Maydell static bool trans_VQDMULLB(DisasContext *s, arg_2op *a)
47343364321SPeter Maydell {
47443364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
47543364321SPeter Maydell         NULL,
47643364321SPeter Maydell         gen_helper_mve_vqdmullbh,
47743364321SPeter Maydell         gen_helper_mve_vqdmullbw,
47843364321SPeter Maydell         NULL,
47943364321SPeter Maydell     };
48043364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
48143364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
48243364321SPeter Maydell         return false;
48343364321SPeter Maydell     }
48443364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
48543364321SPeter Maydell }
48643364321SPeter Maydell 
48743364321SPeter Maydell static bool trans_VQDMULLT(DisasContext *s, arg_2op *a)
48843364321SPeter Maydell {
48943364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
49043364321SPeter Maydell         NULL,
49143364321SPeter Maydell         gen_helper_mve_vqdmullth,
49243364321SPeter Maydell         gen_helper_mve_vqdmulltw,
49343364321SPeter Maydell         NULL,
49443364321SPeter Maydell     };
49543364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
49643364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
49743364321SPeter Maydell         return false;
49843364321SPeter Maydell     }
49943364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
50043364321SPeter Maydell }
50143364321SPeter Maydell 
502c1bd78cbSPeter Maydell static bool trans_VMULLP_B(DisasContext *s, arg_2op *a)
503c1bd78cbSPeter Maydell {
504c1bd78cbSPeter Maydell     /*
505c1bd78cbSPeter Maydell      * Note that a->size indicates the output size, ie VMULL.P8
506c1bd78cbSPeter Maydell      * is the 8x8->16 operation and a->size is MO_16; VMULL.P16
507c1bd78cbSPeter Maydell      * is the 16x16->32 operation and a->size is MO_32.
508c1bd78cbSPeter Maydell      */
509c1bd78cbSPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
510c1bd78cbSPeter Maydell         NULL,
511c1bd78cbSPeter Maydell         gen_helper_mve_vmullpbh,
512c1bd78cbSPeter Maydell         gen_helper_mve_vmullpbw,
513c1bd78cbSPeter Maydell         NULL,
514c1bd78cbSPeter Maydell     };
515c1bd78cbSPeter Maydell     return do_2op(s, a, fns[a->size]);
516c1bd78cbSPeter Maydell }
517c1bd78cbSPeter Maydell 
518c1bd78cbSPeter Maydell static bool trans_VMULLP_T(DisasContext *s, arg_2op *a)
519c1bd78cbSPeter Maydell {
520c1bd78cbSPeter Maydell     /* a->size is as for trans_VMULLP_B */
521c1bd78cbSPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
522c1bd78cbSPeter Maydell         NULL,
523c1bd78cbSPeter Maydell         gen_helper_mve_vmullpth,
524c1bd78cbSPeter Maydell         gen_helper_mve_vmullptw,
525c1bd78cbSPeter Maydell         NULL,
526c1bd78cbSPeter Maydell     };
527c1bd78cbSPeter Maydell     return do_2op(s, a, fns[a->size]);
528c1bd78cbSPeter Maydell }
529c1bd78cbSPeter Maydell 
53089bc4c4fSPeter Maydell /*
53189bc4c4fSPeter Maydell  * VADC and VSBC: these perform an add-with-carry or subtract-with-carry
53289bc4c4fSPeter Maydell  * of the 32-bit elements in each lane of the input vectors, where the
53389bc4c4fSPeter Maydell  * carry-out of each add is the carry-in of the next.  The initial carry
53489bc4c4fSPeter Maydell  * input is either fixed (0 for VADCI, 1 for VSBCI) or is from FPSCR.C
53589bc4c4fSPeter Maydell  * (for VADC and VSBC); the carry out at the end is written back to FPSCR.C.
53689bc4c4fSPeter Maydell  * These insns are subject to beat-wise execution.  Partial execution
53789bc4c4fSPeter Maydell  * of an I=1 (initial carry input fixed) insn which does not
53889bc4c4fSPeter Maydell  * execute the first beat must start with the current FPSCR.NZCV
53989bc4c4fSPeter Maydell  * value, not the fixed constant input.
54089bc4c4fSPeter Maydell  */
54189bc4c4fSPeter Maydell static bool trans_VADC(DisasContext *s, arg_2op *a)
54289bc4c4fSPeter Maydell {
54389bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadc);
54489bc4c4fSPeter Maydell }
54589bc4c4fSPeter Maydell 
54689bc4c4fSPeter Maydell static bool trans_VADCI(DisasContext *s, arg_2op *a)
54789bc4c4fSPeter Maydell {
54889bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
54989bc4c4fSPeter Maydell         return trans_VADC(s, a);
55089bc4c4fSPeter Maydell     }
55189bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadci);
55289bc4c4fSPeter Maydell }
55389bc4c4fSPeter Maydell 
55489bc4c4fSPeter Maydell static bool trans_VSBC(DisasContext *s, arg_2op *a)
55589bc4c4fSPeter Maydell {
55689bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbc);
55789bc4c4fSPeter Maydell }
55889bc4c4fSPeter Maydell 
55989bc4c4fSPeter Maydell static bool trans_VSBCI(DisasContext *s, arg_2op *a)
56089bc4c4fSPeter Maydell {
56189bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
56289bc4c4fSPeter Maydell         return trans_VSBC(s, a);
56389bc4c4fSPeter Maydell     }
56489bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbci);
56589bc4c4fSPeter Maydell }
56689bc4c4fSPeter Maydell 
567e51896b3SPeter Maydell static bool do_2op_scalar(DisasContext *s, arg_2scalar *a,
568e51896b3SPeter Maydell                           MVEGenTwoOpScalarFn fn)
569e51896b3SPeter Maydell {
570e51896b3SPeter Maydell     TCGv_ptr qd, qn;
571e51896b3SPeter Maydell     TCGv_i32 rm;
572e51896b3SPeter Maydell 
573e51896b3SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
574e51896b3SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn) ||
575e51896b3SPeter Maydell         !fn) {
576e51896b3SPeter Maydell         return false;
577e51896b3SPeter Maydell     }
578e51896b3SPeter Maydell     if (a->rm == 13 || a->rm == 15) {
579e51896b3SPeter Maydell         /* UNPREDICTABLE */
580e51896b3SPeter Maydell         return false;
581e51896b3SPeter Maydell     }
582e51896b3SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
583e51896b3SPeter Maydell         return true;
584e51896b3SPeter Maydell     }
585e51896b3SPeter Maydell 
586e51896b3SPeter Maydell     qd = mve_qreg_ptr(a->qd);
587e51896b3SPeter Maydell     qn = mve_qreg_ptr(a->qn);
588e51896b3SPeter Maydell     rm = load_reg(s, a->rm);
589e51896b3SPeter Maydell     fn(cpu_env, qd, qn, rm);
590e51896b3SPeter Maydell     tcg_temp_free_i32(rm);
591e51896b3SPeter Maydell     tcg_temp_free_ptr(qd);
592e51896b3SPeter Maydell     tcg_temp_free_ptr(qn);
593e51896b3SPeter Maydell     mve_update_eci(s);
594e51896b3SPeter Maydell     return true;
595e51896b3SPeter Maydell }
596e51896b3SPeter Maydell 
597e51896b3SPeter Maydell #define DO_2OP_SCALAR(INSN, FN) \
598e51896b3SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2scalar *a)   \
599e51896b3SPeter Maydell     {                                                           \
600e51896b3SPeter Maydell         static MVEGenTwoOpScalarFn * const fns[] = {            \
601e51896b3SPeter Maydell             gen_helper_mve_##FN##b,                             \
602e51896b3SPeter Maydell             gen_helper_mve_##FN##h,                             \
603e51896b3SPeter Maydell             gen_helper_mve_##FN##w,                             \
604e51896b3SPeter Maydell             NULL,                                               \
605e51896b3SPeter Maydell         };                                                      \
606e51896b3SPeter Maydell         return do_2op_scalar(s, a, fns[a->size]);               \
607e51896b3SPeter Maydell     }
608e51896b3SPeter Maydell 
609e51896b3SPeter Maydell DO_2OP_SCALAR(VADD_scalar, vadd_scalar)
61091a358fdSPeter Maydell DO_2OP_SCALAR(VSUB_scalar, vsub_scalar)
61191a358fdSPeter Maydell DO_2OP_SCALAR(VMUL_scalar, vmul_scalar)
612644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_S_scalar, vhadds_scalar)
613644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_U_scalar, vhaddu_scalar)
614644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_S_scalar, vhsubs_scalar)
615644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_U_scalar, vhsubu_scalar)
61639f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_S_scalar, vqadds_scalar)
61739f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_U_scalar, vqaddu_scalar)
61839f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_S_scalar, vqsubs_scalar)
61939f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_U_scalar, vqsubu_scalar)
62066c05767SPeter Maydell DO_2OP_SCALAR(VQDMULH_scalar, vqdmulh_scalar)
62166c05767SPeter Maydell DO_2OP_SCALAR(VQRDMULH_scalar, vqrdmulh_scalar)
622b050543bSPeter Maydell DO_2OP_SCALAR(VBRSR, vbrsr)
623*c69e34c6SPeter Maydell DO_2OP_SCALAR(VMLA, vmla)
6246b895bf8SPeter Maydell DO_2OP_SCALAR(VMLAS, vmlas)
625e51896b3SPeter Maydell 
626a8890353SPeter Maydell static bool trans_VQDMULLB_scalar(DisasContext *s, arg_2scalar *a)
627a8890353SPeter Maydell {
628a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
629a8890353SPeter Maydell         NULL,
630a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarh,
631a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarw,
632a8890353SPeter Maydell         NULL,
633a8890353SPeter Maydell     };
634a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
635a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
636a8890353SPeter Maydell         return false;
637a8890353SPeter Maydell     }
638a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
639a8890353SPeter Maydell }
640a8890353SPeter Maydell 
641a8890353SPeter Maydell static bool trans_VQDMULLT_scalar(DisasContext *s, arg_2scalar *a)
642a8890353SPeter Maydell {
643a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
644a8890353SPeter Maydell         NULL,
645a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarh,
646a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarw,
647a8890353SPeter Maydell         NULL,
648a8890353SPeter Maydell     };
649a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
650a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
651a8890353SPeter Maydell         return false;
652a8890353SPeter Maydell     }
653a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
654a8890353SPeter Maydell }
655a8890353SPeter Maydell 
6561d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a,
657640cdf20SPeter Maydell                              MVEGenLongDualAccOpFn *fn)
6581d2386f7SPeter Maydell {
6591d2386f7SPeter Maydell     TCGv_ptr qn, qm;
6601d2386f7SPeter Maydell     TCGv_i64 rda;
6611d2386f7SPeter Maydell     TCGv_i32 rdalo, rdahi;
6621d2386f7SPeter Maydell 
6631d2386f7SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
6641d2386f7SPeter Maydell         !mve_check_qreg_bank(s, a->qn | a->qm) ||
6651d2386f7SPeter Maydell         !fn) {
6661d2386f7SPeter Maydell         return false;
6671d2386f7SPeter Maydell     }
6681d2386f7SPeter Maydell     /*
6691d2386f7SPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
6701d2386f7SPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
6711d2386f7SPeter Maydell      */
6721d2386f7SPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
6731d2386f7SPeter Maydell         return false;
6741d2386f7SPeter Maydell     }
6751d2386f7SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
6761d2386f7SPeter Maydell         return true;
6771d2386f7SPeter Maydell     }
6781d2386f7SPeter Maydell 
6791d2386f7SPeter Maydell     qn = mve_qreg_ptr(a->qn);
6801d2386f7SPeter Maydell     qm = mve_qreg_ptr(a->qm);
6811d2386f7SPeter Maydell 
6821d2386f7SPeter Maydell     /*
6831d2386f7SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
6841d2386f7SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
6851d2386f7SPeter Maydell      * beat must start with the current rda value, not 0.
6861d2386f7SPeter Maydell      */
6871d2386f7SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
6881d2386f7SPeter Maydell         rda = tcg_temp_new_i64();
6891d2386f7SPeter Maydell         rdalo = load_reg(s, a->rdalo);
6901d2386f7SPeter Maydell         rdahi = load_reg(s, a->rdahi);
6911d2386f7SPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
6921d2386f7SPeter Maydell         tcg_temp_free_i32(rdalo);
6931d2386f7SPeter Maydell         tcg_temp_free_i32(rdahi);
6941d2386f7SPeter Maydell     } else {
6951d2386f7SPeter Maydell         rda = tcg_const_i64(0);
6961d2386f7SPeter Maydell     }
6971d2386f7SPeter Maydell 
6981d2386f7SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
6991d2386f7SPeter Maydell     tcg_temp_free_ptr(qn);
7001d2386f7SPeter Maydell     tcg_temp_free_ptr(qm);
7011d2386f7SPeter Maydell 
7021d2386f7SPeter Maydell     rdalo = tcg_temp_new_i32();
7031d2386f7SPeter Maydell     rdahi = tcg_temp_new_i32();
7041d2386f7SPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
7051d2386f7SPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
7061d2386f7SPeter Maydell     store_reg(s, a->rdalo, rdalo);
7071d2386f7SPeter Maydell     store_reg(s, a->rdahi, rdahi);
7081d2386f7SPeter Maydell     tcg_temp_free_i64(rda);
7091d2386f7SPeter Maydell     mve_update_eci(s);
7101d2386f7SPeter Maydell     return true;
7111d2386f7SPeter Maydell }
7121d2386f7SPeter Maydell 
7131d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a)
7141d2386f7SPeter Maydell {
715640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
7161d2386f7SPeter Maydell         { NULL, NULL },
7171d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh },
7181d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw },
7191d2386f7SPeter Maydell         { NULL, NULL },
7201d2386f7SPeter Maydell     };
7211d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
7221d2386f7SPeter Maydell }
7231d2386f7SPeter Maydell 
7241d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a)
7251d2386f7SPeter Maydell {
726640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
7271d2386f7SPeter Maydell         { NULL, NULL },
7281d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuh, NULL },
7291d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuw, NULL },
7301d2386f7SPeter Maydell         { NULL, NULL },
7311d2386f7SPeter Maydell     };
7321d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
7331d2386f7SPeter Maydell }
734181cd971SPeter Maydell 
735181cd971SPeter Maydell static bool trans_VMLSLDAV(DisasContext *s, arg_vmlaldav *a)
736181cd971SPeter Maydell {
737640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
738181cd971SPeter Maydell         { NULL, NULL },
739181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh },
740181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw },
741181cd971SPeter Maydell         { NULL, NULL },
742181cd971SPeter Maydell     };
743181cd971SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
744181cd971SPeter Maydell }
74538548747SPeter Maydell 
74638548747SPeter Maydell static bool trans_VRMLALDAVH_S(DisasContext *s, arg_vmlaldav *a)
74738548747SPeter Maydell {
748640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
74938548747SPeter Maydell         gen_helper_mve_vrmlaldavhsw, gen_helper_mve_vrmlaldavhxsw,
75038548747SPeter Maydell     };
75138548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
75238548747SPeter Maydell }
75338548747SPeter Maydell 
75438548747SPeter Maydell static bool trans_VRMLALDAVH_U(DisasContext *s, arg_vmlaldav *a)
75538548747SPeter Maydell {
756640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
75738548747SPeter Maydell         gen_helper_mve_vrmlaldavhuw, NULL,
75838548747SPeter Maydell     };
75938548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
76038548747SPeter Maydell }
76138548747SPeter Maydell 
76238548747SPeter Maydell static bool trans_VRMLSLDAVH(DisasContext *s, arg_vmlaldav *a)
76338548747SPeter Maydell {
764640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
76538548747SPeter Maydell         gen_helper_mve_vrmlsldavhsw, gen_helper_mve_vrmlsldavhxsw,
76638548747SPeter Maydell     };
76738548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
76838548747SPeter Maydell }
769387debdbSPeter Maydell 
770f0ffff51SPeter Maydell static bool do_dual_acc(DisasContext *s, arg_vmladav *a, MVEGenDualAccOpFn *fn)
771f0ffff51SPeter Maydell {
772f0ffff51SPeter Maydell     TCGv_ptr qn, qm;
773f0ffff51SPeter Maydell     TCGv_i32 rda;
774f0ffff51SPeter Maydell 
775f0ffff51SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
776f0ffff51SPeter Maydell         !mve_check_qreg_bank(s, a->qn) ||
777f0ffff51SPeter Maydell         !fn) {
778f0ffff51SPeter Maydell         return false;
779f0ffff51SPeter Maydell     }
780f0ffff51SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
781f0ffff51SPeter Maydell         return true;
782f0ffff51SPeter Maydell     }
783f0ffff51SPeter Maydell 
784f0ffff51SPeter Maydell     qn = mve_qreg_ptr(a->qn);
785f0ffff51SPeter Maydell     qm = mve_qreg_ptr(a->qm);
786f0ffff51SPeter Maydell 
787f0ffff51SPeter Maydell     /*
788f0ffff51SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
789f0ffff51SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
790f0ffff51SPeter Maydell      * beat must start with the current rda value, not 0.
791f0ffff51SPeter Maydell      */
792f0ffff51SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
793f0ffff51SPeter Maydell         rda = load_reg(s, a->rda);
794f0ffff51SPeter Maydell     } else {
795f0ffff51SPeter Maydell         rda = tcg_const_i32(0);
796f0ffff51SPeter Maydell     }
797f0ffff51SPeter Maydell 
798f0ffff51SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
799f0ffff51SPeter Maydell     store_reg(s, a->rda, rda);
800f0ffff51SPeter Maydell     tcg_temp_free_ptr(qn);
801f0ffff51SPeter Maydell     tcg_temp_free_ptr(qm);
802f0ffff51SPeter Maydell 
803f0ffff51SPeter Maydell     mve_update_eci(s);
804f0ffff51SPeter Maydell     return true;
805f0ffff51SPeter Maydell }
806f0ffff51SPeter Maydell 
807f0ffff51SPeter Maydell #define DO_DUAL_ACC(INSN, FN)                                           \
808f0ffff51SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vmladav *a)           \
809f0ffff51SPeter Maydell     {                                                                   \
810f0ffff51SPeter Maydell         static MVEGenDualAccOpFn * const fns[4][2] = {                  \
811f0ffff51SPeter Maydell             { gen_helper_mve_##FN##b, gen_helper_mve_##FN##xb },        \
812f0ffff51SPeter Maydell             { gen_helper_mve_##FN##h, gen_helper_mve_##FN##xh },        \
813f0ffff51SPeter Maydell             { gen_helper_mve_##FN##w, gen_helper_mve_##FN##xw },        \
814f0ffff51SPeter Maydell             { NULL, NULL },                                             \
815f0ffff51SPeter Maydell         };                                                              \
816f0ffff51SPeter Maydell         return do_dual_acc(s, a, fns[a->size][a->x]);                   \
817f0ffff51SPeter Maydell     }
818f0ffff51SPeter Maydell 
819f0ffff51SPeter Maydell DO_DUAL_ACC(VMLADAV_S, vmladavs)
820f0ffff51SPeter Maydell DO_DUAL_ACC(VMLSDAV, vmlsdav)
821f0ffff51SPeter Maydell 
822f0ffff51SPeter Maydell static bool trans_VMLADAV_U(DisasContext *s, arg_vmladav *a)
823f0ffff51SPeter Maydell {
824f0ffff51SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
825f0ffff51SPeter Maydell         { gen_helper_mve_vmladavub, NULL },
826f0ffff51SPeter Maydell         { gen_helper_mve_vmladavuh, NULL },
827f0ffff51SPeter Maydell         { gen_helper_mve_vmladavuw, NULL },
828f0ffff51SPeter Maydell         { NULL, NULL },
829f0ffff51SPeter Maydell     };
830f0ffff51SPeter Maydell     return do_dual_acc(s, a, fns[a->size][a->x]);
831f0ffff51SPeter Maydell }
832f0ffff51SPeter Maydell 
83355251786SPeter Maydell static void gen_vpst(DisasContext *s, uint32_t mask)
834387debdbSPeter Maydell {
835387debdbSPeter Maydell     /*
836387debdbSPeter Maydell      * Set the VPR mask fields. We take advantage of MASK01 and MASK23
837387debdbSPeter Maydell      * being adjacent fields in the register.
838387debdbSPeter Maydell      *
83955251786SPeter Maydell      * Updating the masks is not predicated, but it is subject to beat-wise
840387debdbSPeter Maydell      * execution, and the mask is updated on the odd-numbered beats.
841387debdbSPeter Maydell      * So if PSR.ECI says we should skip beat 1, we mustn't update the
842387debdbSPeter Maydell      * 01 mask field.
843387debdbSPeter Maydell      */
84455251786SPeter Maydell     TCGv_i32 vpr = load_cpu_field(v7m.vpr);
845387debdbSPeter Maydell     switch (s->eci) {
846387debdbSPeter Maydell     case ECI_NONE:
847387debdbSPeter Maydell     case ECI_A0:
848387debdbSPeter Maydell         /* Update both 01 and 23 fields */
849387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
85055251786SPeter Maydell                             tcg_constant_i32(mask | (mask << 4)),
851387debdbSPeter Maydell                             R_V7M_VPR_MASK01_SHIFT,
852387debdbSPeter Maydell                             R_V7M_VPR_MASK01_LENGTH + R_V7M_VPR_MASK23_LENGTH);
853387debdbSPeter Maydell         break;
854387debdbSPeter Maydell     case ECI_A0A1:
855387debdbSPeter Maydell     case ECI_A0A1A2:
856387debdbSPeter Maydell     case ECI_A0A1A2B0:
857387debdbSPeter Maydell         /* Update only the 23 mask field */
858387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
85955251786SPeter Maydell                             tcg_constant_i32(mask),
860387debdbSPeter Maydell                             R_V7M_VPR_MASK23_SHIFT, R_V7M_VPR_MASK23_LENGTH);
861387debdbSPeter Maydell         break;
862387debdbSPeter Maydell     default:
863387debdbSPeter Maydell         g_assert_not_reached();
864387debdbSPeter Maydell     }
865387debdbSPeter Maydell     store_cpu_field(vpr, v7m.vpr);
86655251786SPeter Maydell }
86755251786SPeter Maydell 
86855251786SPeter Maydell static bool trans_VPST(DisasContext *s, arg_VPST *a)
86955251786SPeter Maydell {
87055251786SPeter Maydell     /* mask == 0 is a "related encoding" */
87155251786SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !a->mask) {
87255251786SPeter Maydell         return false;
87355251786SPeter Maydell     }
87455251786SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
87555251786SPeter Maydell         return true;
87655251786SPeter Maydell     }
87755251786SPeter Maydell     gen_vpst(s, a->mask);
878387debdbSPeter Maydell     mve_update_and_store_eci(s);
879387debdbSPeter Maydell     return true;
880387debdbSPeter Maydell }
8816f060a63SPeter Maydell 
8826f060a63SPeter Maydell static bool trans_VADDV(DisasContext *s, arg_VADDV *a)
8836f060a63SPeter Maydell {
8846f060a63SPeter Maydell     /* VADDV: vector add across vector */
8856f060a63SPeter Maydell     static MVEGenVADDVFn * const fns[4][2] = {
8866f060a63SPeter Maydell         { gen_helper_mve_vaddvsb, gen_helper_mve_vaddvub },
8876f060a63SPeter Maydell         { gen_helper_mve_vaddvsh, gen_helper_mve_vaddvuh },
8886f060a63SPeter Maydell         { gen_helper_mve_vaddvsw, gen_helper_mve_vaddvuw },
8896f060a63SPeter Maydell         { NULL, NULL }
8906f060a63SPeter Maydell     };
8916f060a63SPeter Maydell     TCGv_ptr qm;
8926f060a63SPeter Maydell     TCGv_i32 rda;
8936f060a63SPeter Maydell 
8946f060a63SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
8956f060a63SPeter Maydell         a->size == 3) {
8966f060a63SPeter Maydell         return false;
8976f060a63SPeter Maydell     }
8986f060a63SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
8996f060a63SPeter Maydell         return true;
9006f060a63SPeter Maydell     }
9016f060a63SPeter Maydell 
9026f060a63SPeter Maydell     /*
9036f060a63SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
9046f060a63SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
9056f060a63SPeter Maydell      * beat must start with the current value of Rda, not zero.
9066f060a63SPeter Maydell      */
9076f060a63SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
9086f060a63SPeter Maydell         /* Accumulate input from Rda */
9096f060a63SPeter Maydell         rda = load_reg(s, a->rda);
9106f060a63SPeter Maydell     } else {
9116f060a63SPeter Maydell         /* Accumulate starting at zero */
9126f060a63SPeter Maydell         rda = tcg_const_i32(0);
9136f060a63SPeter Maydell     }
9146f060a63SPeter Maydell 
9156f060a63SPeter Maydell     qm = mve_qreg_ptr(a->qm);
9166f060a63SPeter Maydell     fns[a->size][a->u](rda, cpu_env, qm, rda);
9176f060a63SPeter Maydell     store_reg(s, a->rda, rda);
9186f060a63SPeter Maydell     tcg_temp_free_ptr(qm);
9196f060a63SPeter Maydell 
9206f060a63SPeter Maydell     mve_update_eci(s);
9216f060a63SPeter Maydell     return true;
9226f060a63SPeter Maydell }
923eab84139SPeter Maydell 
924d43ebd9dSPeter Maydell static bool trans_VADDLV(DisasContext *s, arg_VADDLV *a)
925d43ebd9dSPeter Maydell {
926d43ebd9dSPeter Maydell     /*
927d43ebd9dSPeter Maydell      * Vector Add Long Across Vector: accumulate the 32-bit
928d43ebd9dSPeter Maydell      * elements of the vector into a 64-bit result stored in
929d43ebd9dSPeter Maydell      * a pair of general-purpose registers.
930d43ebd9dSPeter Maydell      * No need to check Qm's bank: it is only 3 bits in decode.
931d43ebd9dSPeter Maydell      */
932d43ebd9dSPeter Maydell     TCGv_ptr qm;
933d43ebd9dSPeter Maydell     TCGv_i64 rda;
934d43ebd9dSPeter Maydell     TCGv_i32 rdalo, rdahi;
935d43ebd9dSPeter Maydell 
936d43ebd9dSPeter Maydell     if (!dc_isar_feature(aa32_mve, s)) {
937d43ebd9dSPeter Maydell         return false;
938d43ebd9dSPeter Maydell     }
939d43ebd9dSPeter Maydell     /*
940d43ebd9dSPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
941d43ebd9dSPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
942d43ebd9dSPeter Maydell      */
943d43ebd9dSPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
944d43ebd9dSPeter Maydell         return false;
945d43ebd9dSPeter Maydell     }
946d43ebd9dSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
947d43ebd9dSPeter Maydell         return true;
948d43ebd9dSPeter Maydell     }
949d43ebd9dSPeter Maydell 
950d43ebd9dSPeter Maydell     /*
951d43ebd9dSPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
952d43ebd9dSPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
953d43ebd9dSPeter Maydell      * beat must start with the current value of RdaHi:RdaLo, not zero.
954d43ebd9dSPeter Maydell      */
955d43ebd9dSPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
956d43ebd9dSPeter Maydell         /* Accumulate input from RdaHi:RdaLo */
957d43ebd9dSPeter Maydell         rda = tcg_temp_new_i64();
958d43ebd9dSPeter Maydell         rdalo = load_reg(s, a->rdalo);
959d43ebd9dSPeter Maydell         rdahi = load_reg(s, a->rdahi);
960d43ebd9dSPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
961d43ebd9dSPeter Maydell         tcg_temp_free_i32(rdalo);
962d43ebd9dSPeter Maydell         tcg_temp_free_i32(rdahi);
963d43ebd9dSPeter Maydell     } else {
964d43ebd9dSPeter Maydell         /* Accumulate starting at zero */
965d43ebd9dSPeter Maydell         rda = tcg_const_i64(0);
966d43ebd9dSPeter Maydell     }
967d43ebd9dSPeter Maydell 
968d43ebd9dSPeter Maydell     qm = mve_qreg_ptr(a->qm);
969d43ebd9dSPeter Maydell     if (a->u) {
970d43ebd9dSPeter Maydell         gen_helper_mve_vaddlv_u(rda, cpu_env, qm, rda);
971d43ebd9dSPeter Maydell     } else {
972d43ebd9dSPeter Maydell         gen_helper_mve_vaddlv_s(rda, cpu_env, qm, rda);
973d43ebd9dSPeter Maydell     }
974d43ebd9dSPeter Maydell     tcg_temp_free_ptr(qm);
975d43ebd9dSPeter Maydell 
976d43ebd9dSPeter Maydell     rdalo = tcg_temp_new_i32();
977d43ebd9dSPeter Maydell     rdahi = tcg_temp_new_i32();
978d43ebd9dSPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
979d43ebd9dSPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
980d43ebd9dSPeter Maydell     store_reg(s, a->rdalo, rdalo);
981d43ebd9dSPeter Maydell     store_reg(s, a->rdahi, rdahi);
982d43ebd9dSPeter Maydell     tcg_temp_free_i64(rda);
983d43ebd9dSPeter Maydell     mve_update_eci(s);
984d43ebd9dSPeter Maydell     return true;
985d43ebd9dSPeter Maydell }
986d43ebd9dSPeter Maydell 
987eab84139SPeter Maydell static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
988eab84139SPeter Maydell {
989eab84139SPeter Maydell     TCGv_ptr qd;
990eab84139SPeter Maydell     uint64_t imm;
991eab84139SPeter Maydell 
992eab84139SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
993eab84139SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
994eab84139SPeter Maydell         !fn) {
995eab84139SPeter Maydell         return false;
996eab84139SPeter Maydell     }
997eab84139SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
998eab84139SPeter Maydell         return true;
999eab84139SPeter Maydell     }
1000eab84139SPeter Maydell 
1001eab84139SPeter Maydell     imm = asimd_imm_const(a->imm, a->cmode, a->op);
1002eab84139SPeter Maydell 
1003eab84139SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1004eab84139SPeter Maydell     fn(cpu_env, qd, tcg_constant_i64(imm));
1005eab84139SPeter Maydell     tcg_temp_free_ptr(qd);
1006eab84139SPeter Maydell     mve_update_eci(s);
1007eab84139SPeter Maydell     return true;
1008eab84139SPeter Maydell }
1009eab84139SPeter Maydell 
1010eab84139SPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
1011eab84139SPeter Maydell {
1012eab84139SPeter Maydell     /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
1013eab84139SPeter Maydell     MVEGenOneOpImmFn *fn;
1014eab84139SPeter Maydell 
1015eab84139SPeter Maydell     if ((a->cmode & 1) && a->cmode < 12) {
1016eab84139SPeter Maydell         if (a->op) {
1017eab84139SPeter Maydell             /*
1018eab84139SPeter Maydell              * For op=1, the immediate will be inverted by asimd_imm_const(),
1019eab84139SPeter Maydell              * so the VBIC becomes a logical AND operation.
1020eab84139SPeter Maydell              */
1021eab84139SPeter Maydell             fn = gen_helper_mve_vandi;
1022eab84139SPeter Maydell         } else {
1023eab84139SPeter Maydell             fn = gen_helper_mve_vorri;
1024eab84139SPeter Maydell         }
1025eab84139SPeter Maydell     } else {
1026eab84139SPeter Maydell         /* There is one unallocated cmode/op combination in this space */
1027eab84139SPeter Maydell         if (a->cmode == 15 && a->op == 1) {
1028eab84139SPeter Maydell             return false;
1029eab84139SPeter Maydell         }
1030eab84139SPeter Maydell         /* asimd_imm_const() sorts out VMVNI vs VMOVI for us */
1031eab84139SPeter Maydell         fn = gen_helper_mve_vmovi;
1032eab84139SPeter Maydell     }
1033eab84139SPeter Maydell     return do_1imm(s, a, fn);
1034eab84139SPeter Maydell }
1035f9ed6174SPeter Maydell 
1036f9ed6174SPeter Maydell static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
1037f9ed6174SPeter Maydell                       bool negateshift)
1038f9ed6174SPeter Maydell {
1039f9ed6174SPeter Maydell     TCGv_ptr qd, qm;
1040f9ed6174SPeter Maydell     int shift = a->shift;
1041f9ed6174SPeter Maydell 
1042f9ed6174SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
1043f9ed6174SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
1044f9ed6174SPeter Maydell         !fn) {
1045f9ed6174SPeter Maydell         return false;
1046f9ed6174SPeter Maydell     }
1047f9ed6174SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1048f9ed6174SPeter Maydell         return true;
1049f9ed6174SPeter Maydell     }
1050f9ed6174SPeter Maydell 
1051f9ed6174SPeter Maydell     /*
1052f9ed6174SPeter Maydell      * When we handle a right shift insn using a left-shift helper
1053f9ed6174SPeter Maydell      * which permits a negative shift count to indicate a right-shift,
1054f9ed6174SPeter Maydell      * we must negate the shift count.
1055f9ed6174SPeter Maydell      */
1056f9ed6174SPeter Maydell     if (negateshift) {
1057f9ed6174SPeter Maydell         shift = -shift;
1058f9ed6174SPeter Maydell     }
1059f9ed6174SPeter Maydell 
1060f9ed6174SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1061f9ed6174SPeter Maydell     qm = mve_qreg_ptr(a->qm);
1062f9ed6174SPeter Maydell     fn(cpu_env, qd, qm, tcg_constant_i32(shift));
1063f9ed6174SPeter Maydell     tcg_temp_free_ptr(qd);
1064f9ed6174SPeter Maydell     tcg_temp_free_ptr(qm);
1065f9ed6174SPeter Maydell     mve_update_eci(s);
1066f9ed6174SPeter Maydell     return true;
1067f9ed6174SPeter Maydell }
1068f9ed6174SPeter Maydell 
1069f9ed6174SPeter Maydell #define DO_2SHIFT(INSN, FN, NEGATESHIFT)                         \
1070f9ed6174SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1071f9ed6174SPeter Maydell     {                                                           \
1072f9ed6174SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1073f9ed6174SPeter Maydell             gen_helper_mve_##FN##b,                             \
1074f9ed6174SPeter Maydell             gen_helper_mve_##FN##h,                             \
1075f9ed6174SPeter Maydell             gen_helper_mve_##FN##w,                             \
1076f9ed6174SPeter Maydell             NULL,                                               \
1077f9ed6174SPeter Maydell         };                                                      \
1078f9ed6174SPeter Maydell         return do_2shift(s, a, fns[a->size], NEGATESHIFT);      \
1079f9ed6174SPeter Maydell     }
1080f9ed6174SPeter Maydell 
1081f9ed6174SPeter Maydell DO_2SHIFT(VSHLI, vshli_u, false)
1082f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_S, vqshli_s, false)
1083f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_U, vqshli_u, false)
1084f9ed6174SPeter Maydell DO_2SHIFT(VQSHLUI, vqshlui_s, false)
10853394116fSPeter Maydell /* These right shifts use a left-shift helper with negated shift count */
10863394116fSPeter Maydell DO_2SHIFT(VSHRI_S, vshli_s, true)
10873394116fSPeter Maydell DO_2SHIFT(VSHRI_U, vshli_u, true)
10883394116fSPeter Maydell DO_2SHIFT(VRSHRI_S, vrshli_s, true)
10893394116fSPeter Maydell DO_2SHIFT(VRSHRI_U, vrshli_u, true)
1090c2262707SPeter Maydell 
1091a78b25faSPeter Maydell DO_2SHIFT(VSRI, vsri, false)
1092a78b25faSPeter Maydell DO_2SHIFT(VSLI, vsli, false)
1093a78b25faSPeter Maydell 
10941b15a97dSPeter Maydell static bool do_2shift_scalar(DisasContext *s, arg_shl_scalar *a,
10951b15a97dSPeter Maydell                              MVEGenTwoOpShiftFn *fn)
10961b15a97dSPeter Maydell {
10971b15a97dSPeter Maydell     TCGv_ptr qda;
10981b15a97dSPeter Maydell     TCGv_i32 rm;
10991b15a97dSPeter Maydell 
11001b15a97dSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
11011b15a97dSPeter Maydell         !mve_check_qreg_bank(s, a->qda) ||
11021b15a97dSPeter Maydell         a->rm == 13 || a->rm == 15 || !fn) {
11031b15a97dSPeter Maydell         /* Rm cases are UNPREDICTABLE */
11041b15a97dSPeter Maydell         return false;
11051b15a97dSPeter Maydell     }
11061b15a97dSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
11071b15a97dSPeter Maydell         return true;
11081b15a97dSPeter Maydell     }
11091b15a97dSPeter Maydell 
11101b15a97dSPeter Maydell     qda = mve_qreg_ptr(a->qda);
11111b15a97dSPeter Maydell     rm = load_reg(s, a->rm);
11121b15a97dSPeter Maydell     fn(cpu_env, qda, qda, rm);
11131b15a97dSPeter Maydell     tcg_temp_free_ptr(qda);
11141b15a97dSPeter Maydell     tcg_temp_free_i32(rm);
11151b15a97dSPeter Maydell     mve_update_eci(s);
11161b15a97dSPeter Maydell     return true;
11171b15a97dSPeter Maydell }
11181b15a97dSPeter Maydell 
11191b15a97dSPeter Maydell #define DO_2SHIFT_SCALAR(INSN, FN)                                      \
11201b15a97dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_shl_scalar *a)        \
11211b15a97dSPeter Maydell     {                                                                   \
11221b15a97dSPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {                     \
11231b15a97dSPeter Maydell             gen_helper_mve_##FN##b,                                     \
11241b15a97dSPeter Maydell             gen_helper_mve_##FN##h,                                     \
11251b15a97dSPeter Maydell             gen_helper_mve_##FN##w,                                     \
11261b15a97dSPeter Maydell             NULL,                                                       \
11271b15a97dSPeter Maydell         };                                                              \
11281b15a97dSPeter Maydell         return do_2shift_scalar(s, a, fns[a->size]);                    \
11291b15a97dSPeter Maydell     }
11301b15a97dSPeter Maydell 
11311b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VSHL_S_scalar, vshli_s)
11321b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VSHL_U_scalar, vshli_u)
11331b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VRSHL_S_scalar, vrshli_s)
11341b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VRSHL_U_scalar, vrshli_u)
11351b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQSHL_S_scalar, vqshli_s)
11361b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQSHL_U_scalar, vqshli_u)
11371b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQRSHL_S_scalar, vqrshli_s)
11381b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQRSHL_U_scalar, vqrshli_u)
11391b15a97dSPeter Maydell 
1140c2262707SPeter Maydell #define DO_VSHLL(INSN, FN)                                      \
1141c2262707SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1142c2262707SPeter Maydell     {                                                           \
1143c2262707SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1144c2262707SPeter Maydell             gen_helper_mve_##FN##b,                             \
1145c2262707SPeter Maydell             gen_helper_mve_##FN##h,                             \
1146c2262707SPeter Maydell         };                                                      \
1147c2262707SPeter Maydell         return do_2shift(s, a, fns[a->size], false);            \
1148c2262707SPeter Maydell     }
1149c2262707SPeter Maydell 
1150c2262707SPeter Maydell DO_VSHLL(VSHLL_BS, vshllbs)
1151c2262707SPeter Maydell DO_VSHLL(VSHLL_BU, vshllbu)
1152c2262707SPeter Maydell DO_VSHLL(VSHLL_TS, vshllts)
1153c2262707SPeter Maydell DO_VSHLL(VSHLL_TU, vshlltu)
1154162e2655SPeter Maydell 
1155162e2655SPeter Maydell #define DO_2SHIFT_N(INSN, FN)                                   \
1156162e2655SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1157162e2655SPeter Maydell     {                                                           \
1158162e2655SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1159162e2655SPeter Maydell             gen_helper_mve_##FN##b,                             \
1160162e2655SPeter Maydell             gen_helper_mve_##FN##h,                             \
1161162e2655SPeter Maydell         };                                                      \
1162162e2655SPeter Maydell         return do_2shift(s, a, fns[a->size], false);            \
1163162e2655SPeter Maydell     }
1164162e2655SPeter Maydell 
1165162e2655SPeter Maydell DO_2SHIFT_N(VSHRNB, vshrnb)
1166162e2655SPeter Maydell DO_2SHIFT_N(VSHRNT, vshrnt)
1167162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNB, vrshrnb)
1168162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNT, vrshrnt)
1169d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_S, vqshrnb_s)
1170d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_S, vqshrnt_s)
1171d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_U, vqshrnb_u)
1172d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_U, vqshrnt_u)
1173d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNB, vqshrunb)
1174d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNT, vqshrunt)
1175d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_S, vqrshrnb_s)
1176d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_S, vqrshrnt_s)
1177d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_U, vqrshrnb_u)
1178d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_U, vqrshrnt_u)
1179d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNB, vqrshrunb)
1180d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNT, vqrshrunt)
11812e6a4ce0SPeter Maydell 
11822e6a4ce0SPeter Maydell static bool trans_VSHLC(DisasContext *s, arg_VSHLC *a)
11832e6a4ce0SPeter Maydell {
11842e6a4ce0SPeter Maydell     /*
11852e6a4ce0SPeter Maydell      * Whole Vector Left Shift with Carry. The carry is taken
11862e6a4ce0SPeter Maydell      * from a general purpose register and written back there.
11872e6a4ce0SPeter Maydell      * An imm of 0 means "shift by 32".
11882e6a4ce0SPeter Maydell      */
11892e6a4ce0SPeter Maydell     TCGv_ptr qd;
11902e6a4ce0SPeter Maydell     TCGv_i32 rdm;
11912e6a4ce0SPeter Maydell 
11922e6a4ce0SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
11932e6a4ce0SPeter Maydell         return false;
11942e6a4ce0SPeter Maydell     }
11952e6a4ce0SPeter Maydell     if (a->rdm == 13 || a->rdm == 15) {
11962e6a4ce0SPeter Maydell         /* CONSTRAINED UNPREDICTABLE: we UNDEF */
11972e6a4ce0SPeter Maydell         return false;
11982e6a4ce0SPeter Maydell     }
11992e6a4ce0SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
12002e6a4ce0SPeter Maydell         return true;
12012e6a4ce0SPeter Maydell     }
12022e6a4ce0SPeter Maydell 
12032e6a4ce0SPeter Maydell     qd = mve_qreg_ptr(a->qd);
12042e6a4ce0SPeter Maydell     rdm = load_reg(s, a->rdm);
12052e6a4ce0SPeter Maydell     gen_helper_mve_vshlc(rdm, cpu_env, qd, rdm, tcg_constant_i32(a->imm));
12062e6a4ce0SPeter Maydell     store_reg(s, a->rdm, rdm);
12072e6a4ce0SPeter Maydell     tcg_temp_free_ptr(qd);
12082e6a4ce0SPeter Maydell     mve_update_eci(s);
12092e6a4ce0SPeter Maydell     return true;
12102e6a4ce0SPeter Maydell }
1211395b92d5SPeter Maydell 
1212395b92d5SPeter Maydell static bool do_vidup(DisasContext *s, arg_vidup *a, MVEGenVIDUPFn *fn)
1213395b92d5SPeter Maydell {
1214395b92d5SPeter Maydell     TCGv_ptr qd;
1215395b92d5SPeter Maydell     TCGv_i32 rn;
1216395b92d5SPeter Maydell 
1217395b92d5SPeter Maydell     /*
1218395b92d5SPeter Maydell      * Vector increment/decrement with wrap and duplicate (VIDUP, VDDUP).
1219395b92d5SPeter Maydell      * This fills the vector with elements of successively increasing
1220395b92d5SPeter Maydell      * or decreasing values, starting from Rn.
1221395b92d5SPeter Maydell      */
1222395b92d5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
1223395b92d5SPeter Maydell         return false;
1224395b92d5SPeter Maydell     }
1225395b92d5SPeter Maydell     if (a->size == MO_64) {
1226395b92d5SPeter Maydell         /* size 0b11 is another encoding */
1227395b92d5SPeter Maydell         return false;
1228395b92d5SPeter Maydell     }
1229395b92d5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1230395b92d5SPeter Maydell         return true;
1231395b92d5SPeter Maydell     }
1232395b92d5SPeter Maydell 
1233395b92d5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1234395b92d5SPeter Maydell     rn = load_reg(s, a->rn);
1235395b92d5SPeter Maydell     fn(rn, cpu_env, qd, rn, tcg_constant_i32(a->imm));
1236395b92d5SPeter Maydell     store_reg(s, a->rn, rn);
1237395b92d5SPeter Maydell     tcg_temp_free_ptr(qd);
1238395b92d5SPeter Maydell     mve_update_eci(s);
1239395b92d5SPeter Maydell     return true;
1240395b92d5SPeter Maydell }
1241395b92d5SPeter Maydell 
1242395b92d5SPeter Maydell static bool do_viwdup(DisasContext *s, arg_viwdup *a, MVEGenVIWDUPFn *fn)
1243395b92d5SPeter Maydell {
1244395b92d5SPeter Maydell     TCGv_ptr qd;
1245395b92d5SPeter Maydell     TCGv_i32 rn, rm;
1246395b92d5SPeter Maydell 
1247395b92d5SPeter Maydell     /*
1248395b92d5SPeter Maydell      * Vector increment/decrement with wrap and duplicate (VIWDUp, VDWDUP)
1249395b92d5SPeter Maydell      * This fills the vector with elements of successively increasing
1250395b92d5SPeter Maydell      * or decreasing values, starting from Rn. Rm specifies a point where
1251395b92d5SPeter Maydell      * the count wraps back around to 0. The updated offset is written back
1252395b92d5SPeter Maydell      * to Rn.
1253395b92d5SPeter Maydell      */
1254395b92d5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
1255395b92d5SPeter Maydell         return false;
1256395b92d5SPeter Maydell     }
1257395b92d5SPeter Maydell     if (!fn || a->rm == 13 || a->rm == 15) {
1258395b92d5SPeter Maydell         /*
1259395b92d5SPeter Maydell          * size 0b11 is another encoding; Rm == 13 is UNPREDICTABLE;
1260395b92d5SPeter Maydell          * Rm == 13 is VIWDUP, VDWDUP.
1261395b92d5SPeter Maydell          */
1262395b92d5SPeter Maydell         return false;
1263395b92d5SPeter Maydell     }
1264395b92d5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1265395b92d5SPeter Maydell         return true;
1266395b92d5SPeter Maydell     }
1267395b92d5SPeter Maydell 
1268395b92d5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1269395b92d5SPeter Maydell     rn = load_reg(s, a->rn);
1270395b92d5SPeter Maydell     rm = load_reg(s, a->rm);
1271395b92d5SPeter Maydell     fn(rn, cpu_env, qd, rn, rm, tcg_constant_i32(a->imm));
1272395b92d5SPeter Maydell     store_reg(s, a->rn, rn);
1273395b92d5SPeter Maydell     tcg_temp_free_ptr(qd);
1274395b92d5SPeter Maydell     tcg_temp_free_i32(rm);
1275395b92d5SPeter Maydell     mve_update_eci(s);
1276395b92d5SPeter Maydell     return true;
1277395b92d5SPeter Maydell }
1278395b92d5SPeter Maydell 
1279395b92d5SPeter Maydell static bool trans_VIDUP(DisasContext *s, arg_vidup *a)
1280395b92d5SPeter Maydell {
1281395b92d5SPeter Maydell     static MVEGenVIDUPFn * const fns[] = {
1282395b92d5SPeter Maydell         gen_helper_mve_vidupb,
1283395b92d5SPeter Maydell         gen_helper_mve_viduph,
1284395b92d5SPeter Maydell         gen_helper_mve_vidupw,
1285395b92d5SPeter Maydell         NULL,
1286395b92d5SPeter Maydell     };
1287395b92d5SPeter Maydell     return do_vidup(s, a, fns[a->size]);
1288395b92d5SPeter Maydell }
1289395b92d5SPeter Maydell 
1290395b92d5SPeter Maydell static bool trans_VDDUP(DisasContext *s, arg_vidup *a)
1291395b92d5SPeter Maydell {
1292395b92d5SPeter Maydell     static MVEGenVIDUPFn * const fns[] = {
1293395b92d5SPeter Maydell         gen_helper_mve_vidupb,
1294395b92d5SPeter Maydell         gen_helper_mve_viduph,
1295395b92d5SPeter Maydell         gen_helper_mve_vidupw,
1296395b92d5SPeter Maydell         NULL,
1297395b92d5SPeter Maydell     };
1298395b92d5SPeter Maydell     /* VDDUP is just like VIDUP but with a negative immediate */
1299395b92d5SPeter Maydell     a->imm = -a->imm;
1300395b92d5SPeter Maydell     return do_vidup(s, a, fns[a->size]);
1301395b92d5SPeter Maydell }
1302395b92d5SPeter Maydell 
1303395b92d5SPeter Maydell static bool trans_VIWDUP(DisasContext *s, arg_viwdup *a)
1304395b92d5SPeter Maydell {
1305395b92d5SPeter Maydell     static MVEGenVIWDUPFn * const fns[] = {
1306395b92d5SPeter Maydell         gen_helper_mve_viwdupb,
1307395b92d5SPeter Maydell         gen_helper_mve_viwduph,
1308395b92d5SPeter Maydell         gen_helper_mve_viwdupw,
1309395b92d5SPeter Maydell         NULL,
1310395b92d5SPeter Maydell     };
1311395b92d5SPeter Maydell     return do_viwdup(s, a, fns[a->size]);
1312395b92d5SPeter Maydell }
1313395b92d5SPeter Maydell 
1314395b92d5SPeter Maydell static bool trans_VDWDUP(DisasContext *s, arg_viwdup *a)
1315395b92d5SPeter Maydell {
1316395b92d5SPeter Maydell     static MVEGenVIWDUPFn * const fns[] = {
1317395b92d5SPeter Maydell         gen_helper_mve_vdwdupb,
1318395b92d5SPeter Maydell         gen_helper_mve_vdwduph,
1319395b92d5SPeter Maydell         gen_helper_mve_vdwdupw,
1320395b92d5SPeter Maydell         NULL,
1321395b92d5SPeter Maydell     };
1322395b92d5SPeter Maydell     return do_viwdup(s, a, fns[a->size]);
1323395b92d5SPeter Maydell }
1324eff5d9a9SPeter Maydell 
1325eff5d9a9SPeter Maydell static bool do_vcmp(DisasContext *s, arg_vcmp *a, MVEGenCmpFn *fn)
1326eff5d9a9SPeter Maydell {
1327eff5d9a9SPeter Maydell     TCGv_ptr qn, qm;
1328eff5d9a9SPeter Maydell 
1329eff5d9a9SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qm) ||
1330eff5d9a9SPeter Maydell         !fn) {
1331eff5d9a9SPeter Maydell         return false;
1332eff5d9a9SPeter Maydell     }
1333eff5d9a9SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1334eff5d9a9SPeter Maydell         return true;
1335eff5d9a9SPeter Maydell     }
1336eff5d9a9SPeter Maydell 
1337eff5d9a9SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1338eff5d9a9SPeter Maydell     qm = mve_qreg_ptr(a->qm);
1339eff5d9a9SPeter Maydell     fn(cpu_env, qn, qm);
1340eff5d9a9SPeter Maydell     tcg_temp_free_ptr(qn);
1341eff5d9a9SPeter Maydell     tcg_temp_free_ptr(qm);
1342eff5d9a9SPeter Maydell     if (a->mask) {
1343eff5d9a9SPeter Maydell         /* VPT */
1344eff5d9a9SPeter Maydell         gen_vpst(s, a->mask);
1345eff5d9a9SPeter Maydell     }
1346eff5d9a9SPeter Maydell     mve_update_eci(s);
1347eff5d9a9SPeter Maydell     return true;
1348eff5d9a9SPeter Maydell }
1349eff5d9a9SPeter Maydell 
1350cce81873SPeter Maydell static bool do_vcmp_scalar(DisasContext *s, arg_vcmp_scalar *a,
1351cce81873SPeter Maydell                            MVEGenScalarCmpFn *fn)
1352cce81873SPeter Maydell {
1353cce81873SPeter Maydell     TCGv_ptr qn;
1354cce81873SPeter Maydell     TCGv_i32 rm;
1355cce81873SPeter Maydell 
1356cce81873SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !fn || a->rm == 13) {
1357cce81873SPeter Maydell         return false;
1358cce81873SPeter Maydell     }
1359cce81873SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1360cce81873SPeter Maydell         return true;
1361cce81873SPeter Maydell     }
1362cce81873SPeter Maydell 
1363cce81873SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1364cce81873SPeter Maydell     if (a->rm == 15) {
1365cce81873SPeter Maydell         /* Encoding Rm=0b1111 means "constant zero" */
1366cce81873SPeter Maydell         rm = tcg_constant_i32(0);
1367cce81873SPeter Maydell     } else {
1368cce81873SPeter Maydell         rm = load_reg(s, a->rm);
1369cce81873SPeter Maydell     }
1370cce81873SPeter Maydell     fn(cpu_env, qn, rm);
1371cce81873SPeter Maydell     tcg_temp_free_ptr(qn);
1372cce81873SPeter Maydell     tcg_temp_free_i32(rm);
1373cce81873SPeter Maydell     if (a->mask) {
1374cce81873SPeter Maydell         /* VPT */
1375cce81873SPeter Maydell         gen_vpst(s, a->mask);
1376cce81873SPeter Maydell     }
1377cce81873SPeter Maydell     mve_update_eci(s);
1378cce81873SPeter Maydell     return true;
1379cce81873SPeter Maydell }
1380cce81873SPeter Maydell 
1381eff5d9a9SPeter Maydell #define DO_VCMP(INSN, FN)                                       \
1382eff5d9a9SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vcmp *a)      \
1383eff5d9a9SPeter Maydell     {                                                           \
1384eff5d9a9SPeter Maydell         static MVEGenCmpFn * const fns[] = {                    \
1385eff5d9a9SPeter Maydell             gen_helper_mve_##FN##b,                             \
1386eff5d9a9SPeter Maydell             gen_helper_mve_##FN##h,                             \
1387eff5d9a9SPeter Maydell             gen_helper_mve_##FN##w,                             \
1388eff5d9a9SPeter Maydell             NULL,                                               \
1389eff5d9a9SPeter Maydell         };                                                      \
1390eff5d9a9SPeter Maydell         return do_vcmp(s, a, fns[a->size]);                     \
1391cce81873SPeter Maydell     }                                                           \
1392cce81873SPeter Maydell     static bool trans_##INSN##_scalar(DisasContext *s,          \
1393cce81873SPeter Maydell                                       arg_vcmp_scalar *a)       \
1394cce81873SPeter Maydell     {                                                           \
1395cce81873SPeter Maydell         static MVEGenScalarCmpFn * const fns[] = {              \
1396cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarb,                      \
1397cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarh,                      \
1398cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarw,                      \
1399cce81873SPeter Maydell             NULL,                                               \
1400cce81873SPeter Maydell         };                                                      \
1401cce81873SPeter Maydell         return do_vcmp_scalar(s, a, fns[a->size]);              \
1402eff5d9a9SPeter Maydell     }
1403eff5d9a9SPeter Maydell 
1404eff5d9a9SPeter Maydell DO_VCMP(VCMPEQ, vcmpeq)
1405eff5d9a9SPeter Maydell DO_VCMP(VCMPNE, vcmpne)
1406eff5d9a9SPeter Maydell DO_VCMP(VCMPCS, vcmpcs)
1407eff5d9a9SPeter Maydell DO_VCMP(VCMPHI, vcmphi)
1408eff5d9a9SPeter Maydell DO_VCMP(VCMPGE, vcmpge)
1409eff5d9a9SPeter Maydell DO_VCMP(VCMPLT, vcmplt)
1410eff5d9a9SPeter Maydell DO_VCMP(VCMPGT, vcmpgt)
1411eff5d9a9SPeter Maydell DO_VCMP(VCMPLE, vcmple)
1412688ba4cfSPeter Maydell 
1413688ba4cfSPeter Maydell static bool do_vmaxv(DisasContext *s, arg_vmaxv *a, MVEGenVADDVFn fn)
1414688ba4cfSPeter Maydell {
1415688ba4cfSPeter Maydell     /*
1416688ba4cfSPeter Maydell      * MIN/MAX operations across a vector: compute the min or
1417688ba4cfSPeter Maydell      * max of the initial value in a general purpose register
1418688ba4cfSPeter Maydell      * and all the elements in the vector, and store it back
1419688ba4cfSPeter Maydell      * into the general purpose register.
1420688ba4cfSPeter Maydell      */
1421688ba4cfSPeter Maydell     TCGv_ptr qm;
1422688ba4cfSPeter Maydell     TCGv_i32 rda;
1423688ba4cfSPeter Maydell 
1424688ba4cfSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qm) ||
1425688ba4cfSPeter Maydell         !fn || a->rda == 13 || a->rda == 15) {
1426688ba4cfSPeter Maydell         /* Rda cases are UNPREDICTABLE */
1427688ba4cfSPeter Maydell         return false;
1428688ba4cfSPeter Maydell     }
1429688ba4cfSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1430688ba4cfSPeter Maydell         return true;
1431688ba4cfSPeter Maydell     }
1432688ba4cfSPeter Maydell 
1433688ba4cfSPeter Maydell     qm = mve_qreg_ptr(a->qm);
1434688ba4cfSPeter Maydell     rda = load_reg(s, a->rda);
1435688ba4cfSPeter Maydell     fn(rda, cpu_env, qm, rda);
1436688ba4cfSPeter Maydell     store_reg(s, a->rda, rda);
1437688ba4cfSPeter Maydell     tcg_temp_free_ptr(qm);
1438688ba4cfSPeter Maydell     mve_update_eci(s);
1439688ba4cfSPeter Maydell     return true;
1440688ba4cfSPeter Maydell }
1441688ba4cfSPeter Maydell 
1442688ba4cfSPeter Maydell #define DO_VMAXV(INSN, FN)                                      \
1443688ba4cfSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vmaxv *a)     \
1444688ba4cfSPeter Maydell     {                                                           \
1445688ba4cfSPeter Maydell         static MVEGenVADDVFn * const fns[] = {                  \
1446688ba4cfSPeter Maydell             gen_helper_mve_##FN##b,                             \
1447688ba4cfSPeter Maydell             gen_helper_mve_##FN##h,                             \
1448688ba4cfSPeter Maydell             gen_helper_mve_##FN##w,                             \
1449688ba4cfSPeter Maydell             NULL,                                               \
1450688ba4cfSPeter Maydell         };                                                      \
1451688ba4cfSPeter Maydell         return do_vmaxv(s, a, fns[a->size]);                    \
1452688ba4cfSPeter Maydell     }
1453688ba4cfSPeter Maydell 
1454688ba4cfSPeter Maydell DO_VMAXV(VMAXV_S, vmaxvs)
1455688ba4cfSPeter Maydell DO_VMAXV(VMAXV_U, vmaxvu)
1456688ba4cfSPeter Maydell DO_VMAXV(VMAXAV, vmaxav)
1457688ba4cfSPeter Maydell DO_VMAXV(VMINV_S, vminvs)
1458688ba4cfSPeter Maydell DO_VMAXV(VMINV_U, vminvu)
1459688ba4cfSPeter Maydell DO_VMAXV(VMINAV, vminav)
14607f061c0aSPeter Maydell 
14617f061c0aSPeter Maydell static bool do_vabav(DisasContext *s, arg_vabav *a, MVEGenVABAVFn *fn)
14627f061c0aSPeter Maydell {
14637f061c0aSPeter Maydell     /* Absolute difference accumulated across vector */
14647f061c0aSPeter Maydell     TCGv_ptr qn, qm;
14657f061c0aSPeter Maydell     TCGv_i32 rda;
14667f061c0aSPeter Maydell 
14677f061c0aSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
14687f061c0aSPeter Maydell         !mve_check_qreg_bank(s, a->qm | a->qn) ||
14697f061c0aSPeter Maydell         !fn || a->rda == 13 || a->rda == 15) {
14707f061c0aSPeter Maydell         /* Rda cases are UNPREDICTABLE */
14717f061c0aSPeter Maydell         return false;
14727f061c0aSPeter Maydell     }
14737f061c0aSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
14747f061c0aSPeter Maydell         return true;
14757f061c0aSPeter Maydell     }
14767f061c0aSPeter Maydell 
14777f061c0aSPeter Maydell     qm = mve_qreg_ptr(a->qm);
14787f061c0aSPeter Maydell     qn = mve_qreg_ptr(a->qn);
14797f061c0aSPeter Maydell     rda = load_reg(s, a->rda);
14807f061c0aSPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
14817f061c0aSPeter Maydell     store_reg(s, a->rda, rda);
14827f061c0aSPeter Maydell     tcg_temp_free_ptr(qm);
14837f061c0aSPeter Maydell     tcg_temp_free_ptr(qn);
14847f061c0aSPeter Maydell     mve_update_eci(s);
14857f061c0aSPeter Maydell     return true;
14867f061c0aSPeter Maydell }
14877f061c0aSPeter Maydell 
14887f061c0aSPeter Maydell #define DO_VABAV(INSN, FN)                                      \
14897f061c0aSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vabav *a)     \
14907f061c0aSPeter Maydell     {                                                           \
14917f061c0aSPeter Maydell         static MVEGenVABAVFn * const fns[] = {                  \
14927f061c0aSPeter Maydell             gen_helper_mve_##FN##b,                             \
14937f061c0aSPeter Maydell             gen_helper_mve_##FN##h,                             \
14947f061c0aSPeter Maydell             gen_helper_mve_##FN##w,                             \
14957f061c0aSPeter Maydell             NULL,                                               \
14967f061c0aSPeter Maydell         };                                                      \
14977f061c0aSPeter Maydell         return do_vabav(s, a, fns[a->size]);                    \
14987f061c0aSPeter Maydell     }
14997f061c0aSPeter Maydell 
15007f061c0aSPeter Maydell DO_VABAV(VABAV_S, vabavs)
15017f061c0aSPeter Maydell DO_VABAV(VABAV_U, vabavu)
1502