xref: /qemu/target/arm/tcg/translate-mve.c (revision cce81873bcc163a86488deec1e122c303c6762a4)
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);
411d2386f7SPeter Maydell typedef void MVEGenDualAccOpFn(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);
47*cce81873SPeter Maydell typedef void MVEGenScalarCmpFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
48507b6a50SPeter Maydell 
49507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */
50507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg)
51507b6a50SPeter Maydell {
52507b6a50SPeter Maydell     return offsetof(CPUARMState, vfp.zregs[reg].d[0]);
53507b6a50SPeter Maydell }
54507b6a50SPeter Maydell 
55507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg)
56507b6a50SPeter Maydell {
57507b6a50SPeter Maydell     TCGv_ptr ret = tcg_temp_new_ptr();
58507b6a50SPeter Maydell     tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg));
59507b6a50SPeter Maydell     return ret;
60507b6a50SPeter Maydell }
61507b6a50SPeter Maydell 
62507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask)
63507b6a50SPeter Maydell {
64507b6a50SPeter Maydell     /*
65507b6a50SPeter Maydell      * Check whether Qregs are in range. For v8.1M only Q0..Q7
66507b6a50SPeter Maydell      * are supported, see VFPSmallRegisterBank().
67507b6a50SPeter Maydell      */
68507b6a50SPeter Maydell     return qmask < 8;
69507b6a50SPeter Maydell }
70507b6a50SPeter Maydell 
714f57ef95SPeter Maydell bool mve_eci_check(DisasContext *s)
72507b6a50SPeter Maydell {
73507b6a50SPeter Maydell     /*
74507b6a50SPeter Maydell      * This is a beatwise insn: check that ECI is valid (not a
75507b6a50SPeter Maydell      * reserved value) and note that we are handling it.
76507b6a50SPeter Maydell      * Return true if OK, false if we generated an exception.
77507b6a50SPeter Maydell      */
78507b6a50SPeter Maydell     s->eci_handled = true;
79507b6a50SPeter Maydell     switch (s->eci) {
80507b6a50SPeter Maydell     case ECI_NONE:
81507b6a50SPeter Maydell     case ECI_A0:
82507b6a50SPeter Maydell     case ECI_A0A1:
83507b6a50SPeter Maydell     case ECI_A0A1A2:
84507b6a50SPeter Maydell     case ECI_A0A1A2B0:
85507b6a50SPeter Maydell         return true;
86507b6a50SPeter Maydell     default:
87507b6a50SPeter Maydell         /* Reserved value: INVSTATE UsageFault */
88507b6a50SPeter Maydell         gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(),
89507b6a50SPeter Maydell                            default_exception_el(s));
90507b6a50SPeter Maydell         return false;
91507b6a50SPeter Maydell     }
92507b6a50SPeter Maydell }
93507b6a50SPeter Maydell 
94507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s)
95507b6a50SPeter Maydell {
96507b6a50SPeter Maydell     /*
97507b6a50SPeter Maydell      * The helper function will always update the CPUState field,
98507b6a50SPeter Maydell      * so we only need to update the DisasContext field.
99507b6a50SPeter Maydell      */
100507b6a50SPeter Maydell     if (s->eci) {
101507b6a50SPeter Maydell         s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE;
102507b6a50SPeter Maydell     }
103507b6a50SPeter Maydell }
104507b6a50SPeter Maydell 
1054f57ef95SPeter Maydell void mve_update_and_store_eci(DisasContext *s)
106387debdbSPeter Maydell {
107387debdbSPeter Maydell     /*
108387debdbSPeter Maydell      * For insns which don't call a helper function that will call
109387debdbSPeter Maydell      * mve_advance_vpt(), this version updates s->eci and also stores
110387debdbSPeter Maydell      * it out to the CPUState field.
111387debdbSPeter Maydell      */
112387debdbSPeter Maydell     if (s->eci) {
113387debdbSPeter Maydell         mve_update_eci(s);
114387debdbSPeter Maydell         store_cpu_field(tcg_constant_i32(s->eci << 4), condexec_bits);
115387debdbSPeter Maydell     }
116387debdbSPeter Maydell }
117387debdbSPeter Maydell 
1181d2386f7SPeter Maydell static bool mve_skip_first_beat(DisasContext *s)
1191d2386f7SPeter Maydell {
1201d2386f7SPeter Maydell     /* Return true if PSR.ECI says we must skip the first beat of this insn */
1211d2386f7SPeter Maydell     switch (s->eci) {
1221d2386f7SPeter Maydell     case ECI_NONE:
1231d2386f7SPeter Maydell         return false;
1241d2386f7SPeter Maydell     case ECI_A0:
1251d2386f7SPeter Maydell     case ECI_A0A1:
1261d2386f7SPeter Maydell     case ECI_A0A1A2:
1271d2386f7SPeter Maydell     case ECI_A0A1A2B0:
1281d2386f7SPeter Maydell         return true;
1291d2386f7SPeter Maydell     default:
1301d2386f7SPeter Maydell         g_assert_not_reached();
1311d2386f7SPeter Maydell     }
1321d2386f7SPeter Maydell }
1331d2386f7SPeter Maydell 
134d59ccc30SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn,
135d59ccc30SPeter Maydell                     unsigned msize)
136507b6a50SPeter Maydell {
137507b6a50SPeter Maydell     TCGv_i32 addr;
138507b6a50SPeter Maydell     uint32_t offset;
139507b6a50SPeter Maydell     TCGv_ptr qreg;
140507b6a50SPeter Maydell 
141507b6a50SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
142507b6a50SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
143507b6a50SPeter Maydell         !fn) {
144507b6a50SPeter Maydell         return false;
145507b6a50SPeter Maydell     }
146507b6a50SPeter Maydell 
147507b6a50SPeter Maydell     /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
148507b6a50SPeter Maydell     if (a->rn == 15 || (a->rn == 13 && a->w)) {
149507b6a50SPeter Maydell         return false;
150507b6a50SPeter Maydell     }
151507b6a50SPeter Maydell 
152507b6a50SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
153507b6a50SPeter Maydell         return true;
154507b6a50SPeter Maydell     }
155507b6a50SPeter Maydell 
156d59ccc30SPeter Maydell     offset = a->imm << msize;
157507b6a50SPeter Maydell     if (!a->a) {
158507b6a50SPeter Maydell         offset = -offset;
159507b6a50SPeter Maydell     }
160507b6a50SPeter Maydell     addr = load_reg(s, a->rn);
161507b6a50SPeter Maydell     if (a->p) {
162507b6a50SPeter Maydell         tcg_gen_addi_i32(addr, addr, offset);
163507b6a50SPeter Maydell     }
164507b6a50SPeter Maydell 
165507b6a50SPeter Maydell     qreg = mve_qreg_ptr(a->qd);
166507b6a50SPeter Maydell     fn(cpu_env, qreg, addr);
167507b6a50SPeter Maydell     tcg_temp_free_ptr(qreg);
168507b6a50SPeter Maydell 
169507b6a50SPeter Maydell     /*
170507b6a50SPeter Maydell      * Writeback always happens after the last beat of the insn,
171507b6a50SPeter Maydell      * regardless of predication
172507b6a50SPeter Maydell      */
173507b6a50SPeter Maydell     if (a->w) {
174507b6a50SPeter Maydell         if (!a->p) {
175507b6a50SPeter Maydell             tcg_gen_addi_i32(addr, addr, offset);
176507b6a50SPeter Maydell         }
177507b6a50SPeter Maydell         store_reg(s, a->rn, addr);
178507b6a50SPeter Maydell     } else {
179507b6a50SPeter Maydell         tcg_temp_free_i32(addr);
180507b6a50SPeter Maydell     }
181507b6a50SPeter Maydell     mve_update_eci(s);
182507b6a50SPeter Maydell     return true;
183507b6a50SPeter Maydell }
184507b6a50SPeter Maydell 
185507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a)
186507b6a50SPeter Maydell {
187507b6a50SPeter Maydell     static MVEGenLdStFn * const ldstfns[4][2] = {
188507b6a50SPeter Maydell         { gen_helper_mve_vstrb, gen_helper_mve_vldrb },
189507b6a50SPeter Maydell         { gen_helper_mve_vstrh, gen_helper_mve_vldrh },
190507b6a50SPeter Maydell         { gen_helper_mve_vstrw, gen_helper_mve_vldrw },
191507b6a50SPeter Maydell         { NULL, NULL }
192507b6a50SPeter Maydell     };
193d59ccc30SPeter Maydell     return do_ldst(s, a, ldstfns[a->size][a->l], a->size);
194507b6a50SPeter Maydell }
1952fc6b751SPeter Maydell 
196d59ccc30SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST, MSIZE)           \
1972fc6b751SPeter Maydell     static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a)   \
1982fc6b751SPeter Maydell     {                                                           \
1992fc6b751SPeter Maydell         static MVEGenLdStFn * const ldstfns[2][2] = {           \
2002fc6b751SPeter Maydell             { gen_helper_mve_##ST, gen_helper_mve_##SLD },      \
2012fc6b751SPeter Maydell             { NULL, gen_helper_mve_##ULD },                     \
2022fc6b751SPeter Maydell         };                                                      \
203d59ccc30SPeter Maydell         return do_ldst(s, a, ldstfns[a->u][a->l], MSIZE);       \
2042fc6b751SPeter Maydell     }
2052fc6b751SPeter Maydell 
206d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h, MO_8)
207d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w, MO_8)
208d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w, MO_16)
2090f0f2bd5SPeter Maydell 
210ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
211ab59362fSPeter Maydell {
212ab59362fSPeter Maydell     TCGv_ptr qd;
213ab59362fSPeter Maydell     TCGv_i32 rt;
214ab59362fSPeter Maydell 
215ab59362fSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
216ab59362fSPeter Maydell         !mve_check_qreg_bank(s, a->qd)) {
217ab59362fSPeter Maydell         return false;
218ab59362fSPeter Maydell     }
219ab59362fSPeter Maydell     if (a->rt == 13 || a->rt == 15) {
220ab59362fSPeter Maydell         /* UNPREDICTABLE; we choose to UNDEF */
221ab59362fSPeter Maydell         return false;
222ab59362fSPeter Maydell     }
223ab59362fSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
224ab59362fSPeter Maydell         return true;
225ab59362fSPeter Maydell     }
226ab59362fSPeter Maydell 
227ab59362fSPeter Maydell     qd = mve_qreg_ptr(a->qd);
228ab59362fSPeter Maydell     rt = load_reg(s, a->rt);
229ab59362fSPeter Maydell     tcg_gen_dup_i32(a->size, rt, rt);
230ab59362fSPeter Maydell     gen_helper_mve_vdup(cpu_env, qd, rt);
231ab59362fSPeter Maydell     tcg_temp_free_ptr(qd);
232ab59362fSPeter Maydell     tcg_temp_free_i32(rt);
233ab59362fSPeter Maydell     mve_update_eci(s);
234ab59362fSPeter Maydell     return true;
235ab59362fSPeter Maydell }
236ab59362fSPeter Maydell 
2370f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
2380f0f2bd5SPeter Maydell {
2390f0f2bd5SPeter Maydell     TCGv_ptr qd, qm;
2400f0f2bd5SPeter Maydell 
2410f0f2bd5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
2420f0f2bd5SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
2430f0f2bd5SPeter Maydell         !fn) {
2440f0f2bd5SPeter Maydell         return false;
2450f0f2bd5SPeter Maydell     }
2460f0f2bd5SPeter Maydell 
2470f0f2bd5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
2480f0f2bd5SPeter Maydell         return true;
2490f0f2bd5SPeter Maydell     }
2500f0f2bd5SPeter Maydell 
2510f0f2bd5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
2520f0f2bd5SPeter Maydell     qm = mve_qreg_ptr(a->qm);
2530f0f2bd5SPeter Maydell     fn(cpu_env, qd, qm);
2540f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qd);
2550f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qm);
2560f0f2bd5SPeter Maydell     mve_update_eci(s);
2570f0f2bd5SPeter Maydell     return true;
2580f0f2bd5SPeter Maydell }
2590f0f2bd5SPeter Maydell 
2600f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN)                                        \
2610f0f2bd5SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
2620f0f2bd5SPeter Maydell     {                                                           \
2630f0f2bd5SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
2640f0f2bd5SPeter Maydell             gen_helper_mve_##FN##b,                             \
2650f0f2bd5SPeter Maydell             gen_helper_mve_##FN##h,                             \
2660f0f2bd5SPeter Maydell             gen_helper_mve_##FN##w,                             \
2670f0f2bd5SPeter Maydell             NULL,                                               \
2680f0f2bd5SPeter Maydell         };                                                      \
2690f0f2bd5SPeter Maydell         return do_1op(s, a, fns[a->size]);                      \
2700f0f2bd5SPeter Maydell     }
2710f0f2bd5SPeter Maydell 
2720f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz)
2736437f1f7SPeter Maydell DO_1OP(VCLS, vcls)
27459c91773SPeter Maydell DO_1OP(VABS, vabs)
275399a8c76SPeter Maydell DO_1OP(VNEG, vneg)
276249b5309SPeter Maydell 
277249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a)
278249b5309SPeter Maydell {
279249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
280249b5309SPeter Maydell         gen_helper_mve_vrev16b,
281249b5309SPeter Maydell         NULL,
282249b5309SPeter Maydell         NULL,
283249b5309SPeter Maydell         NULL,
284249b5309SPeter Maydell     };
285249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
286249b5309SPeter Maydell }
287249b5309SPeter Maydell 
288249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a)
289249b5309SPeter Maydell {
290249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
291249b5309SPeter Maydell         gen_helper_mve_vrev32b,
292249b5309SPeter Maydell         gen_helper_mve_vrev32h,
293249b5309SPeter Maydell         NULL,
294249b5309SPeter Maydell         NULL,
295249b5309SPeter Maydell     };
296249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
297249b5309SPeter Maydell }
298249b5309SPeter Maydell 
299249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a)
300249b5309SPeter Maydell {
301249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
302249b5309SPeter Maydell         gen_helper_mve_vrev64b,
303249b5309SPeter Maydell         gen_helper_mve_vrev64h,
304249b5309SPeter Maydell         gen_helper_mve_vrev64w,
305249b5309SPeter Maydell         NULL,
306249b5309SPeter Maydell     };
307249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
308249b5309SPeter Maydell }
3098abd3c80SPeter Maydell 
3108abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a)
3118abd3c80SPeter Maydell {
3128abd3c80SPeter Maydell     return do_1op(s, a, gen_helper_mve_vmvn);
3138abd3c80SPeter Maydell }
31459c91773SPeter Maydell 
31559c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a)
31659c91773SPeter Maydell {
31759c91773SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
31859c91773SPeter Maydell         NULL,
31959c91773SPeter Maydell         gen_helper_mve_vfabsh,
32059c91773SPeter Maydell         gen_helper_mve_vfabss,
32159c91773SPeter Maydell         NULL,
32259c91773SPeter Maydell     };
32359c91773SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
32459c91773SPeter Maydell         return false;
32559c91773SPeter Maydell     }
32659c91773SPeter Maydell     return do_1op(s, a, fns[a->size]);
32759c91773SPeter Maydell }
328399a8c76SPeter Maydell 
329399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a)
330399a8c76SPeter Maydell {
331399a8c76SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
332399a8c76SPeter Maydell         NULL,
333399a8c76SPeter Maydell         gen_helper_mve_vfnegh,
334399a8c76SPeter Maydell         gen_helper_mve_vfnegs,
335399a8c76SPeter Maydell         NULL,
336399a8c76SPeter Maydell     };
337399a8c76SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
338399a8c76SPeter Maydell         return false;
339399a8c76SPeter Maydell     }
340399a8c76SPeter Maydell     return do_1op(s, a, fns[a->size]);
341399a8c76SPeter Maydell }
34268245e44SPeter Maydell 
34368245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
34468245e44SPeter Maydell {
34568245e44SPeter Maydell     TCGv_ptr qd, qn, qm;
34668245e44SPeter Maydell 
34768245e44SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
34868245e44SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) ||
34968245e44SPeter Maydell         !fn) {
35068245e44SPeter Maydell         return false;
35168245e44SPeter Maydell     }
35268245e44SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
35368245e44SPeter Maydell         return true;
35468245e44SPeter Maydell     }
35568245e44SPeter Maydell 
35668245e44SPeter Maydell     qd = mve_qreg_ptr(a->qd);
35768245e44SPeter Maydell     qn = mve_qreg_ptr(a->qn);
35868245e44SPeter Maydell     qm = mve_qreg_ptr(a->qm);
35968245e44SPeter Maydell     fn(cpu_env, qd, qn, qm);
36068245e44SPeter Maydell     tcg_temp_free_ptr(qd);
36168245e44SPeter Maydell     tcg_temp_free_ptr(qn);
36268245e44SPeter Maydell     tcg_temp_free_ptr(qm);
36368245e44SPeter Maydell     mve_update_eci(s);
36468245e44SPeter Maydell     return true;
36568245e44SPeter Maydell }
36668245e44SPeter Maydell 
36768245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER)                                  \
36868245e44SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
36968245e44SPeter Maydell     {                                                           \
37068245e44SPeter Maydell         return do_2op(s, a, HELPER);                            \
37168245e44SPeter Maydell     }
37268245e44SPeter Maydell 
37368245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand)
37468245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic)
37568245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr)
37668245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn)
37768245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor)
3789333fe4dSPeter Maydell 
3799333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \
3809333fe4dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
3819333fe4dSPeter Maydell     {                                                           \
3829333fe4dSPeter Maydell         static MVEGenTwoOpFn * const fns[] = {                  \
3839333fe4dSPeter Maydell             gen_helper_mve_##FN##b,                             \
3849333fe4dSPeter Maydell             gen_helper_mve_##FN##h,                             \
3859333fe4dSPeter Maydell             gen_helper_mve_##FN##w,                             \
3869333fe4dSPeter Maydell             NULL,                                               \
3879333fe4dSPeter Maydell         };                                                      \
3889333fe4dSPeter Maydell         return do_2op(s, a, fns[a->size]);                      \
3899333fe4dSPeter Maydell     }
3909333fe4dSPeter Maydell 
3919333fe4dSPeter Maydell DO_2OP(VADD, vadd)
3929333fe4dSPeter Maydell DO_2OP(VSUB, vsub)
3939333fe4dSPeter Maydell DO_2OP(VMUL, vmul)
394ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs)
395ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu)
396fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs)
397fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu)
398cd367ff3SPeter Maydell DO_2OP(VMAX_S, vmaxs)
399cd367ff3SPeter Maydell DO_2OP(VMAX_U, vmaxu)
400cd367ff3SPeter Maydell DO_2OP(VMIN_S, vmins)
401cd367ff3SPeter Maydell DO_2OP(VMIN_U, vminu)
402bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds)
403bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu)
404abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds)
405abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu)
406abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs)
407abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu)
408ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs)
409ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu)
410ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts)
411ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu)
412380caf6cSPeter Maydell DO_2OP(VQDMULH, vqdmulh)
413380caf6cSPeter Maydell DO_2OP(VQRDMULH, vqrdmulh)
414f741707bSPeter Maydell DO_2OP(VQADD_S, vqadds)
415f741707bSPeter Maydell DO_2OP(VQADD_U, vqaddu)
416f741707bSPeter Maydell DO_2OP(VQSUB_S, vqsubs)
417f741707bSPeter Maydell DO_2OP(VQSUB_U, vqsubu)
4180372cad8SPeter Maydell DO_2OP(VSHL_S, vshls)
4190372cad8SPeter Maydell DO_2OP(VSHL_U, vshlu)
420bb002345SPeter Maydell DO_2OP(VRSHL_S, vrshls)
421bb002345SPeter Maydell DO_2OP(VRSHL_U, vrshlu)
422483da661SPeter Maydell DO_2OP(VQSHL_S, vqshls)
423483da661SPeter Maydell DO_2OP(VQSHL_U, vqshlu)
4249dc868c4SPeter Maydell DO_2OP(VQRSHL_S, vqrshls)
4259dc868c4SPeter Maydell DO_2OP(VQRSHL_U, vqrshlu)
426fd677f80SPeter Maydell DO_2OP(VQDMLADH, vqdmladh)
427fd677f80SPeter Maydell DO_2OP(VQDMLADHX, vqdmladhx)
428fd677f80SPeter Maydell DO_2OP(VQRDMLADH, vqrdmladh)
429fd677f80SPeter Maydell DO_2OP(VQRDMLADHX, vqrdmladhx)
43092f11732SPeter Maydell DO_2OP(VQDMLSDH, vqdmlsdh)
43192f11732SPeter Maydell DO_2OP(VQDMLSDHX, vqdmlsdhx)
43292f11732SPeter Maydell DO_2OP(VQRDMLSDH, vqrdmlsdh)
43392f11732SPeter Maydell DO_2OP(VQRDMLSDHX, vqrdmlsdhx)
4341eb987a8SPeter Maydell DO_2OP(VRHADD_S, vrhadds)
4351eb987a8SPeter Maydell DO_2OP(VRHADD_U, vrhaddu)
43667ec113bSPeter Maydell /*
43767ec113bSPeter Maydell  * VCADD Qd == Qm at size MO_32 is UNPREDICTABLE; we choose not to diagnose
43867ec113bSPeter Maydell  * so we can reuse the DO_2OP macro. (Our implementation calculates the
4398625693aSPeter Maydell  * "expected" results in this case.) Similarly for VHCADD.
44067ec113bSPeter Maydell  */
44167ec113bSPeter Maydell DO_2OP(VCADD90, vcadd90)
44267ec113bSPeter Maydell DO_2OP(VCADD270, vcadd270)
4438625693aSPeter Maydell DO_2OP(VHCADD90, vhcadd90)
4448625693aSPeter Maydell DO_2OP(VHCADD270, vhcadd270)
4451d2386f7SPeter Maydell 
44643364321SPeter Maydell static bool trans_VQDMULLB(DisasContext *s, arg_2op *a)
44743364321SPeter Maydell {
44843364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
44943364321SPeter Maydell         NULL,
45043364321SPeter Maydell         gen_helper_mve_vqdmullbh,
45143364321SPeter Maydell         gen_helper_mve_vqdmullbw,
45243364321SPeter Maydell         NULL,
45343364321SPeter Maydell     };
45443364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
45543364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
45643364321SPeter Maydell         return false;
45743364321SPeter Maydell     }
45843364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
45943364321SPeter Maydell }
46043364321SPeter Maydell 
46143364321SPeter Maydell static bool trans_VQDMULLT(DisasContext *s, arg_2op *a)
46243364321SPeter Maydell {
46343364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
46443364321SPeter Maydell         NULL,
46543364321SPeter Maydell         gen_helper_mve_vqdmullth,
46643364321SPeter Maydell         gen_helper_mve_vqdmulltw,
46743364321SPeter Maydell         NULL,
46843364321SPeter Maydell     };
46943364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
47043364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
47143364321SPeter Maydell         return false;
47243364321SPeter Maydell     }
47343364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
47443364321SPeter Maydell }
47543364321SPeter Maydell 
476c1bd78cbSPeter Maydell static bool trans_VMULLP_B(DisasContext *s, arg_2op *a)
477c1bd78cbSPeter Maydell {
478c1bd78cbSPeter Maydell     /*
479c1bd78cbSPeter Maydell      * Note that a->size indicates the output size, ie VMULL.P8
480c1bd78cbSPeter Maydell      * is the 8x8->16 operation and a->size is MO_16; VMULL.P16
481c1bd78cbSPeter Maydell      * is the 16x16->32 operation and a->size is MO_32.
482c1bd78cbSPeter Maydell      */
483c1bd78cbSPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
484c1bd78cbSPeter Maydell         NULL,
485c1bd78cbSPeter Maydell         gen_helper_mve_vmullpbh,
486c1bd78cbSPeter Maydell         gen_helper_mve_vmullpbw,
487c1bd78cbSPeter Maydell         NULL,
488c1bd78cbSPeter Maydell     };
489c1bd78cbSPeter Maydell     return do_2op(s, a, fns[a->size]);
490c1bd78cbSPeter Maydell }
491c1bd78cbSPeter Maydell 
492c1bd78cbSPeter Maydell static bool trans_VMULLP_T(DisasContext *s, arg_2op *a)
493c1bd78cbSPeter Maydell {
494c1bd78cbSPeter Maydell     /* a->size is as for trans_VMULLP_B */
495c1bd78cbSPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
496c1bd78cbSPeter Maydell         NULL,
497c1bd78cbSPeter Maydell         gen_helper_mve_vmullpth,
498c1bd78cbSPeter Maydell         gen_helper_mve_vmullptw,
499c1bd78cbSPeter Maydell         NULL,
500c1bd78cbSPeter Maydell     };
501c1bd78cbSPeter Maydell     return do_2op(s, a, fns[a->size]);
502c1bd78cbSPeter Maydell }
503c1bd78cbSPeter Maydell 
50489bc4c4fSPeter Maydell /*
50589bc4c4fSPeter Maydell  * VADC and VSBC: these perform an add-with-carry or subtract-with-carry
50689bc4c4fSPeter Maydell  * of the 32-bit elements in each lane of the input vectors, where the
50789bc4c4fSPeter Maydell  * carry-out of each add is the carry-in of the next.  The initial carry
50889bc4c4fSPeter Maydell  * input is either fixed (0 for VADCI, 1 for VSBCI) or is from FPSCR.C
50989bc4c4fSPeter Maydell  * (for VADC and VSBC); the carry out at the end is written back to FPSCR.C.
51089bc4c4fSPeter Maydell  * These insns are subject to beat-wise execution.  Partial execution
51189bc4c4fSPeter Maydell  * of an I=1 (initial carry input fixed) insn which does not
51289bc4c4fSPeter Maydell  * execute the first beat must start with the current FPSCR.NZCV
51389bc4c4fSPeter Maydell  * value, not the fixed constant input.
51489bc4c4fSPeter Maydell  */
51589bc4c4fSPeter Maydell static bool trans_VADC(DisasContext *s, arg_2op *a)
51689bc4c4fSPeter Maydell {
51789bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadc);
51889bc4c4fSPeter Maydell }
51989bc4c4fSPeter Maydell 
52089bc4c4fSPeter Maydell static bool trans_VADCI(DisasContext *s, arg_2op *a)
52189bc4c4fSPeter Maydell {
52289bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
52389bc4c4fSPeter Maydell         return trans_VADC(s, a);
52489bc4c4fSPeter Maydell     }
52589bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadci);
52689bc4c4fSPeter Maydell }
52789bc4c4fSPeter Maydell 
52889bc4c4fSPeter Maydell static bool trans_VSBC(DisasContext *s, arg_2op *a)
52989bc4c4fSPeter Maydell {
53089bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbc);
53189bc4c4fSPeter Maydell }
53289bc4c4fSPeter Maydell 
53389bc4c4fSPeter Maydell static bool trans_VSBCI(DisasContext *s, arg_2op *a)
53489bc4c4fSPeter Maydell {
53589bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
53689bc4c4fSPeter Maydell         return trans_VSBC(s, a);
53789bc4c4fSPeter Maydell     }
53889bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbci);
53989bc4c4fSPeter Maydell }
54089bc4c4fSPeter Maydell 
541e51896b3SPeter Maydell static bool do_2op_scalar(DisasContext *s, arg_2scalar *a,
542e51896b3SPeter Maydell                           MVEGenTwoOpScalarFn fn)
543e51896b3SPeter Maydell {
544e51896b3SPeter Maydell     TCGv_ptr qd, qn;
545e51896b3SPeter Maydell     TCGv_i32 rm;
546e51896b3SPeter Maydell 
547e51896b3SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
548e51896b3SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn) ||
549e51896b3SPeter Maydell         !fn) {
550e51896b3SPeter Maydell         return false;
551e51896b3SPeter Maydell     }
552e51896b3SPeter Maydell     if (a->rm == 13 || a->rm == 15) {
553e51896b3SPeter Maydell         /* UNPREDICTABLE */
554e51896b3SPeter Maydell         return false;
555e51896b3SPeter Maydell     }
556e51896b3SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
557e51896b3SPeter Maydell         return true;
558e51896b3SPeter Maydell     }
559e51896b3SPeter Maydell 
560e51896b3SPeter Maydell     qd = mve_qreg_ptr(a->qd);
561e51896b3SPeter Maydell     qn = mve_qreg_ptr(a->qn);
562e51896b3SPeter Maydell     rm = load_reg(s, a->rm);
563e51896b3SPeter Maydell     fn(cpu_env, qd, qn, rm);
564e51896b3SPeter Maydell     tcg_temp_free_i32(rm);
565e51896b3SPeter Maydell     tcg_temp_free_ptr(qd);
566e51896b3SPeter Maydell     tcg_temp_free_ptr(qn);
567e51896b3SPeter Maydell     mve_update_eci(s);
568e51896b3SPeter Maydell     return true;
569e51896b3SPeter Maydell }
570e51896b3SPeter Maydell 
571e51896b3SPeter Maydell #define DO_2OP_SCALAR(INSN, FN) \
572e51896b3SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2scalar *a)   \
573e51896b3SPeter Maydell     {                                                           \
574e51896b3SPeter Maydell         static MVEGenTwoOpScalarFn * const fns[] = {            \
575e51896b3SPeter Maydell             gen_helper_mve_##FN##b,                             \
576e51896b3SPeter Maydell             gen_helper_mve_##FN##h,                             \
577e51896b3SPeter Maydell             gen_helper_mve_##FN##w,                             \
578e51896b3SPeter Maydell             NULL,                                               \
579e51896b3SPeter Maydell         };                                                      \
580e51896b3SPeter Maydell         return do_2op_scalar(s, a, fns[a->size]);               \
581e51896b3SPeter Maydell     }
582e51896b3SPeter Maydell 
583e51896b3SPeter Maydell DO_2OP_SCALAR(VADD_scalar, vadd_scalar)
58491a358fdSPeter Maydell DO_2OP_SCALAR(VSUB_scalar, vsub_scalar)
58591a358fdSPeter Maydell DO_2OP_SCALAR(VMUL_scalar, vmul_scalar)
586644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_S_scalar, vhadds_scalar)
587644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_U_scalar, vhaddu_scalar)
588644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_S_scalar, vhsubs_scalar)
589644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_U_scalar, vhsubu_scalar)
59039f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_S_scalar, vqadds_scalar)
59139f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_U_scalar, vqaddu_scalar)
59239f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_S_scalar, vqsubs_scalar)
59339f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_U_scalar, vqsubu_scalar)
59466c05767SPeter Maydell DO_2OP_SCALAR(VQDMULH_scalar, vqdmulh_scalar)
59566c05767SPeter Maydell DO_2OP_SCALAR(VQRDMULH_scalar, vqrdmulh_scalar)
596b050543bSPeter Maydell DO_2OP_SCALAR(VBRSR, vbrsr)
597e51896b3SPeter Maydell 
598a8890353SPeter Maydell static bool trans_VQDMULLB_scalar(DisasContext *s, arg_2scalar *a)
599a8890353SPeter Maydell {
600a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
601a8890353SPeter Maydell         NULL,
602a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarh,
603a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarw,
604a8890353SPeter Maydell         NULL,
605a8890353SPeter Maydell     };
606a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
607a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
608a8890353SPeter Maydell         return false;
609a8890353SPeter Maydell     }
610a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
611a8890353SPeter Maydell }
612a8890353SPeter Maydell 
613a8890353SPeter Maydell static bool trans_VQDMULLT_scalar(DisasContext *s, arg_2scalar *a)
614a8890353SPeter Maydell {
615a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
616a8890353SPeter Maydell         NULL,
617a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarh,
618a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarw,
619a8890353SPeter Maydell         NULL,
620a8890353SPeter Maydell     };
621a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
622a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
623a8890353SPeter Maydell         return false;
624a8890353SPeter Maydell     }
625a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
626a8890353SPeter Maydell }
627a8890353SPeter Maydell 
6281d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a,
6291d2386f7SPeter Maydell                              MVEGenDualAccOpFn *fn)
6301d2386f7SPeter Maydell {
6311d2386f7SPeter Maydell     TCGv_ptr qn, qm;
6321d2386f7SPeter Maydell     TCGv_i64 rda;
6331d2386f7SPeter Maydell     TCGv_i32 rdalo, rdahi;
6341d2386f7SPeter Maydell 
6351d2386f7SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
6361d2386f7SPeter Maydell         !mve_check_qreg_bank(s, a->qn | a->qm) ||
6371d2386f7SPeter Maydell         !fn) {
6381d2386f7SPeter Maydell         return false;
6391d2386f7SPeter Maydell     }
6401d2386f7SPeter Maydell     /*
6411d2386f7SPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
6421d2386f7SPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
6431d2386f7SPeter Maydell      */
6441d2386f7SPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
6451d2386f7SPeter Maydell         return false;
6461d2386f7SPeter Maydell     }
6471d2386f7SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
6481d2386f7SPeter Maydell         return true;
6491d2386f7SPeter Maydell     }
6501d2386f7SPeter Maydell 
6511d2386f7SPeter Maydell     qn = mve_qreg_ptr(a->qn);
6521d2386f7SPeter Maydell     qm = mve_qreg_ptr(a->qm);
6531d2386f7SPeter Maydell 
6541d2386f7SPeter Maydell     /*
6551d2386f7SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
6561d2386f7SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
6571d2386f7SPeter Maydell      * beat must start with the current rda value, not 0.
6581d2386f7SPeter Maydell      */
6591d2386f7SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
6601d2386f7SPeter Maydell         rda = tcg_temp_new_i64();
6611d2386f7SPeter Maydell         rdalo = load_reg(s, a->rdalo);
6621d2386f7SPeter Maydell         rdahi = load_reg(s, a->rdahi);
6631d2386f7SPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
6641d2386f7SPeter Maydell         tcg_temp_free_i32(rdalo);
6651d2386f7SPeter Maydell         tcg_temp_free_i32(rdahi);
6661d2386f7SPeter Maydell     } else {
6671d2386f7SPeter Maydell         rda = tcg_const_i64(0);
6681d2386f7SPeter Maydell     }
6691d2386f7SPeter Maydell 
6701d2386f7SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
6711d2386f7SPeter Maydell     tcg_temp_free_ptr(qn);
6721d2386f7SPeter Maydell     tcg_temp_free_ptr(qm);
6731d2386f7SPeter Maydell 
6741d2386f7SPeter Maydell     rdalo = tcg_temp_new_i32();
6751d2386f7SPeter Maydell     rdahi = tcg_temp_new_i32();
6761d2386f7SPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
6771d2386f7SPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
6781d2386f7SPeter Maydell     store_reg(s, a->rdalo, rdalo);
6791d2386f7SPeter Maydell     store_reg(s, a->rdahi, rdahi);
6801d2386f7SPeter Maydell     tcg_temp_free_i64(rda);
6811d2386f7SPeter Maydell     mve_update_eci(s);
6821d2386f7SPeter Maydell     return true;
6831d2386f7SPeter Maydell }
6841d2386f7SPeter Maydell 
6851d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a)
6861d2386f7SPeter Maydell {
6871d2386f7SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
6881d2386f7SPeter Maydell         { NULL, NULL },
6891d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh },
6901d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw },
6911d2386f7SPeter Maydell         { NULL, NULL },
6921d2386f7SPeter Maydell     };
6931d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
6941d2386f7SPeter Maydell }
6951d2386f7SPeter Maydell 
6961d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a)
6971d2386f7SPeter Maydell {
6981d2386f7SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
6991d2386f7SPeter Maydell         { NULL, NULL },
7001d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuh, NULL },
7011d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuw, NULL },
7021d2386f7SPeter Maydell         { NULL, NULL },
7031d2386f7SPeter Maydell     };
7041d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
7051d2386f7SPeter Maydell }
706181cd971SPeter Maydell 
707181cd971SPeter Maydell static bool trans_VMLSLDAV(DisasContext *s, arg_vmlaldav *a)
708181cd971SPeter Maydell {
709181cd971SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
710181cd971SPeter Maydell         { NULL, NULL },
711181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh },
712181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw },
713181cd971SPeter Maydell         { NULL, NULL },
714181cd971SPeter Maydell     };
715181cd971SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
716181cd971SPeter Maydell }
71738548747SPeter Maydell 
71838548747SPeter Maydell static bool trans_VRMLALDAVH_S(DisasContext *s, arg_vmlaldav *a)
71938548747SPeter Maydell {
72038548747SPeter Maydell     static MVEGenDualAccOpFn * const fns[] = {
72138548747SPeter Maydell         gen_helper_mve_vrmlaldavhsw, gen_helper_mve_vrmlaldavhxsw,
72238548747SPeter Maydell     };
72338548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
72438548747SPeter Maydell }
72538548747SPeter Maydell 
72638548747SPeter Maydell static bool trans_VRMLALDAVH_U(DisasContext *s, arg_vmlaldav *a)
72738548747SPeter Maydell {
72838548747SPeter Maydell     static MVEGenDualAccOpFn * const fns[] = {
72938548747SPeter Maydell         gen_helper_mve_vrmlaldavhuw, NULL,
73038548747SPeter Maydell     };
73138548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
73238548747SPeter Maydell }
73338548747SPeter Maydell 
73438548747SPeter Maydell static bool trans_VRMLSLDAVH(DisasContext *s, arg_vmlaldav *a)
73538548747SPeter Maydell {
73638548747SPeter Maydell     static MVEGenDualAccOpFn * const fns[] = {
73738548747SPeter Maydell         gen_helper_mve_vrmlsldavhsw, gen_helper_mve_vrmlsldavhxsw,
73838548747SPeter Maydell     };
73938548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
74038548747SPeter Maydell }
741387debdbSPeter Maydell 
74255251786SPeter Maydell static void gen_vpst(DisasContext *s, uint32_t mask)
743387debdbSPeter Maydell {
744387debdbSPeter Maydell     /*
745387debdbSPeter Maydell      * Set the VPR mask fields. We take advantage of MASK01 and MASK23
746387debdbSPeter Maydell      * being adjacent fields in the register.
747387debdbSPeter Maydell      *
74855251786SPeter Maydell      * Updating the masks is not predicated, but it is subject to beat-wise
749387debdbSPeter Maydell      * execution, and the mask is updated on the odd-numbered beats.
750387debdbSPeter Maydell      * So if PSR.ECI says we should skip beat 1, we mustn't update the
751387debdbSPeter Maydell      * 01 mask field.
752387debdbSPeter Maydell      */
75355251786SPeter Maydell     TCGv_i32 vpr = load_cpu_field(v7m.vpr);
754387debdbSPeter Maydell     switch (s->eci) {
755387debdbSPeter Maydell     case ECI_NONE:
756387debdbSPeter Maydell     case ECI_A0:
757387debdbSPeter Maydell         /* Update both 01 and 23 fields */
758387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
75955251786SPeter Maydell                             tcg_constant_i32(mask | (mask << 4)),
760387debdbSPeter Maydell                             R_V7M_VPR_MASK01_SHIFT,
761387debdbSPeter Maydell                             R_V7M_VPR_MASK01_LENGTH + R_V7M_VPR_MASK23_LENGTH);
762387debdbSPeter Maydell         break;
763387debdbSPeter Maydell     case ECI_A0A1:
764387debdbSPeter Maydell     case ECI_A0A1A2:
765387debdbSPeter Maydell     case ECI_A0A1A2B0:
766387debdbSPeter Maydell         /* Update only the 23 mask field */
767387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
76855251786SPeter Maydell                             tcg_constant_i32(mask),
769387debdbSPeter Maydell                             R_V7M_VPR_MASK23_SHIFT, R_V7M_VPR_MASK23_LENGTH);
770387debdbSPeter Maydell         break;
771387debdbSPeter Maydell     default:
772387debdbSPeter Maydell         g_assert_not_reached();
773387debdbSPeter Maydell     }
774387debdbSPeter Maydell     store_cpu_field(vpr, v7m.vpr);
77555251786SPeter Maydell }
77655251786SPeter Maydell 
77755251786SPeter Maydell static bool trans_VPST(DisasContext *s, arg_VPST *a)
77855251786SPeter Maydell {
77955251786SPeter Maydell     /* mask == 0 is a "related encoding" */
78055251786SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !a->mask) {
78155251786SPeter Maydell         return false;
78255251786SPeter Maydell     }
78355251786SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
78455251786SPeter Maydell         return true;
78555251786SPeter Maydell     }
78655251786SPeter Maydell     gen_vpst(s, a->mask);
787387debdbSPeter Maydell     mve_update_and_store_eci(s);
788387debdbSPeter Maydell     return true;
789387debdbSPeter Maydell }
7906f060a63SPeter Maydell 
7916f060a63SPeter Maydell static bool trans_VADDV(DisasContext *s, arg_VADDV *a)
7926f060a63SPeter Maydell {
7936f060a63SPeter Maydell     /* VADDV: vector add across vector */
7946f060a63SPeter Maydell     static MVEGenVADDVFn * const fns[4][2] = {
7956f060a63SPeter Maydell         { gen_helper_mve_vaddvsb, gen_helper_mve_vaddvub },
7966f060a63SPeter Maydell         { gen_helper_mve_vaddvsh, gen_helper_mve_vaddvuh },
7976f060a63SPeter Maydell         { gen_helper_mve_vaddvsw, gen_helper_mve_vaddvuw },
7986f060a63SPeter Maydell         { NULL, NULL }
7996f060a63SPeter Maydell     };
8006f060a63SPeter Maydell     TCGv_ptr qm;
8016f060a63SPeter Maydell     TCGv_i32 rda;
8026f060a63SPeter Maydell 
8036f060a63SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
8046f060a63SPeter Maydell         a->size == 3) {
8056f060a63SPeter Maydell         return false;
8066f060a63SPeter Maydell     }
8076f060a63SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
8086f060a63SPeter Maydell         return true;
8096f060a63SPeter Maydell     }
8106f060a63SPeter Maydell 
8116f060a63SPeter Maydell     /*
8126f060a63SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
8136f060a63SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
8146f060a63SPeter Maydell      * beat must start with the current value of Rda, not zero.
8156f060a63SPeter Maydell      */
8166f060a63SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
8176f060a63SPeter Maydell         /* Accumulate input from Rda */
8186f060a63SPeter Maydell         rda = load_reg(s, a->rda);
8196f060a63SPeter Maydell     } else {
8206f060a63SPeter Maydell         /* Accumulate starting at zero */
8216f060a63SPeter Maydell         rda = tcg_const_i32(0);
8226f060a63SPeter Maydell     }
8236f060a63SPeter Maydell 
8246f060a63SPeter Maydell     qm = mve_qreg_ptr(a->qm);
8256f060a63SPeter Maydell     fns[a->size][a->u](rda, cpu_env, qm, rda);
8266f060a63SPeter Maydell     store_reg(s, a->rda, rda);
8276f060a63SPeter Maydell     tcg_temp_free_ptr(qm);
8286f060a63SPeter Maydell 
8296f060a63SPeter Maydell     mve_update_eci(s);
8306f060a63SPeter Maydell     return true;
8316f060a63SPeter Maydell }
832eab84139SPeter Maydell 
833d43ebd9dSPeter Maydell static bool trans_VADDLV(DisasContext *s, arg_VADDLV *a)
834d43ebd9dSPeter Maydell {
835d43ebd9dSPeter Maydell     /*
836d43ebd9dSPeter Maydell      * Vector Add Long Across Vector: accumulate the 32-bit
837d43ebd9dSPeter Maydell      * elements of the vector into a 64-bit result stored in
838d43ebd9dSPeter Maydell      * a pair of general-purpose registers.
839d43ebd9dSPeter Maydell      * No need to check Qm's bank: it is only 3 bits in decode.
840d43ebd9dSPeter Maydell      */
841d43ebd9dSPeter Maydell     TCGv_ptr qm;
842d43ebd9dSPeter Maydell     TCGv_i64 rda;
843d43ebd9dSPeter Maydell     TCGv_i32 rdalo, rdahi;
844d43ebd9dSPeter Maydell 
845d43ebd9dSPeter Maydell     if (!dc_isar_feature(aa32_mve, s)) {
846d43ebd9dSPeter Maydell         return false;
847d43ebd9dSPeter Maydell     }
848d43ebd9dSPeter Maydell     /*
849d43ebd9dSPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
850d43ebd9dSPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
851d43ebd9dSPeter Maydell      */
852d43ebd9dSPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
853d43ebd9dSPeter Maydell         return false;
854d43ebd9dSPeter Maydell     }
855d43ebd9dSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
856d43ebd9dSPeter Maydell         return true;
857d43ebd9dSPeter Maydell     }
858d43ebd9dSPeter Maydell 
859d43ebd9dSPeter Maydell     /*
860d43ebd9dSPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
861d43ebd9dSPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
862d43ebd9dSPeter Maydell      * beat must start with the current value of RdaHi:RdaLo, not zero.
863d43ebd9dSPeter Maydell      */
864d43ebd9dSPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
865d43ebd9dSPeter Maydell         /* Accumulate input from RdaHi:RdaLo */
866d43ebd9dSPeter Maydell         rda = tcg_temp_new_i64();
867d43ebd9dSPeter Maydell         rdalo = load_reg(s, a->rdalo);
868d43ebd9dSPeter Maydell         rdahi = load_reg(s, a->rdahi);
869d43ebd9dSPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
870d43ebd9dSPeter Maydell         tcg_temp_free_i32(rdalo);
871d43ebd9dSPeter Maydell         tcg_temp_free_i32(rdahi);
872d43ebd9dSPeter Maydell     } else {
873d43ebd9dSPeter Maydell         /* Accumulate starting at zero */
874d43ebd9dSPeter Maydell         rda = tcg_const_i64(0);
875d43ebd9dSPeter Maydell     }
876d43ebd9dSPeter Maydell 
877d43ebd9dSPeter Maydell     qm = mve_qreg_ptr(a->qm);
878d43ebd9dSPeter Maydell     if (a->u) {
879d43ebd9dSPeter Maydell         gen_helper_mve_vaddlv_u(rda, cpu_env, qm, rda);
880d43ebd9dSPeter Maydell     } else {
881d43ebd9dSPeter Maydell         gen_helper_mve_vaddlv_s(rda, cpu_env, qm, rda);
882d43ebd9dSPeter Maydell     }
883d43ebd9dSPeter Maydell     tcg_temp_free_ptr(qm);
884d43ebd9dSPeter Maydell 
885d43ebd9dSPeter Maydell     rdalo = tcg_temp_new_i32();
886d43ebd9dSPeter Maydell     rdahi = tcg_temp_new_i32();
887d43ebd9dSPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
888d43ebd9dSPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
889d43ebd9dSPeter Maydell     store_reg(s, a->rdalo, rdalo);
890d43ebd9dSPeter Maydell     store_reg(s, a->rdahi, rdahi);
891d43ebd9dSPeter Maydell     tcg_temp_free_i64(rda);
892d43ebd9dSPeter Maydell     mve_update_eci(s);
893d43ebd9dSPeter Maydell     return true;
894d43ebd9dSPeter Maydell }
895d43ebd9dSPeter Maydell 
896eab84139SPeter Maydell static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
897eab84139SPeter Maydell {
898eab84139SPeter Maydell     TCGv_ptr qd;
899eab84139SPeter Maydell     uint64_t imm;
900eab84139SPeter Maydell 
901eab84139SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
902eab84139SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
903eab84139SPeter Maydell         !fn) {
904eab84139SPeter Maydell         return false;
905eab84139SPeter Maydell     }
906eab84139SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
907eab84139SPeter Maydell         return true;
908eab84139SPeter Maydell     }
909eab84139SPeter Maydell 
910eab84139SPeter Maydell     imm = asimd_imm_const(a->imm, a->cmode, a->op);
911eab84139SPeter Maydell 
912eab84139SPeter Maydell     qd = mve_qreg_ptr(a->qd);
913eab84139SPeter Maydell     fn(cpu_env, qd, tcg_constant_i64(imm));
914eab84139SPeter Maydell     tcg_temp_free_ptr(qd);
915eab84139SPeter Maydell     mve_update_eci(s);
916eab84139SPeter Maydell     return true;
917eab84139SPeter Maydell }
918eab84139SPeter Maydell 
919eab84139SPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
920eab84139SPeter Maydell {
921eab84139SPeter Maydell     /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
922eab84139SPeter Maydell     MVEGenOneOpImmFn *fn;
923eab84139SPeter Maydell 
924eab84139SPeter Maydell     if ((a->cmode & 1) && a->cmode < 12) {
925eab84139SPeter Maydell         if (a->op) {
926eab84139SPeter Maydell             /*
927eab84139SPeter Maydell              * For op=1, the immediate will be inverted by asimd_imm_const(),
928eab84139SPeter Maydell              * so the VBIC becomes a logical AND operation.
929eab84139SPeter Maydell              */
930eab84139SPeter Maydell             fn = gen_helper_mve_vandi;
931eab84139SPeter Maydell         } else {
932eab84139SPeter Maydell             fn = gen_helper_mve_vorri;
933eab84139SPeter Maydell         }
934eab84139SPeter Maydell     } else {
935eab84139SPeter Maydell         /* There is one unallocated cmode/op combination in this space */
936eab84139SPeter Maydell         if (a->cmode == 15 && a->op == 1) {
937eab84139SPeter Maydell             return false;
938eab84139SPeter Maydell         }
939eab84139SPeter Maydell         /* asimd_imm_const() sorts out VMVNI vs VMOVI for us */
940eab84139SPeter Maydell         fn = gen_helper_mve_vmovi;
941eab84139SPeter Maydell     }
942eab84139SPeter Maydell     return do_1imm(s, a, fn);
943eab84139SPeter Maydell }
944f9ed6174SPeter Maydell 
945f9ed6174SPeter Maydell static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
946f9ed6174SPeter Maydell                       bool negateshift)
947f9ed6174SPeter Maydell {
948f9ed6174SPeter Maydell     TCGv_ptr qd, qm;
949f9ed6174SPeter Maydell     int shift = a->shift;
950f9ed6174SPeter Maydell 
951f9ed6174SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
952f9ed6174SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
953f9ed6174SPeter Maydell         !fn) {
954f9ed6174SPeter Maydell         return false;
955f9ed6174SPeter Maydell     }
956f9ed6174SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
957f9ed6174SPeter Maydell         return true;
958f9ed6174SPeter Maydell     }
959f9ed6174SPeter Maydell 
960f9ed6174SPeter Maydell     /*
961f9ed6174SPeter Maydell      * When we handle a right shift insn using a left-shift helper
962f9ed6174SPeter Maydell      * which permits a negative shift count to indicate a right-shift,
963f9ed6174SPeter Maydell      * we must negate the shift count.
964f9ed6174SPeter Maydell      */
965f9ed6174SPeter Maydell     if (negateshift) {
966f9ed6174SPeter Maydell         shift = -shift;
967f9ed6174SPeter Maydell     }
968f9ed6174SPeter Maydell 
969f9ed6174SPeter Maydell     qd = mve_qreg_ptr(a->qd);
970f9ed6174SPeter Maydell     qm = mve_qreg_ptr(a->qm);
971f9ed6174SPeter Maydell     fn(cpu_env, qd, qm, tcg_constant_i32(shift));
972f9ed6174SPeter Maydell     tcg_temp_free_ptr(qd);
973f9ed6174SPeter Maydell     tcg_temp_free_ptr(qm);
974f9ed6174SPeter Maydell     mve_update_eci(s);
975f9ed6174SPeter Maydell     return true;
976f9ed6174SPeter Maydell }
977f9ed6174SPeter Maydell 
978f9ed6174SPeter Maydell #define DO_2SHIFT(INSN, FN, NEGATESHIFT)                         \
979f9ed6174SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
980f9ed6174SPeter Maydell     {                                                           \
981f9ed6174SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
982f9ed6174SPeter Maydell             gen_helper_mve_##FN##b,                             \
983f9ed6174SPeter Maydell             gen_helper_mve_##FN##h,                             \
984f9ed6174SPeter Maydell             gen_helper_mve_##FN##w,                             \
985f9ed6174SPeter Maydell             NULL,                                               \
986f9ed6174SPeter Maydell         };                                                      \
987f9ed6174SPeter Maydell         return do_2shift(s, a, fns[a->size], NEGATESHIFT);      \
988f9ed6174SPeter Maydell     }
989f9ed6174SPeter Maydell 
990f9ed6174SPeter Maydell DO_2SHIFT(VSHLI, vshli_u, false)
991f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_S, vqshli_s, false)
992f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_U, vqshli_u, false)
993f9ed6174SPeter Maydell DO_2SHIFT(VQSHLUI, vqshlui_s, false)
9943394116fSPeter Maydell /* These right shifts use a left-shift helper with negated shift count */
9953394116fSPeter Maydell DO_2SHIFT(VSHRI_S, vshli_s, true)
9963394116fSPeter Maydell DO_2SHIFT(VSHRI_U, vshli_u, true)
9973394116fSPeter Maydell DO_2SHIFT(VRSHRI_S, vrshli_s, true)
9983394116fSPeter Maydell DO_2SHIFT(VRSHRI_U, vrshli_u, true)
999c2262707SPeter Maydell 
1000a78b25faSPeter Maydell DO_2SHIFT(VSRI, vsri, false)
1001a78b25faSPeter Maydell DO_2SHIFT(VSLI, vsli, false)
1002a78b25faSPeter Maydell 
1003c2262707SPeter Maydell #define DO_VSHLL(INSN, FN)                                      \
1004c2262707SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1005c2262707SPeter Maydell     {                                                           \
1006c2262707SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1007c2262707SPeter Maydell             gen_helper_mve_##FN##b,                             \
1008c2262707SPeter Maydell             gen_helper_mve_##FN##h,                             \
1009c2262707SPeter Maydell         };                                                      \
1010c2262707SPeter Maydell         return do_2shift(s, a, fns[a->size], false);            \
1011c2262707SPeter Maydell     }
1012c2262707SPeter Maydell 
1013c2262707SPeter Maydell DO_VSHLL(VSHLL_BS, vshllbs)
1014c2262707SPeter Maydell DO_VSHLL(VSHLL_BU, vshllbu)
1015c2262707SPeter Maydell DO_VSHLL(VSHLL_TS, vshllts)
1016c2262707SPeter Maydell DO_VSHLL(VSHLL_TU, vshlltu)
1017162e2655SPeter Maydell 
1018162e2655SPeter Maydell #define DO_2SHIFT_N(INSN, FN)                                   \
1019162e2655SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1020162e2655SPeter Maydell     {                                                           \
1021162e2655SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1022162e2655SPeter Maydell             gen_helper_mve_##FN##b,                             \
1023162e2655SPeter Maydell             gen_helper_mve_##FN##h,                             \
1024162e2655SPeter Maydell         };                                                      \
1025162e2655SPeter Maydell         return do_2shift(s, a, fns[a->size], false);            \
1026162e2655SPeter Maydell     }
1027162e2655SPeter Maydell 
1028162e2655SPeter Maydell DO_2SHIFT_N(VSHRNB, vshrnb)
1029162e2655SPeter Maydell DO_2SHIFT_N(VSHRNT, vshrnt)
1030162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNB, vrshrnb)
1031162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNT, vrshrnt)
1032d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_S, vqshrnb_s)
1033d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_S, vqshrnt_s)
1034d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_U, vqshrnb_u)
1035d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_U, vqshrnt_u)
1036d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNB, vqshrunb)
1037d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNT, vqshrunt)
1038d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_S, vqrshrnb_s)
1039d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_S, vqrshrnt_s)
1040d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_U, vqrshrnb_u)
1041d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_U, vqrshrnt_u)
1042d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNB, vqrshrunb)
1043d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNT, vqrshrunt)
10442e6a4ce0SPeter Maydell 
10452e6a4ce0SPeter Maydell static bool trans_VSHLC(DisasContext *s, arg_VSHLC *a)
10462e6a4ce0SPeter Maydell {
10472e6a4ce0SPeter Maydell     /*
10482e6a4ce0SPeter Maydell      * Whole Vector Left Shift with Carry. The carry is taken
10492e6a4ce0SPeter Maydell      * from a general purpose register and written back there.
10502e6a4ce0SPeter Maydell      * An imm of 0 means "shift by 32".
10512e6a4ce0SPeter Maydell      */
10522e6a4ce0SPeter Maydell     TCGv_ptr qd;
10532e6a4ce0SPeter Maydell     TCGv_i32 rdm;
10542e6a4ce0SPeter Maydell 
10552e6a4ce0SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
10562e6a4ce0SPeter Maydell         return false;
10572e6a4ce0SPeter Maydell     }
10582e6a4ce0SPeter Maydell     if (a->rdm == 13 || a->rdm == 15) {
10592e6a4ce0SPeter Maydell         /* CONSTRAINED UNPREDICTABLE: we UNDEF */
10602e6a4ce0SPeter Maydell         return false;
10612e6a4ce0SPeter Maydell     }
10622e6a4ce0SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
10632e6a4ce0SPeter Maydell         return true;
10642e6a4ce0SPeter Maydell     }
10652e6a4ce0SPeter Maydell 
10662e6a4ce0SPeter Maydell     qd = mve_qreg_ptr(a->qd);
10672e6a4ce0SPeter Maydell     rdm = load_reg(s, a->rdm);
10682e6a4ce0SPeter Maydell     gen_helper_mve_vshlc(rdm, cpu_env, qd, rdm, tcg_constant_i32(a->imm));
10692e6a4ce0SPeter Maydell     store_reg(s, a->rdm, rdm);
10702e6a4ce0SPeter Maydell     tcg_temp_free_ptr(qd);
10712e6a4ce0SPeter Maydell     mve_update_eci(s);
10722e6a4ce0SPeter Maydell     return true;
10732e6a4ce0SPeter Maydell }
1074395b92d5SPeter Maydell 
1075395b92d5SPeter Maydell static bool do_vidup(DisasContext *s, arg_vidup *a, MVEGenVIDUPFn *fn)
1076395b92d5SPeter Maydell {
1077395b92d5SPeter Maydell     TCGv_ptr qd;
1078395b92d5SPeter Maydell     TCGv_i32 rn;
1079395b92d5SPeter Maydell 
1080395b92d5SPeter Maydell     /*
1081395b92d5SPeter Maydell      * Vector increment/decrement with wrap and duplicate (VIDUP, VDDUP).
1082395b92d5SPeter Maydell      * This fills the vector with elements of successively increasing
1083395b92d5SPeter Maydell      * or decreasing values, starting from Rn.
1084395b92d5SPeter Maydell      */
1085395b92d5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
1086395b92d5SPeter Maydell         return false;
1087395b92d5SPeter Maydell     }
1088395b92d5SPeter Maydell     if (a->size == MO_64) {
1089395b92d5SPeter Maydell         /* size 0b11 is another encoding */
1090395b92d5SPeter Maydell         return false;
1091395b92d5SPeter Maydell     }
1092395b92d5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1093395b92d5SPeter Maydell         return true;
1094395b92d5SPeter Maydell     }
1095395b92d5SPeter Maydell 
1096395b92d5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1097395b92d5SPeter Maydell     rn = load_reg(s, a->rn);
1098395b92d5SPeter Maydell     fn(rn, cpu_env, qd, rn, tcg_constant_i32(a->imm));
1099395b92d5SPeter Maydell     store_reg(s, a->rn, rn);
1100395b92d5SPeter Maydell     tcg_temp_free_ptr(qd);
1101395b92d5SPeter Maydell     mve_update_eci(s);
1102395b92d5SPeter Maydell     return true;
1103395b92d5SPeter Maydell }
1104395b92d5SPeter Maydell 
1105395b92d5SPeter Maydell static bool do_viwdup(DisasContext *s, arg_viwdup *a, MVEGenVIWDUPFn *fn)
1106395b92d5SPeter Maydell {
1107395b92d5SPeter Maydell     TCGv_ptr qd;
1108395b92d5SPeter Maydell     TCGv_i32 rn, rm;
1109395b92d5SPeter Maydell 
1110395b92d5SPeter Maydell     /*
1111395b92d5SPeter Maydell      * Vector increment/decrement with wrap and duplicate (VIWDUp, VDWDUP)
1112395b92d5SPeter Maydell      * This fills the vector with elements of successively increasing
1113395b92d5SPeter Maydell      * or decreasing values, starting from Rn. Rm specifies a point where
1114395b92d5SPeter Maydell      * the count wraps back around to 0. The updated offset is written back
1115395b92d5SPeter Maydell      * to Rn.
1116395b92d5SPeter Maydell      */
1117395b92d5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
1118395b92d5SPeter Maydell         return false;
1119395b92d5SPeter Maydell     }
1120395b92d5SPeter Maydell     if (!fn || a->rm == 13 || a->rm == 15) {
1121395b92d5SPeter Maydell         /*
1122395b92d5SPeter Maydell          * size 0b11 is another encoding; Rm == 13 is UNPREDICTABLE;
1123395b92d5SPeter Maydell          * Rm == 13 is VIWDUP, VDWDUP.
1124395b92d5SPeter Maydell          */
1125395b92d5SPeter Maydell         return false;
1126395b92d5SPeter Maydell     }
1127395b92d5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1128395b92d5SPeter Maydell         return true;
1129395b92d5SPeter Maydell     }
1130395b92d5SPeter Maydell 
1131395b92d5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1132395b92d5SPeter Maydell     rn = load_reg(s, a->rn);
1133395b92d5SPeter Maydell     rm = load_reg(s, a->rm);
1134395b92d5SPeter Maydell     fn(rn, cpu_env, qd, rn, rm, tcg_constant_i32(a->imm));
1135395b92d5SPeter Maydell     store_reg(s, a->rn, rn);
1136395b92d5SPeter Maydell     tcg_temp_free_ptr(qd);
1137395b92d5SPeter Maydell     tcg_temp_free_i32(rm);
1138395b92d5SPeter Maydell     mve_update_eci(s);
1139395b92d5SPeter Maydell     return true;
1140395b92d5SPeter Maydell }
1141395b92d5SPeter Maydell 
1142395b92d5SPeter Maydell static bool trans_VIDUP(DisasContext *s, arg_vidup *a)
1143395b92d5SPeter Maydell {
1144395b92d5SPeter Maydell     static MVEGenVIDUPFn * const fns[] = {
1145395b92d5SPeter Maydell         gen_helper_mve_vidupb,
1146395b92d5SPeter Maydell         gen_helper_mve_viduph,
1147395b92d5SPeter Maydell         gen_helper_mve_vidupw,
1148395b92d5SPeter Maydell         NULL,
1149395b92d5SPeter Maydell     };
1150395b92d5SPeter Maydell     return do_vidup(s, a, fns[a->size]);
1151395b92d5SPeter Maydell }
1152395b92d5SPeter Maydell 
1153395b92d5SPeter Maydell static bool trans_VDDUP(DisasContext *s, arg_vidup *a)
1154395b92d5SPeter Maydell {
1155395b92d5SPeter Maydell     static MVEGenVIDUPFn * const fns[] = {
1156395b92d5SPeter Maydell         gen_helper_mve_vidupb,
1157395b92d5SPeter Maydell         gen_helper_mve_viduph,
1158395b92d5SPeter Maydell         gen_helper_mve_vidupw,
1159395b92d5SPeter Maydell         NULL,
1160395b92d5SPeter Maydell     };
1161395b92d5SPeter Maydell     /* VDDUP is just like VIDUP but with a negative immediate */
1162395b92d5SPeter Maydell     a->imm = -a->imm;
1163395b92d5SPeter Maydell     return do_vidup(s, a, fns[a->size]);
1164395b92d5SPeter Maydell }
1165395b92d5SPeter Maydell 
1166395b92d5SPeter Maydell static bool trans_VIWDUP(DisasContext *s, arg_viwdup *a)
1167395b92d5SPeter Maydell {
1168395b92d5SPeter Maydell     static MVEGenVIWDUPFn * const fns[] = {
1169395b92d5SPeter Maydell         gen_helper_mve_viwdupb,
1170395b92d5SPeter Maydell         gen_helper_mve_viwduph,
1171395b92d5SPeter Maydell         gen_helper_mve_viwdupw,
1172395b92d5SPeter Maydell         NULL,
1173395b92d5SPeter Maydell     };
1174395b92d5SPeter Maydell     return do_viwdup(s, a, fns[a->size]);
1175395b92d5SPeter Maydell }
1176395b92d5SPeter Maydell 
1177395b92d5SPeter Maydell static bool trans_VDWDUP(DisasContext *s, arg_viwdup *a)
1178395b92d5SPeter Maydell {
1179395b92d5SPeter Maydell     static MVEGenVIWDUPFn * const fns[] = {
1180395b92d5SPeter Maydell         gen_helper_mve_vdwdupb,
1181395b92d5SPeter Maydell         gen_helper_mve_vdwduph,
1182395b92d5SPeter Maydell         gen_helper_mve_vdwdupw,
1183395b92d5SPeter Maydell         NULL,
1184395b92d5SPeter Maydell     };
1185395b92d5SPeter Maydell     return do_viwdup(s, a, fns[a->size]);
1186395b92d5SPeter Maydell }
1187eff5d9a9SPeter Maydell 
1188eff5d9a9SPeter Maydell static bool do_vcmp(DisasContext *s, arg_vcmp *a, MVEGenCmpFn *fn)
1189eff5d9a9SPeter Maydell {
1190eff5d9a9SPeter Maydell     TCGv_ptr qn, qm;
1191eff5d9a9SPeter Maydell 
1192eff5d9a9SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qm) ||
1193eff5d9a9SPeter Maydell         !fn) {
1194eff5d9a9SPeter Maydell         return false;
1195eff5d9a9SPeter Maydell     }
1196eff5d9a9SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1197eff5d9a9SPeter Maydell         return true;
1198eff5d9a9SPeter Maydell     }
1199eff5d9a9SPeter Maydell 
1200eff5d9a9SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1201eff5d9a9SPeter Maydell     qm = mve_qreg_ptr(a->qm);
1202eff5d9a9SPeter Maydell     fn(cpu_env, qn, qm);
1203eff5d9a9SPeter Maydell     tcg_temp_free_ptr(qn);
1204eff5d9a9SPeter Maydell     tcg_temp_free_ptr(qm);
1205eff5d9a9SPeter Maydell     if (a->mask) {
1206eff5d9a9SPeter Maydell         /* VPT */
1207eff5d9a9SPeter Maydell         gen_vpst(s, a->mask);
1208eff5d9a9SPeter Maydell     }
1209eff5d9a9SPeter Maydell     mve_update_eci(s);
1210eff5d9a9SPeter Maydell     return true;
1211eff5d9a9SPeter Maydell }
1212eff5d9a9SPeter Maydell 
1213*cce81873SPeter Maydell static bool do_vcmp_scalar(DisasContext *s, arg_vcmp_scalar *a,
1214*cce81873SPeter Maydell                            MVEGenScalarCmpFn *fn)
1215*cce81873SPeter Maydell {
1216*cce81873SPeter Maydell     TCGv_ptr qn;
1217*cce81873SPeter Maydell     TCGv_i32 rm;
1218*cce81873SPeter Maydell 
1219*cce81873SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !fn || a->rm == 13) {
1220*cce81873SPeter Maydell         return false;
1221*cce81873SPeter Maydell     }
1222*cce81873SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1223*cce81873SPeter Maydell         return true;
1224*cce81873SPeter Maydell     }
1225*cce81873SPeter Maydell 
1226*cce81873SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1227*cce81873SPeter Maydell     if (a->rm == 15) {
1228*cce81873SPeter Maydell         /* Encoding Rm=0b1111 means "constant zero" */
1229*cce81873SPeter Maydell         rm = tcg_constant_i32(0);
1230*cce81873SPeter Maydell     } else {
1231*cce81873SPeter Maydell         rm = load_reg(s, a->rm);
1232*cce81873SPeter Maydell     }
1233*cce81873SPeter Maydell     fn(cpu_env, qn, rm);
1234*cce81873SPeter Maydell     tcg_temp_free_ptr(qn);
1235*cce81873SPeter Maydell     tcg_temp_free_i32(rm);
1236*cce81873SPeter Maydell     if (a->mask) {
1237*cce81873SPeter Maydell         /* VPT */
1238*cce81873SPeter Maydell         gen_vpst(s, a->mask);
1239*cce81873SPeter Maydell     }
1240*cce81873SPeter Maydell     mve_update_eci(s);
1241*cce81873SPeter Maydell     return true;
1242*cce81873SPeter Maydell }
1243*cce81873SPeter Maydell 
1244eff5d9a9SPeter Maydell #define DO_VCMP(INSN, FN)                                       \
1245eff5d9a9SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vcmp *a)      \
1246eff5d9a9SPeter Maydell     {                                                           \
1247eff5d9a9SPeter Maydell         static MVEGenCmpFn * const fns[] = {                    \
1248eff5d9a9SPeter Maydell             gen_helper_mve_##FN##b,                             \
1249eff5d9a9SPeter Maydell             gen_helper_mve_##FN##h,                             \
1250eff5d9a9SPeter Maydell             gen_helper_mve_##FN##w,                             \
1251eff5d9a9SPeter Maydell             NULL,                                               \
1252eff5d9a9SPeter Maydell         };                                                      \
1253eff5d9a9SPeter Maydell         return do_vcmp(s, a, fns[a->size]);                     \
1254*cce81873SPeter Maydell     }                                                           \
1255*cce81873SPeter Maydell     static bool trans_##INSN##_scalar(DisasContext *s,          \
1256*cce81873SPeter Maydell                                       arg_vcmp_scalar *a)       \
1257*cce81873SPeter Maydell     {                                                           \
1258*cce81873SPeter Maydell         static MVEGenScalarCmpFn * const fns[] = {              \
1259*cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarb,                      \
1260*cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarh,                      \
1261*cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarw,                      \
1262*cce81873SPeter Maydell             NULL,                                               \
1263*cce81873SPeter Maydell         };                                                      \
1264*cce81873SPeter Maydell         return do_vcmp_scalar(s, a, fns[a->size]);              \
1265eff5d9a9SPeter Maydell     }
1266eff5d9a9SPeter Maydell 
1267eff5d9a9SPeter Maydell DO_VCMP(VCMPEQ, vcmpeq)
1268eff5d9a9SPeter Maydell DO_VCMP(VCMPNE, vcmpne)
1269eff5d9a9SPeter Maydell DO_VCMP(VCMPCS, vcmpcs)
1270eff5d9a9SPeter Maydell DO_VCMP(VCMPHI, vcmphi)
1271eff5d9a9SPeter Maydell DO_VCMP(VCMPGE, vcmpge)
1272eff5d9a9SPeter Maydell DO_VCMP(VCMPLT, vcmplt)
1273eff5d9a9SPeter Maydell DO_VCMP(VCMPGT, vcmpgt)
1274eff5d9a9SPeter Maydell DO_VCMP(VCMPLE, vcmple)
1275