xref: /qemu/target/arm/tcg/translate-mve.c (revision f9ed61741e5f26ee1bb933a87669697901d9327d)
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 
286390eed4SPeter Maydell /* Include the generated decoder */
296390eed4SPeter Maydell #include "decode-mve.c.inc"
30507b6a50SPeter Maydell 
31507b6a50SPeter Maydell typedef void MVEGenLdStFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
320f0f2bd5SPeter Maydell typedef void MVEGenOneOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
3368245e44SPeter Maydell typedef void MVEGenTwoOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr);
34e51896b3SPeter Maydell typedef void MVEGenTwoOpScalarFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
35*f9ed6174SPeter Maydell typedef void MVEGenTwoOpShiftFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
361d2386f7SPeter Maydell typedef void MVEGenDualAccOpFn(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64);
376f060a63SPeter Maydell typedef void MVEGenVADDVFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32);
38eab84139SPeter Maydell typedef void MVEGenOneOpImmFn(TCGv_ptr, TCGv_ptr, TCGv_i64);
39507b6a50SPeter Maydell 
40507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */
41507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg)
42507b6a50SPeter Maydell {
43507b6a50SPeter Maydell     return offsetof(CPUARMState, vfp.zregs[reg].d[0]);
44507b6a50SPeter Maydell }
45507b6a50SPeter Maydell 
46507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg)
47507b6a50SPeter Maydell {
48507b6a50SPeter Maydell     TCGv_ptr ret = tcg_temp_new_ptr();
49507b6a50SPeter Maydell     tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg));
50507b6a50SPeter Maydell     return ret;
51507b6a50SPeter Maydell }
52507b6a50SPeter Maydell 
53507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask)
54507b6a50SPeter Maydell {
55507b6a50SPeter Maydell     /*
56507b6a50SPeter Maydell      * Check whether Qregs are in range. For v8.1M only Q0..Q7
57507b6a50SPeter Maydell      * are supported, see VFPSmallRegisterBank().
58507b6a50SPeter Maydell      */
59507b6a50SPeter Maydell     return qmask < 8;
60507b6a50SPeter Maydell }
61507b6a50SPeter Maydell 
624f57ef95SPeter Maydell bool mve_eci_check(DisasContext *s)
63507b6a50SPeter Maydell {
64507b6a50SPeter Maydell     /*
65507b6a50SPeter Maydell      * This is a beatwise insn: check that ECI is valid (not a
66507b6a50SPeter Maydell      * reserved value) and note that we are handling it.
67507b6a50SPeter Maydell      * Return true if OK, false if we generated an exception.
68507b6a50SPeter Maydell      */
69507b6a50SPeter Maydell     s->eci_handled = true;
70507b6a50SPeter Maydell     switch (s->eci) {
71507b6a50SPeter Maydell     case ECI_NONE:
72507b6a50SPeter Maydell     case ECI_A0:
73507b6a50SPeter Maydell     case ECI_A0A1:
74507b6a50SPeter Maydell     case ECI_A0A1A2:
75507b6a50SPeter Maydell     case ECI_A0A1A2B0:
76507b6a50SPeter Maydell         return true;
77507b6a50SPeter Maydell     default:
78507b6a50SPeter Maydell         /* Reserved value: INVSTATE UsageFault */
79507b6a50SPeter Maydell         gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(),
80507b6a50SPeter Maydell                            default_exception_el(s));
81507b6a50SPeter Maydell         return false;
82507b6a50SPeter Maydell     }
83507b6a50SPeter Maydell }
84507b6a50SPeter Maydell 
85507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s)
86507b6a50SPeter Maydell {
87507b6a50SPeter Maydell     /*
88507b6a50SPeter Maydell      * The helper function will always update the CPUState field,
89507b6a50SPeter Maydell      * so we only need to update the DisasContext field.
90507b6a50SPeter Maydell      */
91507b6a50SPeter Maydell     if (s->eci) {
92507b6a50SPeter Maydell         s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE;
93507b6a50SPeter Maydell     }
94507b6a50SPeter Maydell }
95507b6a50SPeter Maydell 
964f57ef95SPeter Maydell void mve_update_and_store_eci(DisasContext *s)
97387debdbSPeter Maydell {
98387debdbSPeter Maydell     /*
99387debdbSPeter Maydell      * For insns which don't call a helper function that will call
100387debdbSPeter Maydell      * mve_advance_vpt(), this version updates s->eci and also stores
101387debdbSPeter Maydell      * it out to the CPUState field.
102387debdbSPeter Maydell      */
103387debdbSPeter Maydell     if (s->eci) {
104387debdbSPeter Maydell         mve_update_eci(s);
105387debdbSPeter Maydell         store_cpu_field(tcg_constant_i32(s->eci << 4), condexec_bits);
106387debdbSPeter Maydell     }
107387debdbSPeter Maydell }
108387debdbSPeter Maydell 
1091d2386f7SPeter Maydell static bool mve_skip_first_beat(DisasContext *s)
1101d2386f7SPeter Maydell {
1111d2386f7SPeter Maydell     /* Return true if PSR.ECI says we must skip the first beat of this insn */
1121d2386f7SPeter Maydell     switch (s->eci) {
1131d2386f7SPeter Maydell     case ECI_NONE:
1141d2386f7SPeter Maydell         return false;
1151d2386f7SPeter Maydell     case ECI_A0:
1161d2386f7SPeter Maydell     case ECI_A0A1:
1171d2386f7SPeter Maydell     case ECI_A0A1A2:
1181d2386f7SPeter Maydell     case ECI_A0A1A2B0:
1191d2386f7SPeter Maydell         return true;
1201d2386f7SPeter Maydell     default:
1211d2386f7SPeter Maydell         g_assert_not_reached();
1221d2386f7SPeter Maydell     }
1231d2386f7SPeter Maydell }
1241d2386f7SPeter Maydell 
125d59ccc30SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn,
126d59ccc30SPeter Maydell                     unsigned msize)
127507b6a50SPeter Maydell {
128507b6a50SPeter Maydell     TCGv_i32 addr;
129507b6a50SPeter Maydell     uint32_t offset;
130507b6a50SPeter Maydell     TCGv_ptr qreg;
131507b6a50SPeter Maydell 
132507b6a50SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
133507b6a50SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
134507b6a50SPeter Maydell         !fn) {
135507b6a50SPeter Maydell         return false;
136507b6a50SPeter Maydell     }
137507b6a50SPeter Maydell 
138507b6a50SPeter Maydell     /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
139507b6a50SPeter Maydell     if (a->rn == 15 || (a->rn == 13 && a->w)) {
140507b6a50SPeter Maydell         return false;
141507b6a50SPeter Maydell     }
142507b6a50SPeter Maydell 
143507b6a50SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
144507b6a50SPeter Maydell         return true;
145507b6a50SPeter Maydell     }
146507b6a50SPeter Maydell 
147d59ccc30SPeter Maydell     offset = a->imm << msize;
148507b6a50SPeter Maydell     if (!a->a) {
149507b6a50SPeter Maydell         offset = -offset;
150507b6a50SPeter Maydell     }
151507b6a50SPeter Maydell     addr = load_reg(s, a->rn);
152507b6a50SPeter Maydell     if (a->p) {
153507b6a50SPeter Maydell         tcg_gen_addi_i32(addr, addr, offset);
154507b6a50SPeter Maydell     }
155507b6a50SPeter Maydell 
156507b6a50SPeter Maydell     qreg = mve_qreg_ptr(a->qd);
157507b6a50SPeter Maydell     fn(cpu_env, qreg, addr);
158507b6a50SPeter Maydell     tcg_temp_free_ptr(qreg);
159507b6a50SPeter Maydell 
160507b6a50SPeter Maydell     /*
161507b6a50SPeter Maydell      * Writeback always happens after the last beat of the insn,
162507b6a50SPeter Maydell      * regardless of predication
163507b6a50SPeter Maydell      */
164507b6a50SPeter Maydell     if (a->w) {
165507b6a50SPeter Maydell         if (!a->p) {
166507b6a50SPeter Maydell             tcg_gen_addi_i32(addr, addr, offset);
167507b6a50SPeter Maydell         }
168507b6a50SPeter Maydell         store_reg(s, a->rn, addr);
169507b6a50SPeter Maydell     } else {
170507b6a50SPeter Maydell         tcg_temp_free_i32(addr);
171507b6a50SPeter Maydell     }
172507b6a50SPeter Maydell     mve_update_eci(s);
173507b6a50SPeter Maydell     return true;
174507b6a50SPeter Maydell }
175507b6a50SPeter Maydell 
176507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a)
177507b6a50SPeter Maydell {
178507b6a50SPeter Maydell     static MVEGenLdStFn * const ldstfns[4][2] = {
179507b6a50SPeter Maydell         { gen_helper_mve_vstrb, gen_helper_mve_vldrb },
180507b6a50SPeter Maydell         { gen_helper_mve_vstrh, gen_helper_mve_vldrh },
181507b6a50SPeter Maydell         { gen_helper_mve_vstrw, gen_helper_mve_vldrw },
182507b6a50SPeter Maydell         { NULL, NULL }
183507b6a50SPeter Maydell     };
184d59ccc30SPeter Maydell     return do_ldst(s, a, ldstfns[a->size][a->l], a->size);
185507b6a50SPeter Maydell }
1862fc6b751SPeter Maydell 
187d59ccc30SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST, MSIZE)           \
1882fc6b751SPeter Maydell     static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a)   \
1892fc6b751SPeter Maydell     {                                                           \
1902fc6b751SPeter Maydell         static MVEGenLdStFn * const ldstfns[2][2] = {           \
1912fc6b751SPeter Maydell             { gen_helper_mve_##ST, gen_helper_mve_##SLD },      \
1922fc6b751SPeter Maydell             { NULL, gen_helper_mve_##ULD },                     \
1932fc6b751SPeter Maydell         };                                                      \
194d59ccc30SPeter Maydell         return do_ldst(s, a, ldstfns[a->u][a->l], MSIZE);       \
1952fc6b751SPeter Maydell     }
1962fc6b751SPeter Maydell 
197d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h, MO_8)
198d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w, MO_8)
199d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w, MO_16)
2000f0f2bd5SPeter Maydell 
201ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
202ab59362fSPeter Maydell {
203ab59362fSPeter Maydell     TCGv_ptr qd;
204ab59362fSPeter Maydell     TCGv_i32 rt;
205ab59362fSPeter Maydell 
206ab59362fSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
207ab59362fSPeter Maydell         !mve_check_qreg_bank(s, a->qd)) {
208ab59362fSPeter Maydell         return false;
209ab59362fSPeter Maydell     }
210ab59362fSPeter Maydell     if (a->rt == 13 || a->rt == 15) {
211ab59362fSPeter Maydell         /* UNPREDICTABLE; we choose to UNDEF */
212ab59362fSPeter Maydell         return false;
213ab59362fSPeter Maydell     }
214ab59362fSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
215ab59362fSPeter Maydell         return true;
216ab59362fSPeter Maydell     }
217ab59362fSPeter Maydell 
218ab59362fSPeter Maydell     qd = mve_qreg_ptr(a->qd);
219ab59362fSPeter Maydell     rt = load_reg(s, a->rt);
220ab59362fSPeter Maydell     tcg_gen_dup_i32(a->size, rt, rt);
221ab59362fSPeter Maydell     gen_helper_mve_vdup(cpu_env, qd, rt);
222ab59362fSPeter Maydell     tcg_temp_free_ptr(qd);
223ab59362fSPeter Maydell     tcg_temp_free_i32(rt);
224ab59362fSPeter Maydell     mve_update_eci(s);
225ab59362fSPeter Maydell     return true;
226ab59362fSPeter Maydell }
227ab59362fSPeter Maydell 
2280f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
2290f0f2bd5SPeter Maydell {
2300f0f2bd5SPeter Maydell     TCGv_ptr qd, qm;
2310f0f2bd5SPeter Maydell 
2320f0f2bd5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
2330f0f2bd5SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
2340f0f2bd5SPeter Maydell         !fn) {
2350f0f2bd5SPeter Maydell         return false;
2360f0f2bd5SPeter Maydell     }
2370f0f2bd5SPeter Maydell 
2380f0f2bd5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
2390f0f2bd5SPeter Maydell         return true;
2400f0f2bd5SPeter Maydell     }
2410f0f2bd5SPeter Maydell 
2420f0f2bd5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
2430f0f2bd5SPeter Maydell     qm = mve_qreg_ptr(a->qm);
2440f0f2bd5SPeter Maydell     fn(cpu_env, qd, qm);
2450f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qd);
2460f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qm);
2470f0f2bd5SPeter Maydell     mve_update_eci(s);
2480f0f2bd5SPeter Maydell     return true;
2490f0f2bd5SPeter Maydell }
2500f0f2bd5SPeter Maydell 
2510f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN)                                        \
2520f0f2bd5SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
2530f0f2bd5SPeter Maydell     {                                                           \
2540f0f2bd5SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
2550f0f2bd5SPeter Maydell             gen_helper_mve_##FN##b,                             \
2560f0f2bd5SPeter Maydell             gen_helper_mve_##FN##h,                             \
2570f0f2bd5SPeter Maydell             gen_helper_mve_##FN##w,                             \
2580f0f2bd5SPeter Maydell             NULL,                                               \
2590f0f2bd5SPeter Maydell         };                                                      \
2600f0f2bd5SPeter Maydell         return do_1op(s, a, fns[a->size]);                      \
2610f0f2bd5SPeter Maydell     }
2620f0f2bd5SPeter Maydell 
2630f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz)
2646437f1f7SPeter Maydell DO_1OP(VCLS, vcls)
26559c91773SPeter Maydell DO_1OP(VABS, vabs)
266399a8c76SPeter Maydell DO_1OP(VNEG, vneg)
267249b5309SPeter Maydell 
268249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a)
269249b5309SPeter Maydell {
270249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
271249b5309SPeter Maydell         gen_helper_mve_vrev16b,
272249b5309SPeter Maydell         NULL,
273249b5309SPeter Maydell         NULL,
274249b5309SPeter Maydell         NULL,
275249b5309SPeter Maydell     };
276249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
277249b5309SPeter Maydell }
278249b5309SPeter Maydell 
279249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a)
280249b5309SPeter Maydell {
281249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
282249b5309SPeter Maydell         gen_helper_mve_vrev32b,
283249b5309SPeter Maydell         gen_helper_mve_vrev32h,
284249b5309SPeter Maydell         NULL,
285249b5309SPeter Maydell         NULL,
286249b5309SPeter Maydell     };
287249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
288249b5309SPeter Maydell }
289249b5309SPeter Maydell 
290249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a)
291249b5309SPeter Maydell {
292249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
293249b5309SPeter Maydell         gen_helper_mve_vrev64b,
294249b5309SPeter Maydell         gen_helper_mve_vrev64h,
295249b5309SPeter Maydell         gen_helper_mve_vrev64w,
296249b5309SPeter Maydell         NULL,
297249b5309SPeter Maydell     };
298249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
299249b5309SPeter Maydell }
3008abd3c80SPeter Maydell 
3018abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a)
3028abd3c80SPeter Maydell {
3038abd3c80SPeter Maydell     return do_1op(s, a, gen_helper_mve_vmvn);
3048abd3c80SPeter Maydell }
30559c91773SPeter Maydell 
30659c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a)
30759c91773SPeter Maydell {
30859c91773SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
30959c91773SPeter Maydell         NULL,
31059c91773SPeter Maydell         gen_helper_mve_vfabsh,
31159c91773SPeter Maydell         gen_helper_mve_vfabss,
31259c91773SPeter Maydell         NULL,
31359c91773SPeter Maydell     };
31459c91773SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
31559c91773SPeter Maydell         return false;
31659c91773SPeter Maydell     }
31759c91773SPeter Maydell     return do_1op(s, a, fns[a->size]);
31859c91773SPeter Maydell }
319399a8c76SPeter Maydell 
320399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a)
321399a8c76SPeter Maydell {
322399a8c76SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
323399a8c76SPeter Maydell         NULL,
324399a8c76SPeter Maydell         gen_helper_mve_vfnegh,
325399a8c76SPeter Maydell         gen_helper_mve_vfnegs,
326399a8c76SPeter Maydell         NULL,
327399a8c76SPeter Maydell     };
328399a8c76SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
329399a8c76SPeter Maydell         return false;
330399a8c76SPeter Maydell     }
331399a8c76SPeter Maydell     return do_1op(s, a, fns[a->size]);
332399a8c76SPeter Maydell }
33368245e44SPeter Maydell 
33468245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
33568245e44SPeter Maydell {
33668245e44SPeter Maydell     TCGv_ptr qd, qn, qm;
33768245e44SPeter Maydell 
33868245e44SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
33968245e44SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) ||
34068245e44SPeter Maydell         !fn) {
34168245e44SPeter Maydell         return false;
34268245e44SPeter Maydell     }
34368245e44SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
34468245e44SPeter Maydell         return true;
34568245e44SPeter Maydell     }
34668245e44SPeter Maydell 
34768245e44SPeter Maydell     qd = mve_qreg_ptr(a->qd);
34868245e44SPeter Maydell     qn = mve_qreg_ptr(a->qn);
34968245e44SPeter Maydell     qm = mve_qreg_ptr(a->qm);
35068245e44SPeter Maydell     fn(cpu_env, qd, qn, qm);
35168245e44SPeter Maydell     tcg_temp_free_ptr(qd);
35268245e44SPeter Maydell     tcg_temp_free_ptr(qn);
35368245e44SPeter Maydell     tcg_temp_free_ptr(qm);
35468245e44SPeter Maydell     mve_update_eci(s);
35568245e44SPeter Maydell     return true;
35668245e44SPeter Maydell }
35768245e44SPeter Maydell 
35868245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER)                                  \
35968245e44SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
36068245e44SPeter Maydell     {                                                           \
36168245e44SPeter Maydell         return do_2op(s, a, HELPER);                            \
36268245e44SPeter Maydell     }
36368245e44SPeter Maydell 
36468245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand)
36568245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic)
36668245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr)
36768245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn)
36868245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor)
3699333fe4dSPeter Maydell 
3709333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \
3719333fe4dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
3729333fe4dSPeter Maydell     {                                                           \
3739333fe4dSPeter Maydell         static MVEGenTwoOpFn * const fns[] = {                  \
3749333fe4dSPeter Maydell             gen_helper_mve_##FN##b,                             \
3759333fe4dSPeter Maydell             gen_helper_mve_##FN##h,                             \
3769333fe4dSPeter Maydell             gen_helper_mve_##FN##w,                             \
3779333fe4dSPeter Maydell             NULL,                                               \
3789333fe4dSPeter Maydell         };                                                      \
3799333fe4dSPeter Maydell         return do_2op(s, a, fns[a->size]);                      \
3809333fe4dSPeter Maydell     }
3819333fe4dSPeter Maydell 
3829333fe4dSPeter Maydell DO_2OP(VADD, vadd)
3839333fe4dSPeter Maydell DO_2OP(VSUB, vsub)
3849333fe4dSPeter Maydell DO_2OP(VMUL, vmul)
385ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs)
386ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu)
387fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs)
388fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu)
389cd367ff3SPeter Maydell DO_2OP(VMAX_S, vmaxs)
390cd367ff3SPeter Maydell DO_2OP(VMAX_U, vmaxu)
391cd367ff3SPeter Maydell DO_2OP(VMIN_S, vmins)
392cd367ff3SPeter Maydell DO_2OP(VMIN_U, vminu)
393bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds)
394bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu)
395abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds)
396abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu)
397abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs)
398abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu)
399ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs)
400ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu)
401ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts)
402ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu)
403380caf6cSPeter Maydell DO_2OP(VQDMULH, vqdmulh)
404380caf6cSPeter Maydell DO_2OP(VQRDMULH, vqrdmulh)
405f741707bSPeter Maydell DO_2OP(VQADD_S, vqadds)
406f741707bSPeter Maydell DO_2OP(VQADD_U, vqaddu)
407f741707bSPeter Maydell DO_2OP(VQSUB_S, vqsubs)
408f741707bSPeter Maydell DO_2OP(VQSUB_U, vqsubu)
4090372cad8SPeter Maydell DO_2OP(VSHL_S, vshls)
4100372cad8SPeter Maydell DO_2OP(VSHL_U, vshlu)
411bb002345SPeter Maydell DO_2OP(VRSHL_S, vrshls)
412bb002345SPeter Maydell DO_2OP(VRSHL_U, vrshlu)
413483da661SPeter Maydell DO_2OP(VQSHL_S, vqshls)
414483da661SPeter Maydell DO_2OP(VQSHL_U, vqshlu)
4159dc868c4SPeter Maydell DO_2OP(VQRSHL_S, vqrshls)
4169dc868c4SPeter Maydell DO_2OP(VQRSHL_U, vqrshlu)
417fd677f80SPeter Maydell DO_2OP(VQDMLADH, vqdmladh)
418fd677f80SPeter Maydell DO_2OP(VQDMLADHX, vqdmladhx)
419fd677f80SPeter Maydell DO_2OP(VQRDMLADH, vqrdmladh)
420fd677f80SPeter Maydell DO_2OP(VQRDMLADHX, vqrdmladhx)
42192f11732SPeter Maydell DO_2OP(VQDMLSDH, vqdmlsdh)
42292f11732SPeter Maydell DO_2OP(VQDMLSDHX, vqdmlsdhx)
42392f11732SPeter Maydell DO_2OP(VQRDMLSDH, vqrdmlsdh)
42492f11732SPeter Maydell DO_2OP(VQRDMLSDHX, vqrdmlsdhx)
4251eb987a8SPeter Maydell DO_2OP(VRHADD_S, vrhadds)
4261eb987a8SPeter Maydell DO_2OP(VRHADD_U, vrhaddu)
42767ec113bSPeter Maydell /*
42867ec113bSPeter Maydell  * VCADD Qd == Qm at size MO_32 is UNPREDICTABLE; we choose not to diagnose
42967ec113bSPeter Maydell  * so we can reuse the DO_2OP macro. (Our implementation calculates the
4308625693aSPeter Maydell  * "expected" results in this case.) Similarly for VHCADD.
43167ec113bSPeter Maydell  */
43267ec113bSPeter Maydell DO_2OP(VCADD90, vcadd90)
43367ec113bSPeter Maydell DO_2OP(VCADD270, vcadd270)
4348625693aSPeter Maydell DO_2OP(VHCADD90, vhcadd90)
4358625693aSPeter Maydell DO_2OP(VHCADD270, vhcadd270)
4361d2386f7SPeter Maydell 
43743364321SPeter Maydell static bool trans_VQDMULLB(DisasContext *s, arg_2op *a)
43843364321SPeter Maydell {
43943364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
44043364321SPeter Maydell         NULL,
44143364321SPeter Maydell         gen_helper_mve_vqdmullbh,
44243364321SPeter Maydell         gen_helper_mve_vqdmullbw,
44343364321SPeter Maydell         NULL,
44443364321SPeter Maydell     };
44543364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
44643364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
44743364321SPeter Maydell         return false;
44843364321SPeter Maydell     }
44943364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
45043364321SPeter Maydell }
45143364321SPeter Maydell 
45243364321SPeter Maydell static bool trans_VQDMULLT(DisasContext *s, arg_2op *a)
45343364321SPeter Maydell {
45443364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
45543364321SPeter Maydell         NULL,
45643364321SPeter Maydell         gen_helper_mve_vqdmullth,
45743364321SPeter Maydell         gen_helper_mve_vqdmulltw,
45843364321SPeter Maydell         NULL,
45943364321SPeter Maydell     };
46043364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
46143364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
46243364321SPeter Maydell         return false;
46343364321SPeter Maydell     }
46443364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
46543364321SPeter Maydell }
46643364321SPeter Maydell 
46789bc4c4fSPeter Maydell /*
46889bc4c4fSPeter Maydell  * VADC and VSBC: these perform an add-with-carry or subtract-with-carry
46989bc4c4fSPeter Maydell  * of the 32-bit elements in each lane of the input vectors, where the
47089bc4c4fSPeter Maydell  * carry-out of each add is the carry-in of the next.  The initial carry
47189bc4c4fSPeter Maydell  * input is either fixed (0 for VADCI, 1 for VSBCI) or is from FPSCR.C
47289bc4c4fSPeter Maydell  * (for VADC and VSBC); the carry out at the end is written back to FPSCR.C.
47389bc4c4fSPeter Maydell  * These insns are subject to beat-wise execution.  Partial execution
47489bc4c4fSPeter Maydell  * of an I=1 (initial carry input fixed) insn which does not
47589bc4c4fSPeter Maydell  * execute the first beat must start with the current FPSCR.NZCV
47689bc4c4fSPeter Maydell  * value, not the fixed constant input.
47789bc4c4fSPeter Maydell  */
47889bc4c4fSPeter Maydell static bool trans_VADC(DisasContext *s, arg_2op *a)
47989bc4c4fSPeter Maydell {
48089bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadc);
48189bc4c4fSPeter Maydell }
48289bc4c4fSPeter Maydell 
48389bc4c4fSPeter Maydell static bool trans_VADCI(DisasContext *s, arg_2op *a)
48489bc4c4fSPeter Maydell {
48589bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
48689bc4c4fSPeter Maydell         return trans_VADC(s, a);
48789bc4c4fSPeter Maydell     }
48889bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadci);
48989bc4c4fSPeter Maydell }
49089bc4c4fSPeter Maydell 
49189bc4c4fSPeter Maydell static bool trans_VSBC(DisasContext *s, arg_2op *a)
49289bc4c4fSPeter Maydell {
49389bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbc);
49489bc4c4fSPeter Maydell }
49589bc4c4fSPeter Maydell 
49689bc4c4fSPeter Maydell static bool trans_VSBCI(DisasContext *s, arg_2op *a)
49789bc4c4fSPeter Maydell {
49889bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
49989bc4c4fSPeter Maydell         return trans_VSBC(s, a);
50089bc4c4fSPeter Maydell     }
50189bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbci);
50289bc4c4fSPeter Maydell }
50389bc4c4fSPeter Maydell 
504e51896b3SPeter Maydell static bool do_2op_scalar(DisasContext *s, arg_2scalar *a,
505e51896b3SPeter Maydell                           MVEGenTwoOpScalarFn fn)
506e51896b3SPeter Maydell {
507e51896b3SPeter Maydell     TCGv_ptr qd, qn;
508e51896b3SPeter Maydell     TCGv_i32 rm;
509e51896b3SPeter Maydell 
510e51896b3SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
511e51896b3SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn) ||
512e51896b3SPeter Maydell         !fn) {
513e51896b3SPeter Maydell         return false;
514e51896b3SPeter Maydell     }
515e51896b3SPeter Maydell     if (a->rm == 13 || a->rm == 15) {
516e51896b3SPeter Maydell         /* UNPREDICTABLE */
517e51896b3SPeter Maydell         return false;
518e51896b3SPeter Maydell     }
519e51896b3SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
520e51896b3SPeter Maydell         return true;
521e51896b3SPeter Maydell     }
522e51896b3SPeter Maydell 
523e51896b3SPeter Maydell     qd = mve_qreg_ptr(a->qd);
524e51896b3SPeter Maydell     qn = mve_qreg_ptr(a->qn);
525e51896b3SPeter Maydell     rm = load_reg(s, a->rm);
526e51896b3SPeter Maydell     fn(cpu_env, qd, qn, rm);
527e51896b3SPeter Maydell     tcg_temp_free_i32(rm);
528e51896b3SPeter Maydell     tcg_temp_free_ptr(qd);
529e51896b3SPeter Maydell     tcg_temp_free_ptr(qn);
530e51896b3SPeter Maydell     mve_update_eci(s);
531e51896b3SPeter Maydell     return true;
532e51896b3SPeter Maydell }
533e51896b3SPeter Maydell 
534e51896b3SPeter Maydell #define DO_2OP_SCALAR(INSN, FN) \
535e51896b3SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2scalar *a)   \
536e51896b3SPeter Maydell     {                                                           \
537e51896b3SPeter Maydell         static MVEGenTwoOpScalarFn * const fns[] = {            \
538e51896b3SPeter Maydell             gen_helper_mve_##FN##b,                             \
539e51896b3SPeter Maydell             gen_helper_mve_##FN##h,                             \
540e51896b3SPeter Maydell             gen_helper_mve_##FN##w,                             \
541e51896b3SPeter Maydell             NULL,                                               \
542e51896b3SPeter Maydell         };                                                      \
543e51896b3SPeter Maydell         return do_2op_scalar(s, a, fns[a->size]);               \
544e51896b3SPeter Maydell     }
545e51896b3SPeter Maydell 
546e51896b3SPeter Maydell DO_2OP_SCALAR(VADD_scalar, vadd_scalar)
54791a358fdSPeter Maydell DO_2OP_SCALAR(VSUB_scalar, vsub_scalar)
54891a358fdSPeter Maydell DO_2OP_SCALAR(VMUL_scalar, vmul_scalar)
549644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_S_scalar, vhadds_scalar)
550644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_U_scalar, vhaddu_scalar)
551644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_S_scalar, vhsubs_scalar)
552644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_U_scalar, vhsubu_scalar)
55339f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_S_scalar, vqadds_scalar)
55439f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_U_scalar, vqaddu_scalar)
55539f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_S_scalar, vqsubs_scalar)
55639f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_U_scalar, vqsubu_scalar)
55766c05767SPeter Maydell DO_2OP_SCALAR(VQDMULH_scalar, vqdmulh_scalar)
55866c05767SPeter Maydell DO_2OP_SCALAR(VQRDMULH_scalar, vqrdmulh_scalar)
559b050543bSPeter Maydell DO_2OP_SCALAR(VBRSR, vbrsr)
560e51896b3SPeter Maydell 
561a8890353SPeter Maydell static bool trans_VQDMULLB_scalar(DisasContext *s, arg_2scalar *a)
562a8890353SPeter Maydell {
563a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
564a8890353SPeter Maydell         NULL,
565a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarh,
566a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarw,
567a8890353SPeter Maydell         NULL,
568a8890353SPeter Maydell     };
569a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
570a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
571a8890353SPeter Maydell         return false;
572a8890353SPeter Maydell     }
573a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
574a8890353SPeter Maydell }
575a8890353SPeter Maydell 
576a8890353SPeter Maydell static bool trans_VQDMULLT_scalar(DisasContext *s, arg_2scalar *a)
577a8890353SPeter Maydell {
578a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
579a8890353SPeter Maydell         NULL,
580a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarh,
581a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarw,
582a8890353SPeter Maydell         NULL,
583a8890353SPeter Maydell     };
584a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
585a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
586a8890353SPeter Maydell         return false;
587a8890353SPeter Maydell     }
588a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
589a8890353SPeter Maydell }
590a8890353SPeter Maydell 
5911d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a,
5921d2386f7SPeter Maydell                              MVEGenDualAccOpFn *fn)
5931d2386f7SPeter Maydell {
5941d2386f7SPeter Maydell     TCGv_ptr qn, qm;
5951d2386f7SPeter Maydell     TCGv_i64 rda;
5961d2386f7SPeter Maydell     TCGv_i32 rdalo, rdahi;
5971d2386f7SPeter Maydell 
5981d2386f7SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
5991d2386f7SPeter Maydell         !mve_check_qreg_bank(s, a->qn | a->qm) ||
6001d2386f7SPeter Maydell         !fn) {
6011d2386f7SPeter Maydell         return false;
6021d2386f7SPeter Maydell     }
6031d2386f7SPeter Maydell     /*
6041d2386f7SPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
6051d2386f7SPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
6061d2386f7SPeter Maydell      */
6071d2386f7SPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
6081d2386f7SPeter Maydell         return false;
6091d2386f7SPeter Maydell     }
6101d2386f7SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
6111d2386f7SPeter Maydell         return true;
6121d2386f7SPeter Maydell     }
6131d2386f7SPeter Maydell 
6141d2386f7SPeter Maydell     qn = mve_qreg_ptr(a->qn);
6151d2386f7SPeter Maydell     qm = mve_qreg_ptr(a->qm);
6161d2386f7SPeter Maydell 
6171d2386f7SPeter Maydell     /*
6181d2386f7SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
6191d2386f7SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
6201d2386f7SPeter Maydell      * beat must start with the current rda value, not 0.
6211d2386f7SPeter Maydell      */
6221d2386f7SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
6231d2386f7SPeter Maydell         rda = tcg_temp_new_i64();
6241d2386f7SPeter Maydell         rdalo = load_reg(s, a->rdalo);
6251d2386f7SPeter Maydell         rdahi = load_reg(s, a->rdahi);
6261d2386f7SPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
6271d2386f7SPeter Maydell         tcg_temp_free_i32(rdalo);
6281d2386f7SPeter Maydell         tcg_temp_free_i32(rdahi);
6291d2386f7SPeter Maydell     } else {
6301d2386f7SPeter Maydell         rda = tcg_const_i64(0);
6311d2386f7SPeter Maydell     }
6321d2386f7SPeter Maydell 
6331d2386f7SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
6341d2386f7SPeter Maydell     tcg_temp_free_ptr(qn);
6351d2386f7SPeter Maydell     tcg_temp_free_ptr(qm);
6361d2386f7SPeter Maydell 
6371d2386f7SPeter Maydell     rdalo = tcg_temp_new_i32();
6381d2386f7SPeter Maydell     rdahi = tcg_temp_new_i32();
6391d2386f7SPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
6401d2386f7SPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
6411d2386f7SPeter Maydell     store_reg(s, a->rdalo, rdalo);
6421d2386f7SPeter Maydell     store_reg(s, a->rdahi, rdahi);
6431d2386f7SPeter Maydell     tcg_temp_free_i64(rda);
6441d2386f7SPeter Maydell     mve_update_eci(s);
6451d2386f7SPeter Maydell     return true;
6461d2386f7SPeter Maydell }
6471d2386f7SPeter Maydell 
6481d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a)
6491d2386f7SPeter Maydell {
6501d2386f7SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
6511d2386f7SPeter Maydell         { NULL, NULL },
6521d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh },
6531d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw },
6541d2386f7SPeter Maydell         { NULL, NULL },
6551d2386f7SPeter Maydell     };
6561d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
6571d2386f7SPeter Maydell }
6581d2386f7SPeter Maydell 
6591d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a)
6601d2386f7SPeter Maydell {
6611d2386f7SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
6621d2386f7SPeter Maydell         { NULL, NULL },
6631d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuh, NULL },
6641d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuw, NULL },
6651d2386f7SPeter Maydell         { NULL, NULL },
6661d2386f7SPeter Maydell     };
6671d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
6681d2386f7SPeter Maydell }
669181cd971SPeter Maydell 
670181cd971SPeter Maydell static bool trans_VMLSLDAV(DisasContext *s, arg_vmlaldav *a)
671181cd971SPeter Maydell {
672181cd971SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
673181cd971SPeter Maydell         { NULL, NULL },
674181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh },
675181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw },
676181cd971SPeter Maydell         { NULL, NULL },
677181cd971SPeter Maydell     };
678181cd971SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
679181cd971SPeter Maydell }
68038548747SPeter Maydell 
68138548747SPeter Maydell static bool trans_VRMLALDAVH_S(DisasContext *s, arg_vmlaldav *a)
68238548747SPeter Maydell {
68338548747SPeter Maydell     static MVEGenDualAccOpFn * const fns[] = {
68438548747SPeter Maydell         gen_helper_mve_vrmlaldavhsw, gen_helper_mve_vrmlaldavhxsw,
68538548747SPeter Maydell     };
68638548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
68738548747SPeter Maydell }
68838548747SPeter Maydell 
68938548747SPeter Maydell static bool trans_VRMLALDAVH_U(DisasContext *s, arg_vmlaldav *a)
69038548747SPeter Maydell {
69138548747SPeter Maydell     static MVEGenDualAccOpFn * const fns[] = {
69238548747SPeter Maydell         gen_helper_mve_vrmlaldavhuw, NULL,
69338548747SPeter Maydell     };
69438548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
69538548747SPeter Maydell }
69638548747SPeter Maydell 
69738548747SPeter Maydell static bool trans_VRMLSLDAVH(DisasContext *s, arg_vmlaldav *a)
69838548747SPeter Maydell {
69938548747SPeter Maydell     static MVEGenDualAccOpFn * const fns[] = {
70038548747SPeter Maydell         gen_helper_mve_vrmlsldavhsw, gen_helper_mve_vrmlsldavhxsw,
70138548747SPeter Maydell     };
70238548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
70338548747SPeter Maydell }
704387debdbSPeter Maydell 
705387debdbSPeter Maydell static bool trans_VPST(DisasContext *s, arg_VPST *a)
706387debdbSPeter Maydell {
707387debdbSPeter Maydell     TCGv_i32 vpr;
708387debdbSPeter Maydell 
709387debdbSPeter Maydell     /* mask == 0 is a "related encoding" */
710387debdbSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !a->mask) {
711387debdbSPeter Maydell         return false;
712387debdbSPeter Maydell     }
713387debdbSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
714387debdbSPeter Maydell         return true;
715387debdbSPeter Maydell     }
716387debdbSPeter Maydell     /*
717387debdbSPeter Maydell      * Set the VPR mask fields. We take advantage of MASK01 and MASK23
718387debdbSPeter Maydell      * being adjacent fields in the register.
719387debdbSPeter Maydell      *
720387debdbSPeter Maydell      * This insn is not predicated, but it is subject to beat-wise
721387debdbSPeter Maydell      * execution, and the mask is updated on the odd-numbered beats.
722387debdbSPeter Maydell      * So if PSR.ECI says we should skip beat 1, we mustn't update the
723387debdbSPeter Maydell      * 01 mask field.
724387debdbSPeter Maydell      */
725387debdbSPeter Maydell     vpr = load_cpu_field(v7m.vpr);
726387debdbSPeter Maydell     switch (s->eci) {
727387debdbSPeter Maydell     case ECI_NONE:
728387debdbSPeter Maydell     case ECI_A0:
729387debdbSPeter Maydell         /* Update both 01 and 23 fields */
730387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
731387debdbSPeter Maydell                             tcg_constant_i32(a->mask | (a->mask << 4)),
732387debdbSPeter Maydell                             R_V7M_VPR_MASK01_SHIFT,
733387debdbSPeter Maydell                             R_V7M_VPR_MASK01_LENGTH + R_V7M_VPR_MASK23_LENGTH);
734387debdbSPeter Maydell         break;
735387debdbSPeter Maydell     case ECI_A0A1:
736387debdbSPeter Maydell     case ECI_A0A1A2:
737387debdbSPeter Maydell     case ECI_A0A1A2B0:
738387debdbSPeter Maydell         /* Update only the 23 mask field */
739387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
740387debdbSPeter Maydell                             tcg_constant_i32(a->mask),
741387debdbSPeter Maydell                             R_V7M_VPR_MASK23_SHIFT, R_V7M_VPR_MASK23_LENGTH);
742387debdbSPeter Maydell         break;
743387debdbSPeter Maydell     default:
744387debdbSPeter Maydell         g_assert_not_reached();
745387debdbSPeter Maydell     }
746387debdbSPeter Maydell     store_cpu_field(vpr, v7m.vpr);
747387debdbSPeter Maydell     mve_update_and_store_eci(s);
748387debdbSPeter Maydell     return true;
749387debdbSPeter Maydell }
7506f060a63SPeter Maydell 
7516f060a63SPeter Maydell static bool trans_VADDV(DisasContext *s, arg_VADDV *a)
7526f060a63SPeter Maydell {
7536f060a63SPeter Maydell     /* VADDV: vector add across vector */
7546f060a63SPeter Maydell     static MVEGenVADDVFn * const fns[4][2] = {
7556f060a63SPeter Maydell         { gen_helper_mve_vaddvsb, gen_helper_mve_vaddvub },
7566f060a63SPeter Maydell         { gen_helper_mve_vaddvsh, gen_helper_mve_vaddvuh },
7576f060a63SPeter Maydell         { gen_helper_mve_vaddvsw, gen_helper_mve_vaddvuw },
7586f060a63SPeter Maydell         { NULL, NULL }
7596f060a63SPeter Maydell     };
7606f060a63SPeter Maydell     TCGv_ptr qm;
7616f060a63SPeter Maydell     TCGv_i32 rda;
7626f060a63SPeter Maydell 
7636f060a63SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
7646f060a63SPeter Maydell         a->size == 3) {
7656f060a63SPeter Maydell         return false;
7666f060a63SPeter Maydell     }
7676f060a63SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
7686f060a63SPeter Maydell         return true;
7696f060a63SPeter Maydell     }
7706f060a63SPeter Maydell 
7716f060a63SPeter Maydell     /*
7726f060a63SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
7736f060a63SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
7746f060a63SPeter Maydell      * beat must start with the current value of Rda, not zero.
7756f060a63SPeter Maydell      */
7766f060a63SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
7776f060a63SPeter Maydell         /* Accumulate input from Rda */
7786f060a63SPeter Maydell         rda = load_reg(s, a->rda);
7796f060a63SPeter Maydell     } else {
7806f060a63SPeter Maydell         /* Accumulate starting at zero */
7816f060a63SPeter Maydell         rda = tcg_const_i32(0);
7826f060a63SPeter Maydell     }
7836f060a63SPeter Maydell 
7846f060a63SPeter Maydell     qm = mve_qreg_ptr(a->qm);
7856f060a63SPeter Maydell     fns[a->size][a->u](rda, cpu_env, qm, rda);
7866f060a63SPeter Maydell     store_reg(s, a->rda, rda);
7876f060a63SPeter Maydell     tcg_temp_free_ptr(qm);
7886f060a63SPeter Maydell 
7896f060a63SPeter Maydell     mve_update_eci(s);
7906f060a63SPeter Maydell     return true;
7916f060a63SPeter Maydell }
792eab84139SPeter Maydell 
793eab84139SPeter Maydell static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
794eab84139SPeter Maydell {
795eab84139SPeter Maydell     TCGv_ptr qd;
796eab84139SPeter Maydell     uint64_t imm;
797eab84139SPeter Maydell 
798eab84139SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
799eab84139SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
800eab84139SPeter Maydell         !fn) {
801eab84139SPeter Maydell         return false;
802eab84139SPeter Maydell     }
803eab84139SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
804eab84139SPeter Maydell         return true;
805eab84139SPeter Maydell     }
806eab84139SPeter Maydell 
807eab84139SPeter Maydell     imm = asimd_imm_const(a->imm, a->cmode, a->op);
808eab84139SPeter Maydell 
809eab84139SPeter Maydell     qd = mve_qreg_ptr(a->qd);
810eab84139SPeter Maydell     fn(cpu_env, qd, tcg_constant_i64(imm));
811eab84139SPeter Maydell     tcg_temp_free_ptr(qd);
812eab84139SPeter Maydell     mve_update_eci(s);
813eab84139SPeter Maydell     return true;
814eab84139SPeter Maydell }
815eab84139SPeter Maydell 
816eab84139SPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
817eab84139SPeter Maydell {
818eab84139SPeter Maydell     /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
819eab84139SPeter Maydell     MVEGenOneOpImmFn *fn;
820eab84139SPeter Maydell 
821eab84139SPeter Maydell     if ((a->cmode & 1) && a->cmode < 12) {
822eab84139SPeter Maydell         if (a->op) {
823eab84139SPeter Maydell             /*
824eab84139SPeter Maydell              * For op=1, the immediate will be inverted by asimd_imm_const(),
825eab84139SPeter Maydell              * so the VBIC becomes a logical AND operation.
826eab84139SPeter Maydell              */
827eab84139SPeter Maydell             fn = gen_helper_mve_vandi;
828eab84139SPeter Maydell         } else {
829eab84139SPeter Maydell             fn = gen_helper_mve_vorri;
830eab84139SPeter Maydell         }
831eab84139SPeter Maydell     } else {
832eab84139SPeter Maydell         /* There is one unallocated cmode/op combination in this space */
833eab84139SPeter Maydell         if (a->cmode == 15 && a->op == 1) {
834eab84139SPeter Maydell             return false;
835eab84139SPeter Maydell         }
836eab84139SPeter Maydell         /* asimd_imm_const() sorts out VMVNI vs VMOVI for us */
837eab84139SPeter Maydell         fn = gen_helper_mve_vmovi;
838eab84139SPeter Maydell     }
839eab84139SPeter Maydell     return do_1imm(s, a, fn);
840eab84139SPeter Maydell }
841*f9ed6174SPeter Maydell 
842*f9ed6174SPeter Maydell static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
843*f9ed6174SPeter Maydell                       bool negateshift)
844*f9ed6174SPeter Maydell {
845*f9ed6174SPeter Maydell     TCGv_ptr qd, qm;
846*f9ed6174SPeter Maydell     int shift = a->shift;
847*f9ed6174SPeter Maydell 
848*f9ed6174SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
849*f9ed6174SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
850*f9ed6174SPeter Maydell         !fn) {
851*f9ed6174SPeter Maydell         return false;
852*f9ed6174SPeter Maydell     }
853*f9ed6174SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
854*f9ed6174SPeter Maydell         return true;
855*f9ed6174SPeter Maydell     }
856*f9ed6174SPeter Maydell 
857*f9ed6174SPeter Maydell     /*
858*f9ed6174SPeter Maydell      * When we handle a right shift insn using a left-shift helper
859*f9ed6174SPeter Maydell      * which permits a negative shift count to indicate a right-shift,
860*f9ed6174SPeter Maydell      * we must negate the shift count.
861*f9ed6174SPeter Maydell      */
862*f9ed6174SPeter Maydell     if (negateshift) {
863*f9ed6174SPeter Maydell         shift = -shift;
864*f9ed6174SPeter Maydell     }
865*f9ed6174SPeter Maydell 
866*f9ed6174SPeter Maydell     qd = mve_qreg_ptr(a->qd);
867*f9ed6174SPeter Maydell     qm = mve_qreg_ptr(a->qm);
868*f9ed6174SPeter Maydell     fn(cpu_env, qd, qm, tcg_constant_i32(shift));
869*f9ed6174SPeter Maydell     tcg_temp_free_ptr(qd);
870*f9ed6174SPeter Maydell     tcg_temp_free_ptr(qm);
871*f9ed6174SPeter Maydell     mve_update_eci(s);
872*f9ed6174SPeter Maydell     return true;
873*f9ed6174SPeter Maydell }
874*f9ed6174SPeter Maydell 
875*f9ed6174SPeter Maydell #define DO_2SHIFT(INSN, FN, NEGATESHIFT)                         \
876*f9ed6174SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
877*f9ed6174SPeter Maydell     {                                                           \
878*f9ed6174SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
879*f9ed6174SPeter Maydell             gen_helper_mve_##FN##b,                             \
880*f9ed6174SPeter Maydell             gen_helper_mve_##FN##h,                             \
881*f9ed6174SPeter Maydell             gen_helper_mve_##FN##w,                             \
882*f9ed6174SPeter Maydell             NULL,                                               \
883*f9ed6174SPeter Maydell         };                                                      \
884*f9ed6174SPeter Maydell         return do_2shift(s, a, fns[a->size], NEGATESHIFT);      \
885*f9ed6174SPeter Maydell     }
886*f9ed6174SPeter Maydell 
887*f9ed6174SPeter Maydell DO_2SHIFT(VSHLI, vshli_u, false)
888*f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_S, vqshli_s, false)
889*f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_U, vqshli_u, false)
890*f9ed6174SPeter Maydell DO_2SHIFT(VQSHLUI, vqshlui_s, false)
891