xref: /qemu/target/arm/tcg/translate-mve.c (revision ce75c43f6db70b409bcb03f8dea05463928e12e0)
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);
37dc18628bSPeter Maydell typedef void MVEGenLdStSGFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
38075e7e97SPeter Maydell typedef void MVEGenLdStIlFn(TCGv_ptr, TCGv_i32, TCGv_i32);
390f0f2bd5SPeter Maydell typedef void MVEGenOneOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
4068245e44SPeter Maydell typedef void MVEGenTwoOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr);
41e51896b3SPeter Maydell typedef void MVEGenTwoOpScalarFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
42f9ed6174SPeter Maydell typedef void MVEGenTwoOpShiftFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
43640cdf20SPeter Maydell typedef void MVEGenLongDualAccOpFn(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64);
446f060a63SPeter Maydell typedef void MVEGenVADDVFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32);
45eab84139SPeter Maydell typedef void MVEGenOneOpImmFn(TCGv_ptr, TCGv_ptr, TCGv_i64);
46395b92d5SPeter Maydell typedef void MVEGenVIDUPFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32, TCGv_i32);
47395b92d5SPeter Maydell typedef void MVEGenVIWDUPFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32);
48eff5d9a9SPeter Maydell typedef void MVEGenCmpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
49cce81873SPeter Maydell typedef void MVEGenScalarCmpFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
507f061c0aSPeter Maydell typedef void MVEGenVABAVFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
51f0ffff51SPeter Maydell typedef void MVEGenDualAccOpFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
5253fc5f61SPeter Maydell typedef void MVEGenVCVTRmodeFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
53507b6a50SPeter Maydell 
54507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */
55507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg)
56507b6a50SPeter Maydell {
57507b6a50SPeter Maydell     return offsetof(CPUARMState, vfp.zregs[reg].d[0]);
58507b6a50SPeter Maydell }
59507b6a50SPeter Maydell 
60507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg)
61507b6a50SPeter Maydell {
62507b6a50SPeter Maydell     TCGv_ptr ret = tcg_temp_new_ptr();
63507b6a50SPeter Maydell     tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg));
64507b6a50SPeter Maydell     return ret;
65507b6a50SPeter Maydell }
66507b6a50SPeter Maydell 
67451f9d66SPeter Maydell static bool mve_no_predication(DisasContext *s)
68451f9d66SPeter Maydell {
69451f9d66SPeter Maydell     /*
70451f9d66SPeter Maydell      * Return true if we are executing the entire MVE instruction
71451f9d66SPeter Maydell      * with no predication or partial-execution, and so we can safely
72451f9d66SPeter Maydell      * use an inline TCG vector implementation.
73451f9d66SPeter Maydell      */
74451f9d66SPeter Maydell     return s->eci == 0 && s->mve_no_pred;
75451f9d66SPeter Maydell }
76451f9d66SPeter Maydell 
77507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask)
78507b6a50SPeter Maydell {
79507b6a50SPeter Maydell     /*
80507b6a50SPeter Maydell      * Check whether Qregs are in range. For v8.1M only Q0..Q7
81507b6a50SPeter Maydell      * are supported, see VFPSmallRegisterBank().
82507b6a50SPeter Maydell      */
83507b6a50SPeter Maydell     return qmask < 8;
84507b6a50SPeter Maydell }
85507b6a50SPeter Maydell 
864f57ef95SPeter Maydell bool mve_eci_check(DisasContext *s)
87507b6a50SPeter Maydell {
88507b6a50SPeter Maydell     /*
89507b6a50SPeter Maydell      * This is a beatwise insn: check that ECI is valid (not a
90507b6a50SPeter Maydell      * reserved value) and note that we are handling it.
91507b6a50SPeter Maydell      * Return true if OK, false if we generated an exception.
92507b6a50SPeter Maydell      */
93507b6a50SPeter Maydell     s->eci_handled = true;
94507b6a50SPeter Maydell     switch (s->eci) {
95507b6a50SPeter Maydell     case ECI_NONE:
96507b6a50SPeter Maydell     case ECI_A0:
97507b6a50SPeter Maydell     case ECI_A0A1:
98507b6a50SPeter Maydell     case ECI_A0A1A2:
99507b6a50SPeter Maydell     case ECI_A0A1A2B0:
100507b6a50SPeter Maydell         return true;
101507b6a50SPeter Maydell     default:
102507b6a50SPeter Maydell         /* Reserved value: INVSTATE UsageFault */
103507b6a50SPeter Maydell         gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(),
104507b6a50SPeter Maydell                            default_exception_el(s));
105507b6a50SPeter Maydell         return false;
106507b6a50SPeter Maydell     }
107507b6a50SPeter Maydell }
108507b6a50SPeter Maydell 
1090f31e37cSPeter Maydell void mve_update_eci(DisasContext *s)
110507b6a50SPeter Maydell {
111507b6a50SPeter Maydell     /*
112507b6a50SPeter Maydell      * The helper function will always update the CPUState field,
113507b6a50SPeter Maydell      * so we only need to update the DisasContext field.
114507b6a50SPeter Maydell      */
115507b6a50SPeter Maydell     if (s->eci) {
116507b6a50SPeter Maydell         s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE;
117507b6a50SPeter Maydell     }
118507b6a50SPeter Maydell }
119507b6a50SPeter Maydell 
1204f57ef95SPeter Maydell void mve_update_and_store_eci(DisasContext *s)
121387debdbSPeter Maydell {
122387debdbSPeter Maydell     /*
123387debdbSPeter Maydell      * For insns which don't call a helper function that will call
124387debdbSPeter Maydell      * mve_advance_vpt(), this version updates s->eci and also stores
125387debdbSPeter Maydell      * it out to the CPUState field.
126387debdbSPeter Maydell      */
127387debdbSPeter Maydell     if (s->eci) {
128387debdbSPeter Maydell         mve_update_eci(s);
129387debdbSPeter Maydell         store_cpu_field(tcg_constant_i32(s->eci << 4), condexec_bits);
130387debdbSPeter Maydell     }
131387debdbSPeter Maydell }
132387debdbSPeter Maydell 
1331d2386f7SPeter Maydell static bool mve_skip_first_beat(DisasContext *s)
1341d2386f7SPeter Maydell {
1351d2386f7SPeter Maydell     /* Return true if PSR.ECI says we must skip the first beat of this insn */
1361d2386f7SPeter Maydell     switch (s->eci) {
1371d2386f7SPeter Maydell     case ECI_NONE:
1381d2386f7SPeter Maydell         return false;
1391d2386f7SPeter Maydell     case ECI_A0:
1401d2386f7SPeter Maydell     case ECI_A0A1:
1411d2386f7SPeter Maydell     case ECI_A0A1A2:
1421d2386f7SPeter Maydell     case ECI_A0A1A2B0:
1431d2386f7SPeter Maydell         return true;
1441d2386f7SPeter Maydell     default:
1451d2386f7SPeter Maydell         g_assert_not_reached();
1461d2386f7SPeter Maydell     }
1471d2386f7SPeter Maydell }
1481d2386f7SPeter Maydell 
149d59ccc30SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn,
150d59ccc30SPeter Maydell                     unsigned msize)
151507b6a50SPeter Maydell {
152507b6a50SPeter Maydell     TCGv_i32 addr;
153507b6a50SPeter Maydell     uint32_t offset;
154507b6a50SPeter Maydell     TCGv_ptr qreg;
155507b6a50SPeter Maydell 
156507b6a50SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
157507b6a50SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
158507b6a50SPeter Maydell         !fn) {
159507b6a50SPeter Maydell         return false;
160507b6a50SPeter Maydell     }
161507b6a50SPeter Maydell 
162507b6a50SPeter Maydell     /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
163507b6a50SPeter Maydell     if (a->rn == 15 || (a->rn == 13 && a->w)) {
164507b6a50SPeter Maydell         return false;
165507b6a50SPeter Maydell     }
166507b6a50SPeter Maydell 
167507b6a50SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
168507b6a50SPeter Maydell         return true;
169507b6a50SPeter Maydell     }
170507b6a50SPeter Maydell 
171d59ccc30SPeter Maydell     offset = a->imm << msize;
172507b6a50SPeter Maydell     if (!a->a) {
173507b6a50SPeter Maydell         offset = -offset;
174507b6a50SPeter Maydell     }
175507b6a50SPeter Maydell     addr = load_reg(s, a->rn);
176507b6a50SPeter Maydell     if (a->p) {
177507b6a50SPeter Maydell         tcg_gen_addi_i32(addr, addr, offset);
178507b6a50SPeter Maydell     }
179507b6a50SPeter Maydell 
180507b6a50SPeter Maydell     qreg = mve_qreg_ptr(a->qd);
181507b6a50SPeter Maydell     fn(cpu_env, qreg, addr);
182507b6a50SPeter Maydell     tcg_temp_free_ptr(qreg);
183507b6a50SPeter Maydell 
184507b6a50SPeter Maydell     /*
185507b6a50SPeter Maydell      * Writeback always happens after the last beat of the insn,
186507b6a50SPeter Maydell      * regardless of predication
187507b6a50SPeter Maydell      */
188507b6a50SPeter Maydell     if (a->w) {
189507b6a50SPeter Maydell         if (!a->p) {
190507b6a50SPeter Maydell             tcg_gen_addi_i32(addr, addr, offset);
191507b6a50SPeter Maydell         }
192507b6a50SPeter Maydell         store_reg(s, a->rn, addr);
193507b6a50SPeter Maydell     } else {
194507b6a50SPeter Maydell         tcg_temp_free_i32(addr);
195507b6a50SPeter Maydell     }
196507b6a50SPeter Maydell     mve_update_eci(s);
197507b6a50SPeter Maydell     return true;
198507b6a50SPeter Maydell }
199507b6a50SPeter Maydell 
200507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a)
201507b6a50SPeter Maydell {
202507b6a50SPeter Maydell     static MVEGenLdStFn * const ldstfns[4][2] = {
203507b6a50SPeter Maydell         { gen_helper_mve_vstrb, gen_helper_mve_vldrb },
204507b6a50SPeter Maydell         { gen_helper_mve_vstrh, gen_helper_mve_vldrh },
205507b6a50SPeter Maydell         { gen_helper_mve_vstrw, gen_helper_mve_vldrw },
206507b6a50SPeter Maydell         { NULL, NULL }
207507b6a50SPeter Maydell     };
208d59ccc30SPeter Maydell     return do_ldst(s, a, ldstfns[a->size][a->l], a->size);
209507b6a50SPeter Maydell }
2102fc6b751SPeter Maydell 
211d59ccc30SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST, MSIZE)           \
2122fc6b751SPeter Maydell     static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a)   \
2132fc6b751SPeter Maydell     {                                                           \
2142fc6b751SPeter Maydell         static MVEGenLdStFn * const ldstfns[2][2] = {           \
2152fc6b751SPeter Maydell             { gen_helper_mve_##ST, gen_helper_mve_##SLD },      \
2162fc6b751SPeter Maydell             { NULL, gen_helper_mve_##ULD },                     \
2172fc6b751SPeter Maydell         };                                                      \
218d59ccc30SPeter Maydell         return do_ldst(s, a, ldstfns[a->u][a->l], MSIZE);       \
2192fc6b751SPeter Maydell     }
2202fc6b751SPeter Maydell 
221d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h, MO_8)
222d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w, MO_8)
223d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w, MO_16)
2240f0f2bd5SPeter Maydell 
225dc18628bSPeter Maydell static bool do_ldst_sg(DisasContext *s, arg_vldst_sg *a, MVEGenLdStSGFn fn)
226dc18628bSPeter Maydell {
227dc18628bSPeter Maydell     TCGv_i32 addr;
228dc18628bSPeter Maydell     TCGv_ptr qd, qm;
229dc18628bSPeter Maydell 
230dc18628bSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
231dc18628bSPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
232dc18628bSPeter Maydell         !fn || a->rn == 15) {
233dc18628bSPeter Maydell         /* Rn case is UNPREDICTABLE */
234dc18628bSPeter Maydell         return false;
235dc18628bSPeter Maydell     }
236dc18628bSPeter Maydell 
237dc18628bSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
238dc18628bSPeter Maydell         return true;
239dc18628bSPeter Maydell     }
240dc18628bSPeter Maydell 
241dc18628bSPeter Maydell     addr = load_reg(s, a->rn);
242dc18628bSPeter Maydell 
243dc18628bSPeter Maydell     qd = mve_qreg_ptr(a->qd);
244dc18628bSPeter Maydell     qm = mve_qreg_ptr(a->qm);
245dc18628bSPeter Maydell     fn(cpu_env, qd, qm, addr);
246dc18628bSPeter Maydell     tcg_temp_free_ptr(qd);
247dc18628bSPeter Maydell     tcg_temp_free_ptr(qm);
248dc18628bSPeter Maydell     tcg_temp_free_i32(addr);
249dc18628bSPeter Maydell     mve_update_eci(s);
250dc18628bSPeter Maydell     return true;
251dc18628bSPeter Maydell }
252dc18628bSPeter Maydell 
253dc18628bSPeter Maydell /*
254dc18628bSPeter Maydell  * The naming scheme here is "vldrb_sg_sh == in-memory byte loads
255dc18628bSPeter Maydell  * signextended to halfword elements in register". _os_ indicates that
256dc18628bSPeter Maydell  * the offsets in Qm should be scaled by the element size.
257dc18628bSPeter Maydell  */
258dc18628bSPeter Maydell /* This macro is just to make the arrays more compact in these functions */
259dc18628bSPeter Maydell #define F(N) gen_helper_mve_##N
260dc18628bSPeter Maydell 
261dc18628bSPeter Maydell /* VLDRB/VSTRB (ie msize 1) with OS=1 is UNPREDICTABLE; we UNDEF */
262dc18628bSPeter Maydell static bool trans_VLDR_S_sg(DisasContext *s, arg_vldst_sg *a)
263dc18628bSPeter Maydell {
264dc18628bSPeter Maydell     static MVEGenLdStSGFn * const fns[2][4][4] = { {
265dc18628bSPeter Maydell             { NULL, F(vldrb_sg_sh), F(vldrb_sg_sw), NULL },
266dc18628bSPeter Maydell             { NULL, NULL,           F(vldrh_sg_sw), NULL },
267dc18628bSPeter Maydell             { NULL, NULL,           NULL,           NULL },
268dc18628bSPeter Maydell             { NULL, NULL,           NULL,           NULL }
269dc18628bSPeter Maydell         }, {
270dc18628bSPeter Maydell             { NULL, NULL,              NULL,              NULL },
271dc18628bSPeter Maydell             { NULL, NULL,              F(vldrh_sg_os_sw), NULL },
272dc18628bSPeter Maydell             { NULL, NULL,              NULL,              NULL },
273dc18628bSPeter Maydell             { NULL, NULL,              NULL,              NULL }
274dc18628bSPeter Maydell         }
275dc18628bSPeter Maydell     };
276dc18628bSPeter Maydell     if (a->qd == a->qm) {
277dc18628bSPeter Maydell         return false; /* UNPREDICTABLE */
278dc18628bSPeter Maydell     }
279dc18628bSPeter Maydell     return do_ldst_sg(s, a, fns[a->os][a->msize][a->size]);
280dc18628bSPeter Maydell }
281dc18628bSPeter Maydell 
282dc18628bSPeter Maydell static bool trans_VLDR_U_sg(DisasContext *s, arg_vldst_sg *a)
283dc18628bSPeter Maydell {
284dc18628bSPeter Maydell     static MVEGenLdStSGFn * const fns[2][4][4] = { {
285dc18628bSPeter Maydell             { F(vldrb_sg_ub), F(vldrb_sg_uh), F(vldrb_sg_uw), NULL },
286dc18628bSPeter Maydell             { NULL,           F(vldrh_sg_uh), F(vldrh_sg_uw), NULL },
287dc18628bSPeter Maydell             { NULL,           NULL,           F(vldrw_sg_uw), NULL },
288dc18628bSPeter Maydell             { NULL,           NULL,           NULL,           F(vldrd_sg_ud) }
289dc18628bSPeter Maydell         }, {
290dc18628bSPeter Maydell             { NULL, NULL,              NULL,              NULL },
291dc18628bSPeter Maydell             { NULL, F(vldrh_sg_os_uh), F(vldrh_sg_os_uw), NULL },
292dc18628bSPeter Maydell             { NULL, NULL,              F(vldrw_sg_os_uw), NULL },
293dc18628bSPeter Maydell             { NULL, NULL,              NULL,              F(vldrd_sg_os_ud) }
294dc18628bSPeter Maydell         }
295dc18628bSPeter Maydell     };
296dc18628bSPeter Maydell     if (a->qd == a->qm) {
297dc18628bSPeter Maydell         return false; /* UNPREDICTABLE */
298dc18628bSPeter Maydell     }
299dc18628bSPeter Maydell     return do_ldst_sg(s, a, fns[a->os][a->msize][a->size]);
300dc18628bSPeter Maydell }
301dc18628bSPeter Maydell 
302dc18628bSPeter Maydell static bool trans_VSTR_sg(DisasContext *s, arg_vldst_sg *a)
303dc18628bSPeter Maydell {
304dc18628bSPeter Maydell     static MVEGenLdStSGFn * const fns[2][4][4] = { {
305dc18628bSPeter Maydell             { F(vstrb_sg_ub), F(vstrb_sg_uh), F(vstrb_sg_uw), NULL },
306dc18628bSPeter Maydell             { NULL,           F(vstrh_sg_uh), F(vstrh_sg_uw), NULL },
307dc18628bSPeter Maydell             { NULL,           NULL,           F(vstrw_sg_uw), NULL },
308dc18628bSPeter Maydell             { NULL,           NULL,           NULL,           F(vstrd_sg_ud) }
309dc18628bSPeter Maydell         }, {
310dc18628bSPeter Maydell             { NULL, NULL,              NULL,              NULL },
311dc18628bSPeter Maydell             { NULL, F(vstrh_sg_os_uh), F(vstrh_sg_os_uw), NULL },
312dc18628bSPeter Maydell             { NULL, NULL,              F(vstrw_sg_os_uw), NULL },
313dc18628bSPeter Maydell             { NULL, NULL,              NULL,              F(vstrd_sg_os_ud) }
314dc18628bSPeter Maydell         }
315dc18628bSPeter Maydell     };
316dc18628bSPeter Maydell     return do_ldst_sg(s, a, fns[a->os][a->msize][a->size]);
317dc18628bSPeter Maydell }
318dc18628bSPeter Maydell 
319dc18628bSPeter Maydell #undef F
320dc18628bSPeter Maydell 
321fac80f08SPeter Maydell static bool do_ldst_sg_imm(DisasContext *s, arg_vldst_sg_imm *a,
322fac80f08SPeter Maydell                            MVEGenLdStSGFn *fn, unsigned msize)
323fac80f08SPeter Maydell {
324fac80f08SPeter Maydell     uint32_t offset;
325fac80f08SPeter Maydell     TCGv_ptr qd, qm;
326fac80f08SPeter Maydell 
327fac80f08SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
328fac80f08SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
329fac80f08SPeter Maydell         !fn) {
330fac80f08SPeter Maydell         return false;
331fac80f08SPeter Maydell     }
332fac80f08SPeter Maydell 
333fac80f08SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
334fac80f08SPeter Maydell         return true;
335fac80f08SPeter Maydell     }
336fac80f08SPeter Maydell 
337fac80f08SPeter Maydell     offset = a->imm << msize;
338fac80f08SPeter Maydell     if (!a->a) {
339fac80f08SPeter Maydell         offset = -offset;
340fac80f08SPeter Maydell     }
341fac80f08SPeter Maydell 
342fac80f08SPeter Maydell     qd = mve_qreg_ptr(a->qd);
343fac80f08SPeter Maydell     qm = mve_qreg_ptr(a->qm);
344fac80f08SPeter Maydell     fn(cpu_env, qd, qm, tcg_constant_i32(offset));
345fac80f08SPeter Maydell     tcg_temp_free_ptr(qd);
346fac80f08SPeter Maydell     tcg_temp_free_ptr(qm);
347fac80f08SPeter Maydell     mve_update_eci(s);
348fac80f08SPeter Maydell     return true;
349fac80f08SPeter Maydell }
350fac80f08SPeter Maydell 
351fac80f08SPeter Maydell static bool trans_VLDRW_sg_imm(DisasContext *s, arg_vldst_sg_imm *a)
352fac80f08SPeter Maydell {
353fac80f08SPeter Maydell     static MVEGenLdStSGFn * const fns[] = {
354fac80f08SPeter Maydell         gen_helper_mve_vldrw_sg_uw,
355fac80f08SPeter Maydell         gen_helper_mve_vldrw_sg_wb_uw,
356fac80f08SPeter Maydell     };
357fac80f08SPeter Maydell     if (a->qd == a->qm) {
358fac80f08SPeter Maydell         return false; /* UNPREDICTABLE */
359fac80f08SPeter Maydell     }
360fac80f08SPeter Maydell     return do_ldst_sg_imm(s, a, fns[a->w], MO_32);
361fac80f08SPeter Maydell }
362fac80f08SPeter Maydell 
363fac80f08SPeter Maydell static bool trans_VLDRD_sg_imm(DisasContext *s, arg_vldst_sg_imm *a)
364fac80f08SPeter Maydell {
365fac80f08SPeter Maydell     static MVEGenLdStSGFn * const fns[] = {
366fac80f08SPeter Maydell         gen_helper_mve_vldrd_sg_ud,
367fac80f08SPeter Maydell         gen_helper_mve_vldrd_sg_wb_ud,
368fac80f08SPeter Maydell     };
369fac80f08SPeter Maydell     if (a->qd == a->qm) {
370fac80f08SPeter Maydell         return false; /* UNPREDICTABLE */
371fac80f08SPeter Maydell     }
372fac80f08SPeter Maydell     return do_ldst_sg_imm(s, a, fns[a->w], MO_64);
373fac80f08SPeter Maydell }
374fac80f08SPeter Maydell 
375fac80f08SPeter Maydell static bool trans_VSTRW_sg_imm(DisasContext *s, arg_vldst_sg_imm *a)
376fac80f08SPeter Maydell {
377fac80f08SPeter Maydell     static MVEGenLdStSGFn * const fns[] = {
378fac80f08SPeter Maydell         gen_helper_mve_vstrw_sg_uw,
379fac80f08SPeter Maydell         gen_helper_mve_vstrw_sg_wb_uw,
380fac80f08SPeter Maydell     };
381fac80f08SPeter Maydell     return do_ldst_sg_imm(s, a, fns[a->w], MO_32);
382fac80f08SPeter Maydell }
383fac80f08SPeter Maydell 
384fac80f08SPeter Maydell static bool trans_VSTRD_sg_imm(DisasContext *s, arg_vldst_sg_imm *a)
385fac80f08SPeter Maydell {
386fac80f08SPeter Maydell     static MVEGenLdStSGFn * const fns[] = {
387fac80f08SPeter Maydell         gen_helper_mve_vstrd_sg_ud,
388fac80f08SPeter Maydell         gen_helper_mve_vstrd_sg_wb_ud,
389fac80f08SPeter Maydell     };
390fac80f08SPeter Maydell     return do_ldst_sg_imm(s, a, fns[a->w], MO_64);
391fac80f08SPeter Maydell }
392fac80f08SPeter Maydell 
393075e7e97SPeter Maydell static bool do_vldst_il(DisasContext *s, arg_vldst_il *a, MVEGenLdStIlFn *fn,
394075e7e97SPeter Maydell                         int addrinc)
395075e7e97SPeter Maydell {
396075e7e97SPeter Maydell     TCGv_i32 rn;
397075e7e97SPeter Maydell 
398075e7e97SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
399075e7e97SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
400075e7e97SPeter Maydell         !fn || (a->rn == 13 && a->w) || a->rn == 15) {
401075e7e97SPeter Maydell         /* Variously UNPREDICTABLE or UNDEF or related-encoding */
402075e7e97SPeter Maydell         return false;
403075e7e97SPeter Maydell     }
404075e7e97SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
405075e7e97SPeter Maydell         return true;
406075e7e97SPeter Maydell     }
407075e7e97SPeter Maydell 
408075e7e97SPeter Maydell     rn = load_reg(s, a->rn);
409075e7e97SPeter Maydell     /*
410075e7e97SPeter Maydell      * We pass the index of Qd, not a pointer, because the helper must
411075e7e97SPeter Maydell      * access multiple Q registers starting at Qd and working up.
412075e7e97SPeter Maydell      */
413075e7e97SPeter Maydell     fn(cpu_env, tcg_constant_i32(a->qd), rn);
414075e7e97SPeter Maydell 
415075e7e97SPeter Maydell     if (a->w) {
416075e7e97SPeter Maydell         tcg_gen_addi_i32(rn, rn, addrinc);
417075e7e97SPeter Maydell         store_reg(s, a->rn, rn);
418075e7e97SPeter Maydell     } else {
419075e7e97SPeter Maydell         tcg_temp_free_i32(rn);
420075e7e97SPeter Maydell     }
421075e7e97SPeter Maydell     mve_update_and_store_eci(s);
422075e7e97SPeter Maydell     return true;
423075e7e97SPeter Maydell }
424075e7e97SPeter Maydell 
425075e7e97SPeter Maydell /* This macro is just to make the arrays more compact in these functions */
426075e7e97SPeter Maydell #define F(N) gen_helper_mve_##N
427075e7e97SPeter Maydell 
428075e7e97SPeter Maydell static bool trans_VLD2(DisasContext *s, arg_vldst_il *a)
429075e7e97SPeter Maydell {
430075e7e97SPeter Maydell     static MVEGenLdStIlFn * const fns[4][4] = {
431075e7e97SPeter Maydell         { F(vld20b), F(vld20h), F(vld20w), NULL, },
432075e7e97SPeter Maydell         { F(vld21b), F(vld21h), F(vld21w), NULL, },
433075e7e97SPeter Maydell         { NULL, NULL, NULL, NULL },
434075e7e97SPeter Maydell         { NULL, NULL, NULL, NULL },
435075e7e97SPeter Maydell     };
436075e7e97SPeter Maydell     if (a->qd > 6) {
437075e7e97SPeter Maydell         return false;
438075e7e97SPeter Maydell     }
439075e7e97SPeter Maydell     return do_vldst_il(s, a, fns[a->pat][a->size], 32);
440075e7e97SPeter Maydell }
441075e7e97SPeter Maydell 
442075e7e97SPeter Maydell static bool trans_VLD4(DisasContext *s, arg_vldst_il *a)
443075e7e97SPeter Maydell {
444075e7e97SPeter Maydell     static MVEGenLdStIlFn * const fns[4][4] = {
445075e7e97SPeter Maydell         { F(vld40b), F(vld40h), F(vld40w), NULL, },
446075e7e97SPeter Maydell         { F(vld41b), F(vld41h), F(vld41w), NULL, },
447075e7e97SPeter Maydell         { F(vld42b), F(vld42h), F(vld42w), NULL, },
448075e7e97SPeter Maydell         { F(vld43b), F(vld43h), F(vld43w), NULL, },
449075e7e97SPeter Maydell     };
450075e7e97SPeter Maydell     if (a->qd > 4) {
451075e7e97SPeter Maydell         return false;
452075e7e97SPeter Maydell     }
453075e7e97SPeter Maydell     return do_vldst_il(s, a, fns[a->pat][a->size], 64);
454075e7e97SPeter Maydell }
455075e7e97SPeter Maydell 
456075e7e97SPeter Maydell static bool trans_VST2(DisasContext *s, arg_vldst_il *a)
457075e7e97SPeter Maydell {
458075e7e97SPeter Maydell     static MVEGenLdStIlFn * const fns[4][4] = {
459075e7e97SPeter Maydell         { F(vst20b), F(vst20h), F(vst20w), NULL, },
460075e7e97SPeter Maydell         { F(vst21b), F(vst21h), F(vst21w), NULL, },
461075e7e97SPeter Maydell         { NULL, NULL, NULL, NULL },
462075e7e97SPeter Maydell         { NULL, NULL, NULL, NULL },
463075e7e97SPeter Maydell     };
464075e7e97SPeter Maydell     if (a->qd > 6) {
465075e7e97SPeter Maydell         return false;
466075e7e97SPeter Maydell     }
467075e7e97SPeter Maydell     return do_vldst_il(s, a, fns[a->pat][a->size], 32);
468075e7e97SPeter Maydell }
469075e7e97SPeter Maydell 
470075e7e97SPeter Maydell static bool trans_VST4(DisasContext *s, arg_vldst_il *a)
471075e7e97SPeter Maydell {
472075e7e97SPeter Maydell     static MVEGenLdStIlFn * const fns[4][4] = {
473075e7e97SPeter Maydell         { F(vst40b), F(vst40h), F(vst40w), NULL, },
474075e7e97SPeter Maydell         { F(vst41b), F(vst41h), F(vst41w), NULL, },
475075e7e97SPeter Maydell         { F(vst42b), F(vst42h), F(vst42w), NULL, },
476075e7e97SPeter Maydell         { F(vst43b), F(vst43h), F(vst43w), NULL, },
477075e7e97SPeter Maydell     };
478075e7e97SPeter Maydell     if (a->qd > 4) {
479075e7e97SPeter Maydell         return false;
480075e7e97SPeter Maydell     }
481075e7e97SPeter Maydell     return do_vldst_il(s, a, fns[a->pat][a->size], 64);
482075e7e97SPeter Maydell }
483075e7e97SPeter Maydell 
484075e7e97SPeter Maydell #undef F
485075e7e97SPeter Maydell 
486ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
487ab59362fSPeter Maydell {
488ab59362fSPeter Maydell     TCGv_ptr qd;
489ab59362fSPeter Maydell     TCGv_i32 rt;
490ab59362fSPeter Maydell 
491ab59362fSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
492ab59362fSPeter Maydell         !mve_check_qreg_bank(s, a->qd)) {
493ab59362fSPeter Maydell         return false;
494ab59362fSPeter Maydell     }
495ab59362fSPeter Maydell     if (a->rt == 13 || a->rt == 15) {
496ab59362fSPeter Maydell         /* UNPREDICTABLE; we choose to UNDEF */
497ab59362fSPeter Maydell         return false;
498ab59362fSPeter Maydell     }
499ab59362fSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
500ab59362fSPeter Maydell         return true;
501ab59362fSPeter Maydell     }
502ab59362fSPeter Maydell 
503ab59362fSPeter Maydell     rt = load_reg(s, a->rt);
504f8d94803SPeter Maydell     if (mve_no_predication(s)) {
505f8d94803SPeter Maydell         tcg_gen_gvec_dup_i32(a->size, mve_qreg_offset(a->qd), 16, 16, rt);
506f8d94803SPeter Maydell     } else {
507f8d94803SPeter Maydell         qd = mve_qreg_ptr(a->qd);
508ab59362fSPeter Maydell         tcg_gen_dup_i32(a->size, rt, rt);
509ab59362fSPeter Maydell         gen_helper_mve_vdup(cpu_env, qd, rt);
510ab59362fSPeter Maydell         tcg_temp_free_ptr(qd);
511f8d94803SPeter Maydell     }
512ab59362fSPeter Maydell     tcg_temp_free_i32(rt);
513ab59362fSPeter Maydell     mve_update_eci(s);
514ab59362fSPeter Maydell     return true;
515ab59362fSPeter Maydell }
516ab59362fSPeter Maydell 
5174b1561c4SPeter Maydell static bool do_1op_vec(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn,
5184b1561c4SPeter Maydell                        GVecGen2Fn vecfn)
5190f0f2bd5SPeter Maydell {
5200f0f2bd5SPeter Maydell     TCGv_ptr qd, qm;
5210f0f2bd5SPeter Maydell 
5220f0f2bd5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
5230f0f2bd5SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
5240f0f2bd5SPeter Maydell         !fn) {
5250f0f2bd5SPeter Maydell         return false;
5260f0f2bd5SPeter Maydell     }
5270f0f2bd5SPeter Maydell 
5280f0f2bd5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
5290f0f2bd5SPeter Maydell         return true;
5300f0f2bd5SPeter Maydell     }
5310f0f2bd5SPeter Maydell 
5324b1561c4SPeter Maydell     if (vecfn && mve_no_predication(s)) {
5334b1561c4SPeter Maydell         vecfn(a->size, mve_qreg_offset(a->qd), mve_qreg_offset(a->qm), 16, 16);
5344b1561c4SPeter Maydell     } else {
5350f0f2bd5SPeter Maydell         qd = mve_qreg_ptr(a->qd);
5360f0f2bd5SPeter Maydell         qm = mve_qreg_ptr(a->qm);
5370f0f2bd5SPeter Maydell         fn(cpu_env, qd, qm);
5380f0f2bd5SPeter Maydell         tcg_temp_free_ptr(qd);
5390f0f2bd5SPeter Maydell         tcg_temp_free_ptr(qm);
5404b1561c4SPeter Maydell     }
5410f0f2bd5SPeter Maydell     mve_update_eci(s);
5420f0f2bd5SPeter Maydell     return true;
5430f0f2bd5SPeter Maydell }
5440f0f2bd5SPeter Maydell 
5454b1561c4SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
5464b1561c4SPeter Maydell {
5474b1561c4SPeter Maydell     return do_1op_vec(s, a, fn, NULL);
5484b1561c4SPeter Maydell }
5494b1561c4SPeter Maydell 
5504b1561c4SPeter Maydell #define DO_1OP_VEC(INSN, FN, VECFN)                             \
5510f0f2bd5SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
5520f0f2bd5SPeter Maydell     {                                                           \
5530f0f2bd5SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
5540f0f2bd5SPeter Maydell             gen_helper_mve_##FN##b,                             \
5550f0f2bd5SPeter Maydell             gen_helper_mve_##FN##h,                             \
5560f0f2bd5SPeter Maydell             gen_helper_mve_##FN##w,                             \
5570f0f2bd5SPeter Maydell             NULL,                                               \
5580f0f2bd5SPeter Maydell         };                                                      \
5594b1561c4SPeter Maydell         return do_1op_vec(s, a, fns[a->size], VECFN);           \
5600f0f2bd5SPeter Maydell     }
5610f0f2bd5SPeter Maydell 
5624b1561c4SPeter Maydell #define DO_1OP(INSN, FN) DO_1OP_VEC(INSN, FN, NULL)
5634b1561c4SPeter Maydell 
5640f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz)
5656437f1f7SPeter Maydell DO_1OP(VCLS, vcls)
5664b1561c4SPeter Maydell DO_1OP_VEC(VABS, vabs, tcg_gen_gvec_abs)
5674b1561c4SPeter Maydell DO_1OP_VEC(VNEG, vneg, tcg_gen_gvec_neg)
568398e7cd3SPeter Maydell DO_1OP(VQABS, vqabs)
569398e7cd3SPeter Maydell DO_1OP(VQNEG, vqneg)
570d5c571eaSPeter Maydell DO_1OP(VMAXA, vmaxa)
571d5c571eaSPeter Maydell DO_1OP(VMINA, vmina)
572249b5309SPeter Maydell 
5732ec0dcf0SPeter Maydell /*
5742ec0dcf0SPeter Maydell  * For simple float/int conversions we use the fixed-point
5752ec0dcf0SPeter Maydell  * conversion helpers with a zero shift count
5762ec0dcf0SPeter Maydell  */
5772ec0dcf0SPeter Maydell #define DO_VCVT(INSN, HFN, SFN)                                         \
5782ec0dcf0SPeter Maydell     static void gen_##INSN##h(TCGv_ptr env, TCGv_ptr qd, TCGv_ptr qm)   \
5792ec0dcf0SPeter Maydell     {                                                                   \
5802ec0dcf0SPeter Maydell         gen_helper_mve_##HFN(env, qd, qm, tcg_constant_i32(0));         \
5812ec0dcf0SPeter Maydell     }                                                                   \
5822ec0dcf0SPeter Maydell     static void gen_##INSN##s(TCGv_ptr env, TCGv_ptr qd, TCGv_ptr qm)   \
5832ec0dcf0SPeter Maydell     {                                                                   \
5842ec0dcf0SPeter Maydell         gen_helper_mve_##SFN(env, qd, qm, tcg_constant_i32(0));         \
5852ec0dcf0SPeter Maydell     }                                                                   \
5862ec0dcf0SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)               \
5872ec0dcf0SPeter Maydell     {                                                                   \
5882ec0dcf0SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                          \
5892ec0dcf0SPeter Maydell             NULL,                                                       \
5902ec0dcf0SPeter Maydell             gen_##INSN##h,                                              \
5912ec0dcf0SPeter Maydell             gen_##INSN##s,                                              \
5922ec0dcf0SPeter Maydell             NULL,                                                       \
5932ec0dcf0SPeter Maydell         };                                                              \
5942ec0dcf0SPeter Maydell         if (!dc_isar_feature(aa32_mve_fp, s)) {                         \
5952ec0dcf0SPeter Maydell             return false;                                               \
5962ec0dcf0SPeter Maydell         }                                                               \
5972ec0dcf0SPeter Maydell         return do_1op(s, a, fns[a->size]);                              \
5982ec0dcf0SPeter Maydell     }
5992ec0dcf0SPeter Maydell 
6002ec0dcf0SPeter Maydell DO_VCVT(VCVT_SF, vcvt_sh, vcvt_sf)
6012ec0dcf0SPeter Maydell DO_VCVT(VCVT_UF, vcvt_uh, vcvt_uf)
6022ec0dcf0SPeter Maydell DO_VCVT(VCVT_FS, vcvt_hs, vcvt_fs)
6032ec0dcf0SPeter Maydell DO_VCVT(VCVT_FU, vcvt_hu, vcvt_fu)
6042ec0dcf0SPeter Maydell 
60553fc5f61SPeter Maydell static bool do_vcvt_rmode(DisasContext *s, arg_1op *a,
60653fc5f61SPeter Maydell                           enum arm_fprounding rmode, bool u)
60753fc5f61SPeter Maydell {
60853fc5f61SPeter Maydell     /*
60953fc5f61SPeter Maydell      * Handle VCVT fp to int with specified rounding mode.
61053fc5f61SPeter Maydell      * This is a 1op fn but we must pass the rounding mode as
61153fc5f61SPeter Maydell      * an immediate to the helper.
61253fc5f61SPeter Maydell      */
61353fc5f61SPeter Maydell     TCGv_ptr qd, qm;
61453fc5f61SPeter Maydell     static MVEGenVCVTRmodeFn * const fns[4][2] = {
61553fc5f61SPeter Maydell         { NULL, NULL },
61653fc5f61SPeter Maydell         { gen_helper_mve_vcvt_rm_sh, gen_helper_mve_vcvt_rm_uh },
61753fc5f61SPeter Maydell         { gen_helper_mve_vcvt_rm_ss, gen_helper_mve_vcvt_rm_us },
61853fc5f61SPeter Maydell         { NULL, NULL },
61953fc5f61SPeter Maydell     };
62053fc5f61SPeter Maydell     MVEGenVCVTRmodeFn *fn = fns[a->size][u];
62153fc5f61SPeter Maydell 
62253fc5f61SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s) ||
62353fc5f61SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
62453fc5f61SPeter Maydell         !fn) {
62553fc5f61SPeter Maydell         return false;
62653fc5f61SPeter Maydell     }
62753fc5f61SPeter Maydell 
62853fc5f61SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
62953fc5f61SPeter Maydell         return true;
63053fc5f61SPeter Maydell     }
63153fc5f61SPeter Maydell 
63253fc5f61SPeter Maydell     qd = mve_qreg_ptr(a->qd);
63353fc5f61SPeter Maydell     qm = mve_qreg_ptr(a->qm);
63453fc5f61SPeter Maydell     fn(cpu_env, qd, qm, tcg_constant_i32(arm_rmode_to_sf(rmode)));
63553fc5f61SPeter Maydell     tcg_temp_free_ptr(qd);
63653fc5f61SPeter Maydell     tcg_temp_free_ptr(qm);
63753fc5f61SPeter Maydell     mve_update_eci(s);
63853fc5f61SPeter Maydell     return true;
63953fc5f61SPeter Maydell }
64053fc5f61SPeter Maydell 
64153fc5f61SPeter Maydell #define DO_VCVT_RMODE(INSN, RMODE, U)                           \
64253fc5f61SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
64353fc5f61SPeter Maydell     {                                                           \
64453fc5f61SPeter Maydell         return do_vcvt_rmode(s, a, RMODE, U);                   \
64553fc5f61SPeter Maydell     }                                                           \
64653fc5f61SPeter Maydell 
64753fc5f61SPeter Maydell DO_VCVT_RMODE(VCVTAS, FPROUNDING_TIEAWAY, false)
64853fc5f61SPeter Maydell DO_VCVT_RMODE(VCVTAU, FPROUNDING_TIEAWAY, true)
64953fc5f61SPeter Maydell DO_VCVT_RMODE(VCVTNS, FPROUNDING_TIEEVEN, false)
65053fc5f61SPeter Maydell DO_VCVT_RMODE(VCVTNU, FPROUNDING_TIEEVEN, true)
65153fc5f61SPeter Maydell DO_VCVT_RMODE(VCVTPS, FPROUNDING_POSINF, false)
65253fc5f61SPeter Maydell DO_VCVT_RMODE(VCVTPU, FPROUNDING_POSINF, true)
65353fc5f61SPeter Maydell DO_VCVT_RMODE(VCVTMS, FPROUNDING_NEGINF, false)
65453fc5f61SPeter Maydell DO_VCVT_RMODE(VCVTMU, FPROUNDING_NEGINF, true)
65553fc5f61SPeter Maydell 
65673d260dbSPeter Maydell #define DO_VCVT_SH(INSN, FN)                                    \
65773d260dbSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
65873d260dbSPeter Maydell     {                                                           \
65973d260dbSPeter Maydell         if (!dc_isar_feature(aa32_mve_fp, s)) {                 \
66073d260dbSPeter Maydell             return false;                                       \
66173d260dbSPeter Maydell         }                                                       \
66273d260dbSPeter Maydell         return do_1op(s, a, gen_helper_mve_##FN);               \
66373d260dbSPeter Maydell     }                                                           \
66473d260dbSPeter Maydell 
66573d260dbSPeter Maydell DO_VCVT_SH(VCVTB_SH, vcvtb_sh)
66673d260dbSPeter Maydell DO_VCVT_SH(VCVTT_SH, vcvtt_sh)
66773d260dbSPeter Maydell DO_VCVT_SH(VCVTB_HS, vcvtb_hs)
66873d260dbSPeter Maydell DO_VCVT_SH(VCVTT_HS, vcvtt_hs)
66973d260dbSPeter Maydell 
67098e40fbdSPeter Maydell #define DO_VRINT(INSN, RMODE)                                           \
67198e40fbdSPeter Maydell     static void gen_##INSN##h(TCGv_ptr env, TCGv_ptr qd, TCGv_ptr qm)   \
67298e40fbdSPeter Maydell     {                                                                   \
67398e40fbdSPeter Maydell         gen_helper_mve_vrint_rm_h(env, qd, qm,                          \
67498e40fbdSPeter Maydell                                   tcg_constant_i32(arm_rmode_to_sf(RMODE))); \
67598e40fbdSPeter Maydell     }                                                                   \
67698e40fbdSPeter Maydell     static void gen_##INSN##s(TCGv_ptr env, TCGv_ptr qd, TCGv_ptr qm)   \
67798e40fbdSPeter Maydell     {                                                                   \
67898e40fbdSPeter Maydell         gen_helper_mve_vrint_rm_s(env, qd, qm,                          \
67998e40fbdSPeter Maydell                                   tcg_constant_i32(arm_rmode_to_sf(RMODE))); \
68098e40fbdSPeter Maydell     }                                                                   \
68198e40fbdSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)               \
68298e40fbdSPeter Maydell     {                                                                   \
68398e40fbdSPeter Maydell         static MVEGenOneOpFn * const fns[] = {                          \
68498e40fbdSPeter Maydell             NULL,                                                       \
68598e40fbdSPeter Maydell             gen_##INSN##h,                                              \
68698e40fbdSPeter Maydell             gen_##INSN##s,                                              \
68798e40fbdSPeter Maydell             NULL,                                                       \
68898e40fbdSPeter Maydell         };                                                              \
68998e40fbdSPeter Maydell         if (!dc_isar_feature(aa32_mve_fp, s)) {                         \
69098e40fbdSPeter Maydell             return false;                                               \
69198e40fbdSPeter Maydell         }                                                               \
69298e40fbdSPeter Maydell         return do_1op(s, a, fns[a->size]);                              \
69398e40fbdSPeter Maydell     }
69498e40fbdSPeter Maydell 
69598e40fbdSPeter Maydell DO_VRINT(VRINTN, FPROUNDING_TIEEVEN)
69698e40fbdSPeter Maydell DO_VRINT(VRINTA, FPROUNDING_TIEAWAY)
69798e40fbdSPeter Maydell DO_VRINT(VRINTZ, FPROUNDING_ZERO)
69898e40fbdSPeter Maydell DO_VRINT(VRINTM, FPROUNDING_NEGINF)
69998e40fbdSPeter Maydell DO_VRINT(VRINTP, FPROUNDING_POSINF)
70098e40fbdSPeter Maydell 
70198e40fbdSPeter Maydell static bool trans_VRINTX(DisasContext *s, arg_1op *a)
70298e40fbdSPeter Maydell {
70398e40fbdSPeter Maydell     static MVEGenOneOpFn * const fns[] = {
70498e40fbdSPeter Maydell         NULL,
70598e40fbdSPeter Maydell         gen_helper_mve_vrintx_h,
70698e40fbdSPeter Maydell         gen_helper_mve_vrintx_s,
70798e40fbdSPeter Maydell         NULL,
70898e40fbdSPeter Maydell     };
70998e40fbdSPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
71098e40fbdSPeter Maydell         return false;
71198e40fbdSPeter Maydell     }
71298e40fbdSPeter Maydell     return do_1op(s, a, fns[a->size]);
71398e40fbdSPeter Maydell }
71498e40fbdSPeter Maydell 
71554dc78a9SPeter Maydell /* Narrowing moves: only size 0 and 1 are valid */
71654dc78a9SPeter Maydell #define DO_VMOVN(INSN, FN) \
71754dc78a9SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
71854dc78a9SPeter Maydell     {                                                           \
71954dc78a9SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
72054dc78a9SPeter Maydell             gen_helper_mve_##FN##b,                             \
72154dc78a9SPeter Maydell             gen_helper_mve_##FN##h,                             \
72254dc78a9SPeter Maydell             NULL,                                               \
72354dc78a9SPeter Maydell             NULL,                                               \
72454dc78a9SPeter Maydell         };                                                      \
72554dc78a9SPeter Maydell         return do_1op(s, a, fns[a->size]);                      \
72654dc78a9SPeter Maydell     }
72754dc78a9SPeter Maydell 
72854dc78a9SPeter Maydell DO_VMOVN(VMOVNB, vmovnb)
72954dc78a9SPeter Maydell DO_VMOVN(VMOVNT, vmovnt)
73054dc78a9SPeter Maydell DO_VMOVN(VQMOVUNB, vqmovunb)
73154dc78a9SPeter Maydell DO_VMOVN(VQMOVUNT, vqmovunt)
73254dc78a9SPeter Maydell DO_VMOVN(VQMOVN_BS, vqmovnbs)
73354dc78a9SPeter Maydell DO_VMOVN(VQMOVN_TS, vqmovnts)
73454dc78a9SPeter Maydell DO_VMOVN(VQMOVN_BU, vqmovnbu)
73554dc78a9SPeter Maydell DO_VMOVN(VQMOVN_TU, vqmovntu)
73654dc78a9SPeter Maydell 
737249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a)
738249b5309SPeter Maydell {
739249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
740249b5309SPeter Maydell         gen_helper_mve_vrev16b,
741249b5309SPeter Maydell         NULL,
742249b5309SPeter Maydell         NULL,
743249b5309SPeter Maydell         NULL,
744249b5309SPeter Maydell     };
745249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
746249b5309SPeter Maydell }
747249b5309SPeter Maydell 
748249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a)
749249b5309SPeter Maydell {
750249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
751249b5309SPeter Maydell         gen_helper_mve_vrev32b,
752249b5309SPeter Maydell         gen_helper_mve_vrev32h,
753249b5309SPeter Maydell         NULL,
754249b5309SPeter Maydell         NULL,
755249b5309SPeter Maydell     };
756249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
757249b5309SPeter Maydell }
758249b5309SPeter Maydell 
759249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a)
760249b5309SPeter Maydell {
761249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
762249b5309SPeter Maydell         gen_helper_mve_vrev64b,
763249b5309SPeter Maydell         gen_helper_mve_vrev64h,
764249b5309SPeter Maydell         gen_helper_mve_vrev64w,
765249b5309SPeter Maydell         NULL,
766249b5309SPeter Maydell     };
767249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
768249b5309SPeter Maydell }
7698abd3c80SPeter Maydell 
7708abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a)
7718abd3c80SPeter Maydell {
7725cf525a8SPeter Maydell     return do_1op_vec(s, a, gen_helper_mve_vmvn, tcg_gen_gvec_not);
7738abd3c80SPeter Maydell }
77459c91773SPeter Maydell 
77559c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a)
77659c91773SPeter Maydell {
77759c91773SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
77859c91773SPeter Maydell         NULL,
77959c91773SPeter Maydell         gen_helper_mve_vfabsh,
78059c91773SPeter Maydell         gen_helper_mve_vfabss,
78159c91773SPeter Maydell         NULL,
78259c91773SPeter Maydell     };
78359c91773SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
78459c91773SPeter Maydell         return false;
78559c91773SPeter Maydell     }
78659c91773SPeter Maydell     return do_1op(s, a, fns[a->size]);
78759c91773SPeter Maydell }
788399a8c76SPeter Maydell 
789399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a)
790399a8c76SPeter Maydell {
791399a8c76SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
792399a8c76SPeter Maydell         NULL,
793399a8c76SPeter Maydell         gen_helper_mve_vfnegh,
794399a8c76SPeter Maydell         gen_helper_mve_vfnegs,
795399a8c76SPeter Maydell         NULL,
796399a8c76SPeter Maydell     };
797399a8c76SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
798399a8c76SPeter Maydell         return false;
799399a8c76SPeter Maydell     }
800399a8c76SPeter Maydell     return do_1op(s, a, fns[a->size]);
801399a8c76SPeter Maydell }
80268245e44SPeter Maydell 
803451f9d66SPeter Maydell static bool do_2op_vec(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn,
804451f9d66SPeter Maydell                        GVecGen3Fn *vecfn)
80568245e44SPeter Maydell {
80668245e44SPeter Maydell     TCGv_ptr qd, qn, qm;
80768245e44SPeter Maydell 
80868245e44SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
80968245e44SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) ||
81068245e44SPeter Maydell         !fn) {
81168245e44SPeter Maydell         return false;
81268245e44SPeter Maydell     }
81368245e44SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
81468245e44SPeter Maydell         return true;
81568245e44SPeter Maydell     }
81668245e44SPeter Maydell 
817451f9d66SPeter Maydell     if (vecfn && mve_no_predication(s)) {
818451f9d66SPeter Maydell         vecfn(a->size, mve_qreg_offset(a->qd), mve_qreg_offset(a->qn),
819451f9d66SPeter Maydell               mve_qreg_offset(a->qm), 16, 16);
820451f9d66SPeter Maydell     } else {
82168245e44SPeter Maydell         qd = mve_qreg_ptr(a->qd);
82268245e44SPeter Maydell         qn = mve_qreg_ptr(a->qn);
82368245e44SPeter Maydell         qm = mve_qreg_ptr(a->qm);
82468245e44SPeter Maydell         fn(cpu_env, qd, qn, qm);
82568245e44SPeter Maydell         tcg_temp_free_ptr(qd);
82668245e44SPeter Maydell         tcg_temp_free_ptr(qn);
82768245e44SPeter Maydell         tcg_temp_free_ptr(qm);
828451f9d66SPeter Maydell     }
82968245e44SPeter Maydell     mve_update_eci(s);
83068245e44SPeter Maydell     return true;
83168245e44SPeter Maydell }
83268245e44SPeter Maydell 
833451f9d66SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn *fn)
834451f9d66SPeter Maydell {
835451f9d66SPeter Maydell     return do_2op_vec(s, a, fn, NULL);
83668245e44SPeter Maydell }
83768245e44SPeter Maydell 
838451f9d66SPeter Maydell #define DO_LOGIC(INSN, HELPER, VECFN)                           \
839451f9d66SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
840451f9d66SPeter Maydell     {                                                           \
841451f9d66SPeter Maydell         return do_2op_vec(s, a, HELPER, VECFN);                 \
842451f9d66SPeter Maydell     }
843451f9d66SPeter Maydell 
844451f9d66SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand, tcg_gen_gvec_and)
845451f9d66SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic, tcg_gen_gvec_andc)
846451f9d66SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr, tcg_gen_gvec_or)
847451f9d66SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn, tcg_gen_gvec_orc)
848451f9d66SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor, tcg_gen_gvec_xor)
8499333fe4dSPeter Maydell 
85026702213SPeter Maydell static bool trans_VPSEL(DisasContext *s, arg_2op *a)
85126702213SPeter Maydell {
85226702213SPeter Maydell     /* This insn updates predication bits */
85326702213SPeter Maydell     s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
85426702213SPeter Maydell     return do_2op(s, a, gen_helper_mve_vpsel);
85526702213SPeter Maydell }
856c386443bSPeter Maydell 
857bc3087f2SPeter Maydell #define DO_2OP_VEC(INSN, FN, VECFN)                             \
8589333fe4dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
8599333fe4dSPeter Maydell     {                                                           \
8609333fe4dSPeter Maydell         static MVEGenTwoOpFn * const fns[] = {                  \
8619333fe4dSPeter Maydell             gen_helper_mve_##FN##b,                             \
8629333fe4dSPeter Maydell             gen_helper_mve_##FN##h,                             \
8639333fe4dSPeter Maydell             gen_helper_mve_##FN##w,                             \
8649333fe4dSPeter Maydell             NULL,                                               \
8659333fe4dSPeter Maydell         };                                                      \
866bc3087f2SPeter Maydell         return do_2op_vec(s, a, fns[a->size], VECFN);           \
8679333fe4dSPeter Maydell     }
8689333fe4dSPeter Maydell 
869bc3087f2SPeter Maydell #define DO_2OP(INSN, FN) DO_2OP_VEC(INSN, FN, NULL)
870bc3087f2SPeter Maydell 
871bc3087f2SPeter Maydell DO_2OP_VEC(VADD, vadd, tcg_gen_gvec_add)
872bc3087f2SPeter Maydell DO_2OP_VEC(VSUB, vsub, tcg_gen_gvec_sub)
873bc3087f2SPeter Maydell DO_2OP_VEC(VMUL, vmul, tcg_gen_gvec_mul)
874ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs)
875ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu)
876fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs)
877fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu)
878bc3087f2SPeter Maydell DO_2OP_VEC(VMAX_S, vmaxs, tcg_gen_gvec_smax)
879bc3087f2SPeter Maydell DO_2OP_VEC(VMAX_U, vmaxu, tcg_gen_gvec_umax)
880bc3087f2SPeter Maydell DO_2OP_VEC(VMIN_S, vmins, tcg_gen_gvec_smin)
881bc3087f2SPeter Maydell DO_2OP_VEC(VMIN_U, vminu, tcg_gen_gvec_umin)
882bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds)
883bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu)
884abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds)
885abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu)
886abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs)
887abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu)
888ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs)
889ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu)
890ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts)
891ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu)
892380caf6cSPeter Maydell DO_2OP(VQDMULH, vqdmulh)
893380caf6cSPeter Maydell DO_2OP(VQRDMULH, vqrdmulh)
894f741707bSPeter Maydell DO_2OP(VQADD_S, vqadds)
895f741707bSPeter Maydell DO_2OP(VQADD_U, vqaddu)
896f741707bSPeter Maydell DO_2OP(VQSUB_S, vqsubs)
897f741707bSPeter Maydell DO_2OP(VQSUB_U, vqsubu)
8980372cad8SPeter Maydell DO_2OP(VSHL_S, vshls)
8990372cad8SPeter Maydell DO_2OP(VSHL_U, vshlu)
900bb002345SPeter Maydell DO_2OP(VRSHL_S, vrshls)
901bb002345SPeter Maydell DO_2OP(VRSHL_U, vrshlu)
902483da661SPeter Maydell DO_2OP(VQSHL_S, vqshls)
903483da661SPeter Maydell DO_2OP(VQSHL_U, vqshlu)
9049dc868c4SPeter Maydell DO_2OP(VQRSHL_S, vqrshls)
9059dc868c4SPeter Maydell DO_2OP(VQRSHL_U, vqrshlu)
906fd677f80SPeter Maydell DO_2OP(VQDMLADH, vqdmladh)
907fd677f80SPeter Maydell DO_2OP(VQDMLADHX, vqdmladhx)
908fd677f80SPeter Maydell DO_2OP(VQRDMLADH, vqrdmladh)
909fd677f80SPeter Maydell DO_2OP(VQRDMLADHX, vqrdmladhx)
91092f11732SPeter Maydell DO_2OP(VQDMLSDH, vqdmlsdh)
91192f11732SPeter Maydell DO_2OP(VQDMLSDHX, vqdmlsdhx)
91292f11732SPeter Maydell DO_2OP(VQRDMLSDH, vqrdmlsdh)
91392f11732SPeter Maydell DO_2OP(VQRDMLSDHX, vqrdmlsdhx)
9141eb987a8SPeter Maydell DO_2OP(VRHADD_S, vrhadds)
9151eb987a8SPeter Maydell DO_2OP(VRHADD_U, vrhaddu)
91667ec113bSPeter Maydell /*
91767ec113bSPeter Maydell  * VCADD Qd == Qm at size MO_32 is UNPREDICTABLE; we choose not to diagnose
91867ec113bSPeter Maydell  * so we can reuse the DO_2OP macro. (Our implementation calculates the
9198625693aSPeter Maydell  * "expected" results in this case.) Similarly for VHCADD.
92067ec113bSPeter Maydell  */
92167ec113bSPeter Maydell DO_2OP(VCADD90, vcadd90)
92267ec113bSPeter Maydell DO_2OP(VCADD270, vcadd270)
9238625693aSPeter Maydell DO_2OP(VHCADD90, vhcadd90)
9248625693aSPeter Maydell DO_2OP(VHCADD270, vhcadd270)
9251d2386f7SPeter Maydell 
92643364321SPeter Maydell static bool trans_VQDMULLB(DisasContext *s, arg_2op *a)
92743364321SPeter Maydell {
92843364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
92943364321SPeter Maydell         NULL,
93043364321SPeter Maydell         gen_helper_mve_vqdmullbh,
93143364321SPeter Maydell         gen_helper_mve_vqdmullbw,
93243364321SPeter Maydell         NULL,
93343364321SPeter Maydell     };
93443364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
93543364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
93643364321SPeter Maydell         return false;
93743364321SPeter Maydell     }
93843364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
93943364321SPeter Maydell }
94043364321SPeter Maydell 
94143364321SPeter Maydell static bool trans_VQDMULLT(DisasContext *s, arg_2op *a)
94243364321SPeter Maydell {
94343364321SPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
94443364321SPeter Maydell         NULL,
94543364321SPeter Maydell         gen_helper_mve_vqdmullth,
94643364321SPeter Maydell         gen_helper_mve_vqdmulltw,
94743364321SPeter Maydell         NULL,
94843364321SPeter Maydell     };
94943364321SPeter Maydell     if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) {
95043364321SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
95143364321SPeter Maydell         return false;
95243364321SPeter Maydell     }
95343364321SPeter Maydell     return do_2op(s, a, fns[a->size]);
95443364321SPeter Maydell }
95543364321SPeter Maydell 
956c1bd78cbSPeter Maydell static bool trans_VMULLP_B(DisasContext *s, arg_2op *a)
957c1bd78cbSPeter Maydell {
958c1bd78cbSPeter Maydell     /*
959c1bd78cbSPeter Maydell      * Note that a->size indicates the output size, ie VMULL.P8
960c1bd78cbSPeter Maydell      * is the 8x8->16 operation and a->size is MO_16; VMULL.P16
961c1bd78cbSPeter Maydell      * is the 16x16->32 operation and a->size is MO_32.
962c1bd78cbSPeter Maydell      */
963c1bd78cbSPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
964c1bd78cbSPeter Maydell         NULL,
965c1bd78cbSPeter Maydell         gen_helper_mve_vmullpbh,
966c1bd78cbSPeter Maydell         gen_helper_mve_vmullpbw,
967c1bd78cbSPeter Maydell         NULL,
968c1bd78cbSPeter Maydell     };
969c1bd78cbSPeter Maydell     return do_2op(s, a, fns[a->size]);
970c1bd78cbSPeter Maydell }
971c1bd78cbSPeter Maydell 
972c1bd78cbSPeter Maydell static bool trans_VMULLP_T(DisasContext *s, arg_2op *a)
973c1bd78cbSPeter Maydell {
974c1bd78cbSPeter Maydell     /* a->size is as for trans_VMULLP_B */
975c1bd78cbSPeter Maydell     static MVEGenTwoOpFn * const fns[] = {
976c1bd78cbSPeter Maydell         NULL,
977c1bd78cbSPeter Maydell         gen_helper_mve_vmullpth,
978c1bd78cbSPeter Maydell         gen_helper_mve_vmullptw,
979c1bd78cbSPeter Maydell         NULL,
980c1bd78cbSPeter Maydell     };
981c1bd78cbSPeter Maydell     return do_2op(s, a, fns[a->size]);
982c1bd78cbSPeter Maydell }
983c1bd78cbSPeter Maydell 
98489bc4c4fSPeter Maydell /*
98589bc4c4fSPeter Maydell  * VADC and VSBC: these perform an add-with-carry or subtract-with-carry
98689bc4c4fSPeter Maydell  * of the 32-bit elements in each lane of the input vectors, where the
98789bc4c4fSPeter Maydell  * carry-out of each add is the carry-in of the next.  The initial carry
98889bc4c4fSPeter Maydell  * input is either fixed (0 for VADCI, 1 for VSBCI) or is from FPSCR.C
98989bc4c4fSPeter Maydell  * (for VADC and VSBC); the carry out at the end is written back to FPSCR.C.
99089bc4c4fSPeter Maydell  * These insns are subject to beat-wise execution.  Partial execution
99189bc4c4fSPeter Maydell  * of an I=1 (initial carry input fixed) insn which does not
99289bc4c4fSPeter Maydell  * execute the first beat must start with the current FPSCR.NZCV
99389bc4c4fSPeter Maydell  * value, not the fixed constant input.
99489bc4c4fSPeter Maydell  */
99589bc4c4fSPeter Maydell static bool trans_VADC(DisasContext *s, arg_2op *a)
99689bc4c4fSPeter Maydell {
99789bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadc);
99889bc4c4fSPeter Maydell }
99989bc4c4fSPeter Maydell 
100089bc4c4fSPeter Maydell static bool trans_VADCI(DisasContext *s, arg_2op *a)
100189bc4c4fSPeter Maydell {
100289bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
100389bc4c4fSPeter Maydell         return trans_VADC(s, a);
100489bc4c4fSPeter Maydell     }
100589bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vadci);
100689bc4c4fSPeter Maydell }
100789bc4c4fSPeter Maydell 
100889bc4c4fSPeter Maydell static bool trans_VSBC(DisasContext *s, arg_2op *a)
100989bc4c4fSPeter Maydell {
101089bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbc);
101189bc4c4fSPeter Maydell }
101289bc4c4fSPeter Maydell 
101389bc4c4fSPeter Maydell static bool trans_VSBCI(DisasContext *s, arg_2op *a)
101489bc4c4fSPeter Maydell {
101589bc4c4fSPeter Maydell     if (mve_skip_first_beat(s)) {
101689bc4c4fSPeter Maydell         return trans_VSBC(s, a);
101789bc4c4fSPeter Maydell     }
101889bc4c4fSPeter Maydell     return do_2op(s, a, gen_helper_mve_vsbci);
101989bc4c4fSPeter Maydell }
102089bc4c4fSPeter Maydell 
10211e35cd91SPeter Maydell #define DO_2OP_FP(INSN, FN)                                     \
10221e35cd91SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
10231e35cd91SPeter Maydell     {                                                           \
10241e35cd91SPeter Maydell         static MVEGenTwoOpFn * const fns[] = {                  \
10251e35cd91SPeter Maydell             NULL,                                               \
10261e35cd91SPeter Maydell             gen_helper_mve_##FN##h,                             \
10271e35cd91SPeter Maydell             gen_helper_mve_##FN##s,                             \
10281e35cd91SPeter Maydell             NULL,                                               \
10291e35cd91SPeter Maydell         };                                                      \
10301e35cd91SPeter Maydell         if (!dc_isar_feature(aa32_mve_fp, s)) {                 \
10311e35cd91SPeter Maydell             return false;                                       \
10321e35cd91SPeter Maydell         }                                                       \
10331e35cd91SPeter Maydell         return do_2op(s, a, fns[a->size]);                      \
10341e35cd91SPeter Maydell     }
10351e35cd91SPeter Maydell 
10361e35cd91SPeter Maydell DO_2OP_FP(VADD_fp, vfadd)
103782af0153SPeter Maydell DO_2OP_FP(VSUB_fp, vfsub)
103882af0153SPeter Maydell DO_2OP_FP(VMUL_fp, vfmul)
103982af0153SPeter Maydell DO_2OP_FP(VABD_fp, vfabd)
104082af0153SPeter Maydell DO_2OP_FP(VMAXNM, vmaxnm)
104182af0153SPeter Maydell DO_2OP_FP(VMINNM, vminnm)
1042104afc68SPeter Maydell DO_2OP_FP(VCADD90_fp, vfcadd90)
1043104afc68SPeter Maydell DO_2OP_FP(VCADD270_fp, vfcadd270)
10443173c0ddSPeter Maydell DO_2OP_FP(VFMA, vfma)
10453173c0ddSPeter Maydell DO_2OP_FP(VFMS, vfms)
1046d3cd965cSPeter Maydell DO_2OP_FP(VCMUL0, vcmul0)
1047d3cd965cSPeter Maydell DO_2OP_FP(VCMUL90, vcmul90)
1048d3cd965cSPeter Maydell DO_2OP_FP(VCMUL180, vcmul180)
1049d3cd965cSPeter Maydell DO_2OP_FP(VCMUL270, vcmul270)
1050d3cd965cSPeter Maydell DO_2OP_FP(VCMLA0, vcmla0)
1051d3cd965cSPeter Maydell DO_2OP_FP(VCMLA90, vcmla90)
1052d3cd965cSPeter Maydell DO_2OP_FP(VCMLA180, vcmla180)
1053d3cd965cSPeter Maydell DO_2OP_FP(VCMLA270, vcmla270)
105490257a4fSPeter Maydell DO_2OP_FP(VMAXNMA, vmaxnma)
105590257a4fSPeter Maydell DO_2OP_FP(VMINNMA, vminnma)
10561e35cd91SPeter Maydell 
1057e51896b3SPeter Maydell static bool do_2op_scalar(DisasContext *s, arg_2scalar *a,
1058e51896b3SPeter Maydell                           MVEGenTwoOpScalarFn fn)
1059e51896b3SPeter Maydell {
1060e51896b3SPeter Maydell     TCGv_ptr qd, qn;
1061e51896b3SPeter Maydell     TCGv_i32 rm;
1062e51896b3SPeter Maydell 
1063e51896b3SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
1064e51896b3SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn) ||
1065e51896b3SPeter Maydell         !fn) {
1066e51896b3SPeter Maydell         return false;
1067e51896b3SPeter Maydell     }
1068e51896b3SPeter Maydell     if (a->rm == 13 || a->rm == 15) {
1069e51896b3SPeter Maydell         /* UNPREDICTABLE */
1070e51896b3SPeter Maydell         return false;
1071e51896b3SPeter Maydell     }
1072e51896b3SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1073e51896b3SPeter Maydell         return true;
1074e51896b3SPeter Maydell     }
1075e51896b3SPeter Maydell 
1076e51896b3SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1077e51896b3SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1078e51896b3SPeter Maydell     rm = load_reg(s, a->rm);
1079e51896b3SPeter Maydell     fn(cpu_env, qd, qn, rm);
1080e51896b3SPeter Maydell     tcg_temp_free_i32(rm);
1081e51896b3SPeter Maydell     tcg_temp_free_ptr(qd);
1082e51896b3SPeter Maydell     tcg_temp_free_ptr(qn);
1083e51896b3SPeter Maydell     mve_update_eci(s);
1084e51896b3SPeter Maydell     return true;
1085e51896b3SPeter Maydell }
1086e51896b3SPeter Maydell 
1087e51896b3SPeter Maydell #define DO_2OP_SCALAR(INSN, FN)                                 \
1088e51896b3SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2scalar *a)   \
1089e51896b3SPeter Maydell     {                                                           \
1090e51896b3SPeter Maydell         static MVEGenTwoOpScalarFn * const fns[] = {            \
1091e51896b3SPeter Maydell             gen_helper_mve_##FN##b,                             \
1092e51896b3SPeter Maydell             gen_helper_mve_##FN##h,                             \
1093e51896b3SPeter Maydell             gen_helper_mve_##FN##w,                             \
1094e51896b3SPeter Maydell             NULL,                                               \
1095e51896b3SPeter Maydell         };                                                      \
1096e51896b3SPeter Maydell         return do_2op_scalar(s, a, fns[a->size]);               \
1097e51896b3SPeter Maydell     }
1098e51896b3SPeter Maydell 
1099e51896b3SPeter Maydell DO_2OP_SCALAR(VADD_scalar, vadd_scalar)
110091a358fdSPeter Maydell DO_2OP_SCALAR(VSUB_scalar, vsub_scalar)
110191a358fdSPeter Maydell DO_2OP_SCALAR(VMUL_scalar, vmul_scalar)
1102644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_S_scalar, vhadds_scalar)
1103644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_U_scalar, vhaddu_scalar)
1104644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_S_scalar, vhsubs_scalar)
1105644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_U_scalar, vhsubu_scalar)
110639f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_S_scalar, vqadds_scalar)
110739f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_U_scalar, vqaddu_scalar)
110839f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_S_scalar, vqsubs_scalar)
110939f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_U_scalar, vqsubu_scalar)
111066c05767SPeter Maydell DO_2OP_SCALAR(VQDMULH_scalar, vqdmulh_scalar)
111166c05767SPeter Maydell DO_2OP_SCALAR(VQRDMULH_scalar, vqrdmulh_scalar)
1112b050543bSPeter Maydell DO_2OP_SCALAR(VBRSR, vbrsr)
1113c69e34c6SPeter Maydell DO_2OP_SCALAR(VMLA, vmla)
11146b895bf8SPeter Maydell DO_2OP_SCALAR(VMLAS, vmlas)
11158be9a250SPeter Maydell DO_2OP_SCALAR(VQDMLAH, vqdmlah)
11168be9a250SPeter Maydell DO_2OP_SCALAR(VQRDMLAH, vqrdmlah)
11178be9a250SPeter Maydell DO_2OP_SCALAR(VQDMLASH, vqdmlash)
11188be9a250SPeter Maydell DO_2OP_SCALAR(VQRDMLASH, vqrdmlash)
1119e51896b3SPeter Maydell 
1120a8890353SPeter Maydell static bool trans_VQDMULLB_scalar(DisasContext *s, arg_2scalar *a)
1121a8890353SPeter Maydell {
1122a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
1123a8890353SPeter Maydell         NULL,
1124a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarh,
1125a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarw,
1126a8890353SPeter Maydell         NULL,
1127a8890353SPeter Maydell     };
1128a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
1129a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
1130a8890353SPeter Maydell         return false;
1131a8890353SPeter Maydell     }
1132a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
1133a8890353SPeter Maydell }
1134a8890353SPeter Maydell 
1135a8890353SPeter Maydell static bool trans_VQDMULLT_scalar(DisasContext *s, arg_2scalar *a)
1136a8890353SPeter Maydell {
1137a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
1138a8890353SPeter Maydell         NULL,
1139a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarh,
1140a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarw,
1141a8890353SPeter Maydell         NULL,
1142a8890353SPeter Maydell     };
1143a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
1144a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
1145a8890353SPeter Maydell         return false;
1146a8890353SPeter Maydell     }
1147a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
1148a8890353SPeter Maydell }
1149a8890353SPeter Maydell 
1150abfe39b2SPeter Maydell 
1151abfe39b2SPeter Maydell #define DO_2OP_FP_SCALAR(INSN, FN)                              \
1152abfe39b2SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2scalar *a)   \
1153abfe39b2SPeter Maydell     {                                                           \
1154abfe39b2SPeter Maydell         static MVEGenTwoOpScalarFn * const fns[] = {            \
1155abfe39b2SPeter Maydell             NULL,                                               \
1156abfe39b2SPeter Maydell             gen_helper_mve_##FN##h,                             \
1157abfe39b2SPeter Maydell             gen_helper_mve_##FN##s,                             \
1158abfe39b2SPeter Maydell             NULL,                                               \
1159abfe39b2SPeter Maydell         };                                                      \
1160abfe39b2SPeter Maydell         if (!dc_isar_feature(aa32_mve_fp, s)) {                 \
1161abfe39b2SPeter Maydell             return false;                                       \
1162abfe39b2SPeter Maydell         }                                                       \
1163abfe39b2SPeter Maydell         return do_2op_scalar(s, a, fns[a->size]);               \
1164abfe39b2SPeter Maydell     }
1165abfe39b2SPeter Maydell 
1166abfe39b2SPeter Maydell DO_2OP_FP_SCALAR(VADD_fp_scalar, vfadd_scalar)
1167abfe39b2SPeter Maydell DO_2OP_FP_SCALAR(VSUB_fp_scalar, vfsub_scalar)
1168abfe39b2SPeter Maydell DO_2OP_FP_SCALAR(VMUL_fp_scalar, vfmul_scalar)
11694773e74eSPeter Maydell DO_2OP_FP_SCALAR(VFMA_scalar, vfma_scalar)
11704773e74eSPeter Maydell DO_2OP_FP_SCALAR(VFMAS_scalar, vfmas_scalar)
1171abfe39b2SPeter Maydell 
11721d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a,
1173640cdf20SPeter Maydell                              MVEGenLongDualAccOpFn *fn)
11741d2386f7SPeter Maydell {
11751d2386f7SPeter Maydell     TCGv_ptr qn, qm;
11761d2386f7SPeter Maydell     TCGv_i64 rda;
11771d2386f7SPeter Maydell     TCGv_i32 rdalo, rdahi;
11781d2386f7SPeter Maydell 
11791d2386f7SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
11801d2386f7SPeter Maydell         !mve_check_qreg_bank(s, a->qn | a->qm) ||
11811d2386f7SPeter Maydell         !fn) {
11821d2386f7SPeter Maydell         return false;
11831d2386f7SPeter Maydell     }
11841d2386f7SPeter Maydell     /*
11851d2386f7SPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
11861d2386f7SPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
11871d2386f7SPeter Maydell      */
11881d2386f7SPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
11891d2386f7SPeter Maydell         return false;
11901d2386f7SPeter Maydell     }
11911d2386f7SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
11921d2386f7SPeter Maydell         return true;
11931d2386f7SPeter Maydell     }
11941d2386f7SPeter Maydell 
11951d2386f7SPeter Maydell     qn = mve_qreg_ptr(a->qn);
11961d2386f7SPeter Maydell     qm = mve_qreg_ptr(a->qm);
11971d2386f7SPeter Maydell 
11981d2386f7SPeter Maydell     /*
11991d2386f7SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
12001d2386f7SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
12011d2386f7SPeter Maydell      * beat must start with the current rda value, not 0.
12021d2386f7SPeter Maydell      */
12031d2386f7SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
12041d2386f7SPeter Maydell         rda = tcg_temp_new_i64();
12051d2386f7SPeter Maydell         rdalo = load_reg(s, a->rdalo);
12061d2386f7SPeter Maydell         rdahi = load_reg(s, a->rdahi);
12071d2386f7SPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
12081d2386f7SPeter Maydell         tcg_temp_free_i32(rdalo);
12091d2386f7SPeter Maydell         tcg_temp_free_i32(rdahi);
12101d2386f7SPeter Maydell     } else {
12111d2386f7SPeter Maydell         rda = tcg_const_i64(0);
12121d2386f7SPeter Maydell     }
12131d2386f7SPeter Maydell 
12141d2386f7SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
12151d2386f7SPeter Maydell     tcg_temp_free_ptr(qn);
12161d2386f7SPeter Maydell     tcg_temp_free_ptr(qm);
12171d2386f7SPeter Maydell 
12181d2386f7SPeter Maydell     rdalo = tcg_temp_new_i32();
12191d2386f7SPeter Maydell     rdahi = tcg_temp_new_i32();
12201d2386f7SPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
12211d2386f7SPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
12221d2386f7SPeter Maydell     store_reg(s, a->rdalo, rdalo);
12231d2386f7SPeter Maydell     store_reg(s, a->rdahi, rdahi);
12241d2386f7SPeter Maydell     tcg_temp_free_i64(rda);
12251d2386f7SPeter Maydell     mve_update_eci(s);
12261d2386f7SPeter Maydell     return true;
12271d2386f7SPeter Maydell }
12281d2386f7SPeter Maydell 
12291d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a)
12301d2386f7SPeter Maydell {
1231640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
12321d2386f7SPeter Maydell         { NULL, NULL },
12331d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh },
12341d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw },
12351d2386f7SPeter Maydell         { NULL, NULL },
12361d2386f7SPeter Maydell     };
12371d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
12381d2386f7SPeter Maydell }
12391d2386f7SPeter Maydell 
12401d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a)
12411d2386f7SPeter Maydell {
1242640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
12431d2386f7SPeter Maydell         { NULL, NULL },
12441d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuh, NULL },
12451d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuw, NULL },
12461d2386f7SPeter Maydell         { NULL, NULL },
12471d2386f7SPeter Maydell     };
12481d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
12491d2386f7SPeter Maydell }
1250181cd971SPeter Maydell 
1251181cd971SPeter Maydell static bool trans_VMLSLDAV(DisasContext *s, arg_vmlaldav *a)
1252181cd971SPeter Maydell {
1253640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[4][2] = {
1254181cd971SPeter Maydell         { NULL, NULL },
1255181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh },
1256181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw },
1257181cd971SPeter Maydell         { NULL, NULL },
1258181cd971SPeter Maydell     };
1259181cd971SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
1260181cd971SPeter Maydell }
126138548747SPeter Maydell 
126238548747SPeter Maydell static bool trans_VRMLALDAVH_S(DisasContext *s, arg_vmlaldav *a)
126338548747SPeter Maydell {
1264640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
126538548747SPeter Maydell         gen_helper_mve_vrmlaldavhsw, gen_helper_mve_vrmlaldavhxsw,
126638548747SPeter Maydell     };
126738548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
126838548747SPeter Maydell }
126938548747SPeter Maydell 
127038548747SPeter Maydell static bool trans_VRMLALDAVH_U(DisasContext *s, arg_vmlaldav *a)
127138548747SPeter Maydell {
1272640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
127338548747SPeter Maydell         gen_helper_mve_vrmlaldavhuw, NULL,
127438548747SPeter Maydell     };
127538548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
127638548747SPeter Maydell }
127738548747SPeter Maydell 
127838548747SPeter Maydell static bool trans_VRMLSLDAVH(DisasContext *s, arg_vmlaldav *a)
127938548747SPeter Maydell {
1280640cdf20SPeter Maydell     static MVEGenLongDualAccOpFn * const fns[] = {
128138548747SPeter Maydell         gen_helper_mve_vrmlsldavhsw, gen_helper_mve_vrmlsldavhxsw,
128238548747SPeter Maydell     };
128338548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
128438548747SPeter Maydell }
1285387debdbSPeter Maydell 
1286f0ffff51SPeter Maydell static bool do_dual_acc(DisasContext *s, arg_vmladav *a, MVEGenDualAccOpFn *fn)
1287f0ffff51SPeter Maydell {
1288f0ffff51SPeter Maydell     TCGv_ptr qn, qm;
1289f0ffff51SPeter Maydell     TCGv_i32 rda;
1290f0ffff51SPeter Maydell 
1291f0ffff51SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
1292f0ffff51SPeter Maydell         !mve_check_qreg_bank(s, a->qn) ||
1293f0ffff51SPeter Maydell         !fn) {
1294f0ffff51SPeter Maydell         return false;
1295f0ffff51SPeter Maydell     }
1296f0ffff51SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1297f0ffff51SPeter Maydell         return true;
1298f0ffff51SPeter Maydell     }
1299f0ffff51SPeter Maydell 
1300f0ffff51SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1301f0ffff51SPeter Maydell     qm = mve_qreg_ptr(a->qm);
1302f0ffff51SPeter Maydell 
1303f0ffff51SPeter Maydell     /*
1304f0ffff51SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
1305f0ffff51SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
1306f0ffff51SPeter Maydell      * beat must start with the current rda value, not 0.
1307f0ffff51SPeter Maydell      */
1308f0ffff51SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
1309f0ffff51SPeter Maydell         rda = load_reg(s, a->rda);
1310f0ffff51SPeter Maydell     } else {
1311f0ffff51SPeter Maydell         rda = tcg_const_i32(0);
1312f0ffff51SPeter Maydell     }
1313f0ffff51SPeter Maydell 
1314f0ffff51SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
1315f0ffff51SPeter Maydell     store_reg(s, a->rda, rda);
1316f0ffff51SPeter Maydell     tcg_temp_free_ptr(qn);
1317f0ffff51SPeter Maydell     tcg_temp_free_ptr(qm);
1318f0ffff51SPeter Maydell 
1319f0ffff51SPeter Maydell     mve_update_eci(s);
1320f0ffff51SPeter Maydell     return true;
1321f0ffff51SPeter Maydell }
1322f0ffff51SPeter Maydell 
1323f0ffff51SPeter Maydell #define DO_DUAL_ACC(INSN, FN)                                           \
1324f0ffff51SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vmladav *a)           \
1325f0ffff51SPeter Maydell     {                                                                   \
1326f0ffff51SPeter Maydell         static MVEGenDualAccOpFn * const fns[4][2] = {                  \
1327f0ffff51SPeter Maydell             { gen_helper_mve_##FN##b, gen_helper_mve_##FN##xb },        \
1328f0ffff51SPeter Maydell             { gen_helper_mve_##FN##h, gen_helper_mve_##FN##xh },        \
1329f0ffff51SPeter Maydell             { gen_helper_mve_##FN##w, gen_helper_mve_##FN##xw },        \
1330f0ffff51SPeter Maydell             { NULL, NULL },                                             \
1331f0ffff51SPeter Maydell         };                                                              \
1332f0ffff51SPeter Maydell         return do_dual_acc(s, a, fns[a->size][a->x]);                   \
1333f0ffff51SPeter Maydell     }
1334f0ffff51SPeter Maydell 
1335f0ffff51SPeter Maydell DO_DUAL_ACC(VMLADAV_S, vmladavs)
1336f0ffff51SPeter Maydell DO_DUAL_ACC(VMLSDAV, vmlsdav)
1337f0ffff51SPeter Maydell 
1338f0ffff51SPeter Maydell static bool trans_VMLADAV_U(DisasContext *s, arg_vmladav *a)
1339f0ffff51SPeter Maydell {
1340f0ffff51SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
1341f0ffff51SPeter Maydell         { gen_helper_mve_vmladavub, NULL },
1342f0ffff51SPeter Maydell         { gen_helper_mve_vmladavuh, NULL },
1343f0ffff51SPeter Maydell         { gen_helper_mve_vmladavuw, NULL },
1344f0ffff51SPeter Maydell         { NULL, NULL },
1345f0ffff51SPeter Maydell     };
1346f0ffff51SPeter Maydell     return do_dual_acc(s, a, fns[a->size][a->x]);
1347f0ffff51SPeter Maydell }
1348f0ffff51SPeter Maydell 
134955251786SPeter Maydell static void gen_vpst(DisasContext *s, uint32_t mask)
1350387debdbSPeter Maydell {
1351387debdbSPeter Maydell     /*
1352387debdbSPeter Maydell      * Set the VPR mask fields. We take advantage of MASK01 and MASK23
1353387debdbSPeter Maydell      * being adjacent fields in the register.
1354387debdbSPeter Maydell      *
135555251786SPeter Maydell      * Updating the masks is not predicated, but it is subject to beat-wise
1356387debdbSPeter Maydell      * execution, and the mask is updated on the odd-numbered beats.
1357387debdbSPeter Maydell      * So if PSR.ECI says we should skip beat 1, we mustn't update the
1358387debdbSPeter Maydell      * 01 mask field.
1359387debdbSPeter Maydell      */
136055251786SPeter Maydell     TCGv_i32 vpr = load_cpu_field(v7m.vpr);
1361387debdbSPeter Maydell     switch (s->eci) {
1362387debdbSPeter Maydell     case ECI_NONE:
1363387debdbSPeter Maydell     case ECI_A0:
1364387debdbSPeter Maydell         /* Update both 01 and 23 fields */
1365387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
136655251786SPeter Maydell                             tcg_constant_i32(mask | (mask << 4)),
1367387debdbSPeter Maydell                             R_V7M_VPR_MASK01_SHIFT,
1368387debdbSPeter Maydell                             R_V7M_VPR_MASK01_LENGTH + R_V7M_VPR_MASK23_LENGTH);
1369387debdbSPeter Maydell         break;
1370387debdbSPeter Maydell     case ECI_A0A1:
1371387debdbSPeter Maydell     case ECI_A0A1A2:
1372387debdbSPeter Maydell     case ECI_A0A1A2B0:
1373387debdbSPeter Maydell         /* Update only the 23 mask field */
1374387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
137555251786SPeter Maydell                             tcg_constant_i32(mask),
1376387debdbSPeter Maydell                             R_V7M_VPR_MASK23_SHIFT, R_V7M_VPR_MASK23_LENGTH);
1377387debdbSPeter Maydell         break;
1378387debdbSPeter Maydell     default:
1379387debdbSPeter Maydell         g_assert_not_reached();
1380387debdbSPeter Maydell     }
1381387debdbSPeter Maydell     store_cpu_field(vpr, v7m.vpr);
138255251786SPeter Maydell }
138355251786SPeter Maydell 
138455251786SPeter Maydell static bool trans_VPST(DisasContext *s, arg_VPST *a)
138555251786SPeter Maydell {
138655251786SPeter Maydell     /* mask == 0 is a "related encoding" */
138755251786SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !a->mask) {
138855251786SPeter Maydell         return false;
138955251786SPeter Maydell     }
139055251786SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
139155251786SPeter Maydell         return true;
139255251786SPeter Maydell     }
139355251786SPeter Maydell     gen_vpst(s, a->mask);
1394387debdbSPeter Maydell     mve_update_and_store_eci(s);
1395387debdbSPeter Maydell     return true;
1396387debdbSPeter Maydell }
13976f060a63SPeter Maydell 
1398fea3958fSPeter Maydell static bool trans_VPNOT(DisasContext *s, arg_VPNOT *a)
1399fea3958fSPeter Maydell {
1400fea3958fSPeter Maydell     /*
1401fea3958fSPeter Maydell      * Invert the predicate in VPR.P0. We have call out to
1402fea3958fSPeter Maydell      * a helper because this insn itself is beatwise and can
1403fea3958fSPeter Maydell      * be predicated.
1404fea3958fSPeter Maydell      */
1405fea3958fSPeter Maydell     if (!dc_isar_feature(aa32_mve, s)) {
1406fea3958fSPeter Maydell         return false;
1407fea3958fSPeter Maydell     }
1408fea3958fSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1409fea3958fSPeter Maydell         return true;
1410fea3958fSPeter Maydell     }
1411fea3958fSPeter Maydell 
1412fea3958fSPeter Maydell     gen_helper_mve_vpnot(cpu_env);
141326702213SPeter Maydell     /* This insn updates predication bits */
141426702213SPeter Maydell     s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
1415fea3958fSPeter Maydell     mve_update_eci(s);
1416fea3958fSPeter Maydell     return true;
1417fea3958fSPeter Maydell }
1418fea3958fSPeter Maydell 
14196f060a63SPeter Maydell static bool trans_VADDV(DisasContext *s, arg_VADDV *a)
14206f060a63SPeter Maydell {
14216f060a63SPeter Maydell     /* VADDV: vector add across vector */
14226f060a63SPeter Maydell     static MVEGenVADDVFn * const fns[4][2] = {
14236f060a63SPeter Maydell         { gen_helper_mve_vaddvsb, gen_helper_mve_vaddvub },
14246f060a63SPeter Maydell         { gen_helper_mve_vaddvsh, gen_helper_mve_vaddvuh },
14256f060a63SPeter Maydell         { gen_helper_mve_vaddvsw, gen_helper_mve_vaddvuw },
14266f060a63SPeter Maydell         { NULL, NULL }
14276f060a63SPeter Maydell     };
14286f060a63SPeter Maydell     TCGv_ptr qm;
14296f060a63SPeter Maydell     TCGv_i32 rda;
14306f060a63SPeter Maydell 
14316f060a63SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
14326f060a63SPeter Maydell         a->size == 3) {
14336f060a63SPeter Maydell         return false;
14346f060a63SPeter Maydell     }
14356f060a63SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
14366f060a63SPeter Maydell         return true;
14376f060a63SPeter Maydell     }
14386f060a63SPeter Maydell 
14396f060a63SPeter Maydell     /*
14406f060a63SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
14416f060a63SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
14426f060a63SPeter Maydell      * beat must start with the current value of Rda, not zero.
14436f060a63SPeter Maydell      */
14446f060a63SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
14456f060a63SPeter Maydell         /* Accumulate input from Rda */
14466f060a63SPeter Maydell         rda = load_reg(s, a->rda);
14476f060a63SPeter Maydell     } else {
14486f060a63SPeter Maydell         /* Accumulate starting at zero */
14496f060a63SPeter Maydell         rda = tcg_const_i32(0);
14506f060a63SPeter Maydell     }
14516f060a63SPeter Maydell 
14526f060a63SPeter Maydell     qm = mve_qreg_ptr(a->qm);
14536f060a63SPeter Maydell     fns[a->size][a->u](rda, cpu_env, qm, rda);
14546f060a63SPeter Maydell     store_reg(s, a->rda, rda);
14556f060a63SPeter Maydell     tcg_temp_free_ptr(qm);
14566f060a63SPeter Maydell 
14576f060a63SPeter Maydell     mve_update_eci(s);
14586f060a63SPeter Maydell     return true;
14596f060a63SPeter Maydell }
1460eab84139SPeter Maydell 
1461d43ebd9dSPeter Maydell static bool trans_VADDLV(DisasContext *s, arg_VADDLV *a)
1462d43ebd9dSPeter Maydell {
1463d43ebd9dSPeter Maydell     /*
1464d43ebd9dSPeter Maydell      * Vector Add Long Across Vector: accumulate the 32-bit
1465d43ebd9dSPeter Maydell      * elements of the vector into a 64-bit result stored in
1466d43ebd9dSPeter Maydell      * a pair of general-purpose registers.
1467d43ebd9dSPeter Maydell      * No need to check Qm's bank: it is only 3 bits in decode.
1468d43ebd9dSPeter Maydell      */
1469d43ebd9dSPeter Maydell     TCGv_ptr qm;
1470d43ebd9dSPeter Maydell     TCGv_i64 rda;
1471d43ebd9dSPeter Maydell     TCGv_i32 rdalo, rdahi;
1472d43ebd9dSPeter Maydell 
1473d43ebd9dSPeter Maydell     if (!dc_isar_feature(aa32_mve, s)) {
1474d43ebd9dSPeter Maydell         return false;
1475d43ebd9dSPeter Maydell     }
1476d43ebd9dSPeter Maydell     /*
1477d43ebd9dSPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
1478d43ebd9dSPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
1479d43ebd9dSPeter Maydell      */
1480d43ebd9dSPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
1481d43ebd9dSPeter Maydell         return false;
1482d43ebd9dSPeter Maydell     }
1483d43ebd9dSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1484d43ebd9dSPeter Maydell         return true;
1485d43ebd9dSPeter Maydell     }
1486d43ebd9dSPeter Maydell 
1487d43ebd9dSPeter Maydell     /*
1488d43ebd9dSPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
1489d43ebd9dSPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
1490d43ebd9dSPeter Maydell      * beat must start with the current value of RdaHi:RdaLo, not zero.
1491d43ebd9dSPeter Maydell      */
1492d43ebd9dSPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
1493d43ebd9dSPeter Maydell         /* Accumulate input from RdaHi:RdaLo */
1494d43ebd9dSPeter Maydell         rda = tcg_temp_new_i64();
1495d43ebd9dSPeter Maydell         rdalo = load_reg(s, a->rdalo);
1496d43ebd9dSPeter Maydell         rdahi = load_reg(s, a->rdahi);
1497d43ebd9dSPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
1498d43ebd9dSPeter Maydell         tcg_temp_free_i32(rdalo);
1499d43ebd9dSPeter Maydell         tcg_temp_free_i32(rdahi);
1500d43ebd9dSPeter Maydell     } else {
1501d43ebd9dSPeter Maydell         /* Accumulate starting at zero */
1502d43ebd9dSPeter Maydell         rda = tcg_const_i64(0);
1503d43ebd9dSPeter Maydell     }
1504d43ebd9dSPeter Maydell 
1505d43ebd9dSPeter Maydell     qm = mve_qreg_ptr(a->qm);
1506d43ebd9dSPeter Maydell     if (a->u) {
1507d43ebd9dSPeter Maydell         gen_helper_mve_vaddlv_u(rda, cpu_env, qm, rda);
1508d43ebd9dSPeter Maydell     } else {
1509d43ebd9dSPeter Maydell         gen_helper_mve_vaddlv_s(rda, cpu_env, qm, rda);
1510d43ebd9dSPeter Maydell     }
1511d43ebd9dSPeter Maydell     tcg_temp_free_ptr(qm);
1512d43ebd9dSPeter Maydell 
1513d43ebd9dSPeter Maydell     rdalo = tcg_temp_new_i32();
1514d43ebd9dSPeter Maydell     rdahi = tcg_temp_new_i32();
1515d43ebd9dSPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
1516d43ebd9dSPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
1517d43ebd9dSPeter Maydell     store_reg(s, a->rdalo, rdalo);
1518d43ebd9dSPeter Maydell     store_reg(s, a->rdahi, rdahi);
1519d43ebd9dSPeter Maydell     tcg_temp_free_i64(rda);
1520d43ebd9dSPeter Maydell     mve_update_eci(s);
1521d43ebd9dSPeter Maydell     return true;
1522d43ebd9dSPeter Maydell }
1523d43ebd9dSPeter Maydell 
1524eab84139SPeter Maydell static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
1525eab84139SPeter Maydell {
1526eab84139SPeter Maydell     TCGv_ptr qd;
1527eab84139SPeter Maydell     uint64_t imm;
1528eab84139SPeter Maydell 
1529eab84139SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
1530eab84139SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
1531eab84139SPeter Maydell         !fn) {
1532eab84139SPeter Maydell         return false;
1533eab84139SPeter Maydell     }
1534eab84139SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1535eab84139SPeter Maydell         return true;
1536eab84139SPeter Maydell     }
1537eab84139SPeter Maydell 
1538eab84139SPeter Maydell     imm = asimd_imm_const(a->imm, a->cmode, a->op);
1539eab84139SPeter Maydell 
1540eab84139SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1541eab84139SPeter Maydell     fn(cpu_env, qd, tcg_constant_i64(imm));
1542eab84139SPeter Maydell     tcg_temp_free_ptr(qd);
1543eab84139SPeter Maydell     mve_update_eci(s);
1544eab84139SPeter Maydell     return true;
1545eab84139SPeter Maydell }
1546eab84139SPeter Maydell 
1547eab84139SPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
1548eab84139SPeter Maydell {
1549eab84139SPeter Maydell     /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
1550eab84139SPeter Maydell     MVEGenOneOpImmFn *fn;
1551eab84139SPeter Maydell 
1552eab84139SPeter Maydell     if ((a->cmode & 1) && a->cmode < 12) {
1553eab84139SPeter Maydell         if (a->op) {
1554eab84139SPeter Maydell             /*
1555eab84139SPeter Maydell              * For op=1, the immediate will be inverted by asimd_imm_const(),
1556eab84139SPeter Maydell              * so the VBIC becomes a logical AND operation.
1557eab84139SPeter Maydell              */
1558eab84139SPeter Maydell             fn = gen_helper_mve_vandi;
1559eab84139SPeter Maydell         } else {
1560eab84139SPeter Maydell             fn = gen_helper_mve_vorri;
1561eab84139SPeter Maydell         }
1562eab84139SPeter Maydell     } else {
1563eab84139SPeter Maydell         /* There is one unallocated cmode/op combination in this space */
1564eab84139SPeter Maydell         if (a->cmode == 15 && a->op == 1) {
1565eab84139SPeter Maydell             return false;
1566eab84139SPeter Maydell         }
1567eab84139SPeter Maydell         /* asimd_imm_const() sorts out VMVNI vs VMOVI for us */
1568eab84139SPeter Maydell         fn = gen_helper_mve_vmovi;
1569eab84139SPeter Maydell     }
1570eab84139SPeter Maydell     return do_1imm(s, a, fn);
1571eab84139SPeter Maydell }
1572f9ed6174SPeter Maydell 
1573752970efSPeter Maydell static bool do_2shift_vec(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
1574752970efSPeter Maydell                           bool negateshift, GVecGen2iFn vecfn)
1575f9ed6174SPeter Maydell {
1576f9ed6174SPeter Maydell     TCGv_ptr qd, qm;
1577f9ed6174SPeter Maydell     int shift = a->shift;
1578f9ed6174SPeter Maydell 
1579f9ed6174SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
1580f9ed6174SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
1581f9ed6174SPeter Maydell         !fn) {
1582f9ed6174SPeter Maydell         return false;
1583f9ed6174SPeter Maydell     }
1584f9ed6174SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1585f9ed6174SPeter Maydell         return true;
1586f9ed6174SPeter Maydell     }
1587f9ed6174SPeter Maydell 
1588f9ed6174SPeter Maydell     /*
1589f9ed6174SPeter Maydell      * When we handle a right shift insn using a left-shift helper
1590f9ed6174SPeter Maydell      * which permits a negative shift count to indicate a right-shift,
1591f9ed6174SPeter Maydell      * we must negate the shift count.
1592f9ed6174SPeter Maydell      */
1593f9ed6174SPeter Maydell     if (negateshift) {
1594f9ed6174SPeter Maydell         shift = -shift;
1595f9ed6174SPeter Maydell     }
1596f9ed6174SPeter Maydell 
1597752970efSPeter Maydell     if (vecfn && mve_no_predication(s)) {
1598752970efSPeter Maydell         vecfn(a->size, mve_qreg_offset(a->qd), mve_qreg_offset(a->qm),
1599752970efSPeter Maydell               shift, 16, 16);
1600752970efSPeter Maydell     } else {
1601f9ed6174SPeter Maydell         qd = mve_qreg_ptr(a->qd);
1602f9ed6174SPeter Maydell         qm = mve_qreg_ptr(a->qm);
1603f9ed6174SPeter Maydell         fn(cpu_env, qd, qm, tcg_constant_i32(shift));
1604f9ed6174SPeter Maydell         tcg_temp_free_ptr(qd);
1605f9ed6174SPeter Maydell         tcg_temp_free_ptr(qm);
1606752970efSPeter Maydell     }
1607f9ed6174SPeter Maydell     mve_update_eci(s);
1608f9ed6174SPeter Maydell     return true;
1609f9ed6174SPeter Maydell }
1610f9ed6174SPeter Maydell 
1611752970efSPeter Maydell static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
1612752970efSPeter Maydell                       bool negateshift)
1613752970efSPeter Maydell {
1614752970efSPeter Maydell     return do_2shift_vec(s, a, fn, negateshift, NULL);
1615752970efSPeter Maydell }
1616752970efSPeter Maydell 
1617752970efSPeter Maydell #define DO_2SHIFT_VEC(INSN, FN, NEGATESHIFT, VECFN)                     \
1618f9ed6174SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)            \
1619f9ed6174SPeter Maydell     {                                                                   \
1620f9ed6174SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {                     \
1621f9ed6174SPeter Maydell             gen_helper_mve_##FN##b,                                     \
1622f9ed6174SPeter Maydell             gen_helper_mve_##FN##h,                                     \
1623f9ed6174SPeter Maydell             gen_helper_mve_##FN##w,                                     \
1624f9ed6174SPeter Maydell             NULL,                                                       \
1625f9ed6174SPeter Maydell         };                                                              \
1626752970efSPeter Maydell         return do_2shift_vec(s, a, fns[a->size], NEGATESHIFT, VECFN);   \
1627f9ed6174SPeter Maydell     }
1628f9ed6174SPeter Maydell 
1629752970efSPeter Maydell #define DO_2SHIFT(INSN, FN, NEGATESHIFT)        \
1630752970efSPeter Maydell     DO_2SHIFT_VEC(INSN, FN, NEGATESHIFT, NULL)
1631752970efSPeter Maydell 
1632752970efSPeter Maydell static void do_gvec_shri_s(unsigned vece, uint32_t dofs, uint32_t aofs,
1633752970efSPeter Maydell                            int64_t shift, uint32_t oprsz, uint32_t maxsz)
1634752970efSPeter Maydell {
1635752970efSPeter Maydell     /*
1636752970efSPeter Maydell      * We get here with a negated shift count, and we must handle
1637752970efSPeter Maydell      * shifts by the element size, which tcg_gen_gvec_sari() does not do.
1638752970efSPeter Maydell      */
1639752970efSPeter Maydell     shift = -shift;
1640752970efSPeter Maydell     if (shift == (8 << vece)) {
1641752970efSPeter Maydell         shift--;
1642752970efSPeter Maydell     }
1643752970efSPeter Maydell     tcg_gen_gvec_sari(vece, dofs, aofs, shift, oprsz, maxsz);
1644752970efSPeter Maydell }
1645752970efSPeter Maydell 
1646752970efSPeter Maydell static void do_gvec_shri_u(unsigned vece, uint32_t dofs, uint32_t aofs,
1647752970efSPeter Maydell                            int64_t shift, uint32_t oprsz, uint32_t maxsz)
1648752970efSPeter Maydell {
1649752970efSPeter Maydell     /*
1650752970efSPeter Maydell      * We get here with a negated shift count, and we must handle
1651752970efSPeter Maydell      * shifts by the element size, which tcg_gen_gvec_shri() does not do.
1652752970efSPeter Maydell      */
1653752970efSPeter Maydell     shift = -shift;
1654752970efSPeter Maydell     if (shift == (8 << vece)) {
1655752970efSPeter Maydell         tcg_gen_gvec_dup_imm(vece, dofs, oprsz, maxsz, 0);
1656752970efSPeter Maydell     } else {
1657752970efSPeter Maydell         tcg_gen_gvec_shri(vece, dofs, aofs, shift, oprsz, maxsz);
1658752970efSPeter Maydell     }
1659752970efSPeter Maydell }
1660752970efSPeter Maydell 
1661752970efSPeter Maydell DO_2SHIFT_VEC(VSHLI, vshli_u, false, tcg_gen_gvec_shli)
1662f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_S, vqshli_s, false)
1663f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_U, vqshli_u, false)
1664f9ed6174SPeter Maydell DO_2SHIFT(VQSHLUI, vqshlui_s, false)
16653394116fSPeter Maydell /* These right shifts use a left-shift helper with negated shift count */
1666752970efSPeter Maydell DO_2SHIFT_VEC(VSHRI_S, vshli_s, true, do_gvec_shri_s)
1667752970efSPeter Maydell DO_2SHIFT_VEC(VSHRI_U, vshli_u, true, do_gvec_shri_u)
16683394116fSPeter Maydell DO_2SHIFT(VRSHRI_S, vrshli_s, true)
16693394116fSPeter Maydell DO_2SHIFT(VRSHRI_U, vrshli_u, true)
1670c2262707SPeter Maydell 
1671*ce75c43fSPeter Maydell DO_2SHIFT_VEC(VSRI, vsri, false, gen_gvec_sri)
1672*ce75c43fSPeter Maydell DO_2SHIFT_VEC(VSLI, vsli, false, gen_gvec_sli)
1673a78b25faSPeter Maydell 
16742a4b939cSPeter Maydell #define DO_2SHIFT_FP(INSN, FN)                                  \
16752a4b939cSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
16762a4b939cSPeter Maydell     {                                                           \
16772a4b939cSPeter Maydell         if (!dc_isar_feature(aa32_mve_fp, s)) {                 \
16782a4b939cSPeter Maydell             return false;                                       \
16792a4b939cSPeter Maydell         }                                                       \
16802a4b939cSPeter Maydell         return do_2shift(s, a, gen_helper_mve_##FN, false);     \
16812a4b939cSPeter Maydell     }
16822a4b939cSPeter Maydell 
16832a4b939cSPeter Maydell DO_2SHIFT_FP(VCVT_SH_fixed, vcvt_sh)
16842a4b939cSPeter Maydell DO_2SHIFT_FP(VCVT_UH_fixed, vcvt_uh)
16852a4b939cSPeter Maydell DO_2SHIFT_FP(VCVT_HS_fixed, vcvt_hs)
16862a4b939cSPeter Maydell DO_2SHIFT_FP(VCVT_HU_fixed, vcvt_hu)
16872a4b939cSPeter Maydell DO_2SHIFT_FP(VCVT_SF_fixed, vcvt_sf)
16882a4b939cSPeter Maydell DO_2SHIFT_FP(VCVT_UF_fixed, vcvt_uf)
16892a4b939cSPeter Maydell DO_2SHIFT_FP(VCVT_FS_fixed, vcvt_fs)
16902a4b939cSPeter Maydell DO_2SHIFT_FP(VCVT_FU_fixed, vcvt_fu)
16912a4b939cSPeter Maydell 
16921b15a97dSPeter Maydell static bool do_2shift_scalar(DisasContext *s, arg_shl_scalar *a,
16931b15a97dSPeter Maydell                              MVEGenTwoOpShiftFn *fn)
16941b15a97dSPeter Maydell {
16951b15a97dSPeter Maydell     TCGv_ptr qda;
16961b15a97dSPeter Maydell     TCGv_i32 rm;
16971b15a97dSPeter Maydell 
16981b15a97dSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
16991b15a97dSPeter Maydell         !mve_check_qreg_bank(s, a->qda) ||
17001b15a97dSPeter Maydell         a->rm == 13 || a->rm == 15 || !fn) {
17011b15a97dSPeter Maydell         /* Rm cases are UNPREDICTABLE */
17021b15a97dSPeter Maydell         return false;
17031b15a97dSPeter Maydell     }
17041b15a97dSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
17051b15a97dSPeter Maydell         return true;
17061b15a97dSPeter Maydell     }
17071b15a97dSPeter Maydell 
17081b15a97dSPeter Maydell     qda = mve_qreg_ptr(a->qda);
17091b15a97dSPeter Maydell     rm = load_reg(s, a->rm);
17101b15a97dSPeter Maydell     fn(cpu_env, qda, qda, rm);
17111b15a97dSPeter Maydell     tcg_temp_free_ptr(qda);
17121b15a97dSPeter Maydell     tcg_temp_free_i32(rm);
17131b15a97dSPeter Maydell     mve_update_eci(s);
17141b15a97dSPeter Maydell     return true;
17151b15a97dSPeter Maydell }
17161b15a97dSPeter Maydell 
17171b15a97dSPeter Maydell #define DO_2SHIFT_SCALAR(INSN, FN)                                      \
17181b15a97dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_shl_scalar *a)        \
17191b15a97dSPeter Maydell     {                                                                   \
17201b15a97dSPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {                     \
17211b15a97dSPeter Maydell             gen_helper_mve_##FN##b,                                     \
17221b15a97dSPeter Maydell             gen_helper_mve_##FN##h,                                     \
17231b15a97dSPeter Maydell             gen_helper_mve_##FN##w,                                     \
17241b15a97dSPeter Maydell             NULL,                                                       \
17251b15a97dSPeter Maydell         };                                                              \
17261b15a97dSPeter Maydell         return do_2shift_scalar(s, a, fns[a->size]);                    \
17271b15a97dSPeter Maydell     }
17281b15a97dSPeter Maydell 
17291b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VSHL_S_scalar, vshli_s)
17301b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VSHL_U_scalar, vshli_u)
17311b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VRSHL_S_scalar, vrshli_s)
17321b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VRSHL_U_scalar, vrshli_u)
17331b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQSHL_S_scalar, vqshli_s)
17341b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQSHL_U_scalar, vqshli_u)
17351b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQRSHL_S_scalar, vqrshli_s)
17361b15a97dSPeter Maydell DO_2SHIFT_SCALAR(VQRSHL_U_scalar, vqrshli_u)
17371b15a97dSPeter Maydell 
1738c2262707SPeter Maydell #define DO_VSHLL(INSN, FN)                                              \
1739c2262707SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)            \
1740c2262707SPeter Maydell     {                                                                   \
1741c2262707SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {                     \
1742c2262707SPeter Maydell             gen_helper_mve_##FN##b,                                     \
1743c2262707SPeter Maydell             gen_helper_mve_##FN##h,                                     \
1744c2262707SPeter Maydell         };                                                              \
1745a7789fabSPeter Maydell         return do_2shift_vec(s, a, fns[a->size], false, do_gvec_##FN);  \
1746a7789fabSPeter Maydell     }
1747a7789fabSPeter Maydell 
1748a7789fabSPeter Maydell /*
1749a7789fabSPeter Maydell  * For the VSHLL vector helpers, the vece is the size of the input
1750a7789fabSPeter Maydell  * (ie MO_8 or MO_16); the helpers want to work in the output size.
1751a7789fabSPeter Maydell  * The shift count can be 0..<input size>, inclusive. (0 is VMOVL.)
1752a7789fabSPeter Maydell  */
1753a7789fabSPeter Maydell static void do_gvec_vshllbs(unsigned vece, uint32_t dofs, uint32_t aofs,
1754a7789fabSPeter Maydell                             int64_t shift, uint32_t oprsz, uint32_t maxsz)
1755a7789fabSPeter Maydell {
1756a7789fabSPeter Maydell     unsigned ovece = vece + 1;
1757a7789fabSPeter Maydell     unsigned ibits = vece == MO_8 ? 8 : 16;
1758a7789fabSPeter Maydell     tcg_gen_gvec_shli(ovece, dofs, aofs, ibits, oprsz, maxsz);
1759a7789fabSPeter Maydell     tcg_gen_gvec_sari(ovece, dofs, dofs, ibits - shift, oprsz, maxsz);
1760a7789fabSPeter Maydell }
1761a7789fabSPeter Maydell 
1762a7789fabSPeter Maydell static void do_gvec_vshllbu(unsigned vece, uint32_t dofs, uint32_t aofs,
1763a7789fabSPeter Maydell                             int64_t shift, uint32_t oprsz, uint32_t maxsz)
1764a7789fabSPeter Maydell {
1765a7789fabSPeter Maydell     unsigned ovece = vece + 1;
1766a7789fabSPeter Maydell     tcg_gen_gvec_andi(ovece, dofs, aofs,
1767a7789fabSPeter Maydell                       ovece == MO_16 ? 0xff : 0xffff, oprsz, maxsz);
1768a7789fabSPeter Maydell     tcg_gen_gvec_shli(ovece, dofs, dofs, shift, oprsz, maxsz);
1769a7789fabSPeter Maydell }
1770a7789fabSPeter Maydell 
1771a7789fabSPeter Maydell static void do_gvec_vshllts(unsigned vece, uint32_t dofs, uint32_t aofs,
1772a7789fabSPeter Maydell                             int64_t shift, uint32_t oprsz, uint32_t maxsz)
1773a7789fabSPeter Maydell {
1774a7789fabSPeter Maydell     unsigned ovece = vece + 1;
1775a7789fabSPeter Maydell     unsigned ibits = vece == MO_8 ? 8 : 16;
1776a7789fabSPeter Maydell     if (shift == 0) {
1777a7789fabSPeter Maydell         tcg_gen_gvec_sari(ovece, dofs, aofs, ibits, oprsz, maxsz);
1778a7789fabSPeter Maydell     } else {
1779a7789fabSPeter Maydell         tcg_gen_gvec_andi(ovece, dofs, aofs,
1780a7789fabSPeter Maydell                           ovece == MO_16 ? 0xff00 : 0xffff0000, oprsz, maxsz);
1781a7789fabSPeter Maydell         tcg_gen_gvec_sari(ovece, dofs, dofs, ibits - shift, oprsz, maxsz);
1782a7789fabSPeter Maydell     }
1783a7789fabSPeter Maydell }
1784a7789fabSPeter Maydell 
1785a7789fabSPeter Maydell static void do_gvec_vshlltu(unsigned vece, uint32_t dofs, uint32_t aofs,
1786a7789fabSPeter Maydell                             int64_t shift, uint32_t oprsz, uint32_t maxsz)
1787a7789fabSPeter Maydell {
1788a7789fabSPeter Maydell     unsigned ovece = vece + 1;
1789a7789fabSPeter Maydell     unsigned ibits = vece == MO_8 ? 8 : 16;
1790a7789fabSPeter Maydell     if (shift == 0) {
1791a7789fabSPeter Maydell         tcg_gen_gvec_shri(ovece, dofs, aofs, ibits, oprsz, maxsz);
1792a7789fabSPeter Maydell     } else {
1793a7789fabSPeter Maydell         tcg_gen_gvec_andi(ovece, dofs, aofs,
1794a7789fabSPeter Maydell                           ovece == MO_16 ? 0xff00 : 0xffff0000, oprsz, maxsz);
1795a7789fabSPeter Maydell         tcg_gen_gvec_shri(ovece, dofs, dofs, ibits - shift, oprsz, maxsz);
1796a7789fabSPeter Maydell     }
1797c2262707SPeter Maydell }
1798c2262707SPeter Maydell 
1799c2262707SPeter Maydell DO_VSHLL(VSHLL_BS, vshllbs)
1800c2262707SPeter Maydell DO_VSHLL(VSHLL_BU, vshllbu)
1801c2262707SPeter Maydell DO_VSHLL(VSHLL_TS, vshllts)
1802c2262707SPeter Maydell DO_VSHLL(VSHLL_TU, vshlltu)
1803162e2655SPeter Maydell 
1804162e2655SPeter Maydell #define DO_2SHIFT_N(INSN, FN)                                   \
1805162e2655SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2shift *a)    \
1806162e2655SPeter Maydell     {                                                           \
1807162e2655SPeter Maydell         static MVEGenTwoOpShiftFn * const fns[] = {             \
1808162e2655SPeter Maydell             gen_helper_mve_##FN##b,                             \
1809162e2655SPeter Maydell             gen_helper_mve_##FN##h,                             \
1810162e2655SPeter Maydell         };                                                      \
1811162e2655SPeter Maydell         return do_2shift(s, a, fns[a->size], false);            \
1812162e2655SPeter Maydell     }
1813162e2655SPeter Maydell 
1814162e2655SPeter Maydell DO_2SHIFT_N(VSHRNB, vshrnb)
1815162e2655SPeter Maydell DO_2SHIFT_N(VSHRNT, vshrnt)
1816162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNB, vrshrnb)
1817162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNT, vrshrnt)
1818d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_S, vqshrnb_s)
1819d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_S, vqshrnt_s)
1820d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_U, vqshrnb_u)
1821d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_U, vqshrnt_u)
1822d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNB, vqshrunb)
1823d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNT, vqshrunt)
1824d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_S, vqrshrnb_s)
1825d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_S, vqrshrnt_s)
1826d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_U, vqrshrnb_u)
1827d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_U, vqrshrnt_u)
1828d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNB, vqrshrunb)
1829d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNT, vqrshrunt)
18302e6a4ce0SPeter Maydell 
18312e6a4ce0SPeter Maydell static bool trans_VSHLC(DisasContext *s, arg_VSHLC *a)
18322e6a4ce0SPeter Maydell {
18332e6a4ce0SPeter Maydell     /*
18342e6a4ce0SPeter Maydell      * Whole Vector Left Shift with Carry. The carry is taken
18352e6a4ce0SPeter Maydell      * from a general purpose register and written back there.
18362e6a4ce0SPeter Maydell      * An imm of 0 means "shift by 32".
18372e6a4ce0SPeter Maydell      */
18382e6a4ce0SPeter Maydell     TCGv_ptr qd;
18392e6a4ce0SPeter Maydell     TCGv_i32 rdm;
18402e6a4ce0SPeter Maydell 
18412e6a4ce0SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
18422e6a4ce0SPeter Maydell         return false;
18432e6a4ce0SPeter Maydell     }
18442e6a4ce0SPeter Maydell     if (a->rdm == 13 || a->rdm == 15) {
18452e6a4ce0SPeter Maydell         /* CONSTRAINED UNPREDICTABLE: we UNDEF */
18462e6a4ce0SPeter Maydell         return false;
18472e6a4ce0SPeter Maydell     }
18482e6a4ce0SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
18492e6a4ce0SPeter Maydell         return true;
18502e6a4ce0SPeter Maydell     }
18512e6a4ce0SPeter Maydell 
18522e6a4ce0SPeter Maydell     qd = mve_qreg_ptr(a->qd);
18532e6a4ce0SPeter Maydell     rdm = load_reg(s, a->rdm);
18542e6a4ce0SPeter Maydell     gen_helper_mve_vshlc(rdm, cpu_env, qd, rdm, tcg_constant_i32(a->imm));
18552e6a4ce0SPeter Maydell     store_reg(s, a->rdm, rdm);
18562e6a4ce0SPeter Maydell     tcg_temp_free_ptr(qd);
18572e6a4ce0SPeter Maydell     mve_update_eci(s);
18582e6a4ce0SPeter Maydell     return true;
18592e6a4ce0SPeter Maydell }
1860395b92d5SPeter Maydell 
1861395b92d5SPeter Maydell static bool do_vidup(DisasContext *s, arg_vidup *a, MVEGenVIDUPFn *fn)
1862395b92d5SPeter Maydell {
1863395b92d5SPeter Maydell     TCGv_ptr qd;
1864395b92d5SPeter Maydell     TCGv_i32 rn;
1865395b92d5SPeter Maydell 
1866395b92d5SPeter Maydell     /*
1867395b92d5SPeter Maydell      * Vector increment/decrement with wrap and duplicate (VIDUP, VDDUP).
1868395b92d5SPeter Maydell      * This fills the vector with elements of successively increasing
1869395b92d5SPeter Maydell      * or decreasing values, starting from Rn.
1870395b92d5SPeter Maydell      */
1871395b92d5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
1872395b92d5SPeter Maydell         return false;
1873395b92d5SPeter Maydell     }
1874395b92d5SPeter Maydell     if (a->size == MO_64) {
1875395b92d5SPeter Maydell         /* size 0b11 is another encoding */
1876395b92d5SPeter Maydell         return false;
1877395b92d5SPeter Maydell     }
1878395b92d5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1879395b92d5SPeter Maydell         return true;
1880395b92d5SPeter Maydell     }
1881395b92d5SPeter Maydell 
1882395b92d5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1883395b92d5SPeter Maydell     rn = load_reg(s, a->rn);
1884395b92d5SPeter Maydell     fn(rn, cpu_env, qd, rn, tcg_constant_i32(a->imm));
1885395b92d5SPeter Maydell     store_reg(s, a->rn, rn);
1886395b92d5SPeter Maydell     tcg_temp_free_ptr(qd);
1887395b92d5SPeter Maydell     mve_update_eci(s);
1888395b92d5SPeter Maydell     return true;
1889395b92d5SPeter Maydell }
1890395b92d5SPeter Maydell 
1891395b92d5SPeter Maydell static bool do_viwdup(DisasContext *s, arg_viwdup *a, MVEGenVIWDUPFn *fn)
1892395b92d5SPeter Maydell {
1893395b92d5SPeter Maydell     TCGv_ptr qd;
1894395b92d5SPeter Maydell     TCGv_i32 rn, rm;
1895395b92d5SPeter Maydell 
1896395b92d5SPeter Maydell     /*
1897395b92d5SPeter Maydell      * Vector increment/decrement with wrap and duplicate (VIWDUp, VDWDUP)
1898395b92d5SPeter Maydell      * This fills the vector with elements of successively increasing
1899395b92d5SPeter Maydell      * or decreasing values, starting from Rn. Rm specifies a point where
1900395b92d5SPeter Maydell      * the count wraps back around to 0. The updated offset is written back
1901395b92d5SPeter Maydell      * to Rn.
1902395b92d5SPeter Maydell      */
1903395b92d5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) {
1904395b92d5SPeter Maydell         return false;
1905395b92d5SPeter Maydell     }
1906395b92d5SPeter Maydell     if (!fn || a->rm == 13 || a->rm == 15) {
1907395b92d5SPeter Maydell         /*
1908395b92d5SPeter Maydell          * size 0b11 is another encoding; Rm == 13 is UNPREDICTABLE;
1909395b92d5SPeter Maydell          * Rm == 13 is VIWDUP, VDWDUP.
1910395b92d5SPeter Maydell          */
1911395b92d5SPeter Maydell         return false;
1912395b92d5SPeter Maydell     }
1913395b92d5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1914395b92d5SPeter Maydell         return true;
1915395b92d5SPeter Maydell     }
1916395b92d5SPeter Maydell 
1917395b92d5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
1918395b92d5SPeter Maydell     rn = load_reg(s, a->rn);
1919395b92d5SPeter Maydell     rm = load_reg(s, a->rm);
1920395b92d5SPeter Maydell     fn(rn, cpu_env, qd, rn, rm, tcg_constant_i32(a->imm));
1921395b92d5SPeter Maydell     store_reg(s, a->rn, rn);
1922395b92d5SPeter Maydell     tcg_temp_free_ptr(qd);
1923395b92d5SPeter Maydell     tcg_temp_free_i32(rm);
1924395b92d5SPeter Maydell     mve_update_eci(s);
1925395b92d5SPeter Maydell     return true;
1926395b92d5SPeter Maydell }
1927395b92d5SPeter Maydell 
1928395b92d5SPeter Maydell static bool trans_VIDUP(DisasContext *s, arg_vidup *a)
1929395b92d5SPeter Maydell {
1930395b92d5SPeter Maydell     static MVEGenVIDUPFn * const fns[] = {
1931395b92d5SPeter Maydell         gen_helper_mve_vidupb,
1932395b92d5SPeter Maydell         gen_helper_mve_viduph,
1933395b92d5SPeter Maydell         gen_helper_mve_vidupw,
1934395b92d5SPeter Maydell         NULL,
1935395b92d5SPeter Maydell     };
1936395b92d5SPeter Maydell     return do_vidup(s, a, fns[a->size]);
1937395b92d5SPeter Maydell }
1938395b92d5SPeter Maydell 
1939395b92d5SPeter Maydell static bool trans_VDDUP(DisasContext *s, arg_vidup *a)
1940395b92d5SPeter Maydell {
1941395b92d5SPeter Maydell     static MVEGenVIDUPFn * const fns[] = {
1942395b92d5SPeter Maydell         gen_helper_mve_vidupb,
1943395b92d5SPeter Maydell         gen_helper_mve_viduph,
1944395b92d5SPeter Maydell         gen_helper_mve_vidupw,
1945395b92d5SPeter Maydell         NULL,
1946395b92d5SPeter Maydell     };
1947395b92d5SPeter Maydell     /* VDDUP is just like VIDUP but with a negative immediate */
1948395b92d5SPeter Maydell     a->imm = -a->imm;
1949395b92d5SPeter Maydell     return do_vidup(s, a, fns[a->size]);
1950395b92d5SPeter Maydell }
1951395b92d5SPeter Maydell 
1952395b92d5SPeter Maydell static bool trans_VIWDUP(DisasContext *s, arg_viwdup *a)
1953395b92d5SPeter Maydell {
1954395b92d5SPeter Maydell     static MVEGenVIWDUPFn * const fns[] = {
1955395b92d5SPeter Maydell         gen_helper_mve_viwdupb,
1956395b92d5SPeter Maydell         gen_helper_mve_viwduph,
1957395b92d5SPeter Maydell         gen_helper_mve_viwdupw,
1958395b92d5SPeter Maydell         NULL,
1959395b92d5SPeter Maydell     };
1960395b92d5SPeter Maydell     return do_viwdup(s, a, fns[a->size]);
1961395b92d5SPeter Maydell }
1962395b92d5SPeter Maydell 
1963395b92d5SPeter Maydell static bool trans_VDWDUP(DisasContext *s, arg_viwdup *a)
1964395b92d5SPeter Maydell {
1965395b92d5SPeter Maydell     static MVEGenVIWDUPFn * const fns[] = {
1966395b92d5SPeter Maydell         gen_helper_mve_vdwdupb,
1967395b92d5SPeter Maydell         gen_helper_mve_vdwduph,
1968395b92d5SPeter Maydell         gen_helper_mve_vdwdupw,
1969395b92d5SPeter Maydell         NULL,
1970395b92d5SPeter Maydell     };
1971395b92d5SPeter Maydell     return do_viwdup(s, a, fns[a->size]);
1972395b92d5SPeter Maydell }
1973eff5d9a9SPeter Maydell 
1974eff5d9a9SPeter Maydell static bool do_vcmp(DisasContext *s, arg_vcmp *a, MVEGenCmpFn *fn)
1975eff5d9a9SPeter Maydell {
1976eff5d9a9SPeter Maydell     TCGv_ptr qn, qm;
1977eff5d9a9SPeter Maydell 
1978eff5d9a9SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qm) ||
1979eff5d9a9SPeter Maydell         !fn) {
1980eff5d9a9SPeter Maydell         return false;
1981eff5d9a9SPeter Maydell     }
1982eff5d9a9SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
1983eff5d9a9SPeter Maydell         return true;
1984eff5d9a9SPeter Maydell     }
1985eff5d9a9SPeter Maydell 
1986eff5d9a9SPeter Maydell     qn = mve_qreg_ptr(a->qn);
1987eff5d9a9SPeter Maydell     qm = mve_qreg_ptr(a->qm);
1988eff5d9a9SPeter Maydell     fn(cpu_env, qn, qm);
1989eff5d9a9SPeter Maydell     tcg_temp_free_ptr(qn);
1990eff5d9a9SPeter Maydell     tcg_temp_free_ptr(qm);
1991eff5d9a9SPeter Maydell     if (a->mask) {
1992eff5d9a9SPeter Maydell         /* VPT */
1993eff5d9a9SPeter Maydell         gen_vpst(s, a->mask);
1994eff5d9a9SPeter Maydell     }
199526702213SPeter Maydell     /* This insn updates predication bits */
199626702213SPeter Maydell     s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
1997eff5d9a9SPeter Maydell     mve_update_eci(s);
1998eff5d9a9SPeter Maydell     return true;
1999eff5d9a9SPeter Maydell }
2000eff5d9a9SPeter Maydell 
2001cce81873SPeter Maydell static bool do_vcmp_scalar(DisasContext *s, arg_vcmp_scalar *a,
2002cce81873SPeter Maydell                            MVEGenScalarCmpFn *fn)
2003cce81873SPeter Maydell {
2004cce81873SPeter Maydell     TCGv_ptr qn;
2005cce81873SPeter Maydell     TCGv_i32 rm;
2006cce81873SPeter Maydell 
2007cce81873SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !fn || a->rm == 13) {
2008cce81873SPeter Maydell         return false;
2009cce81873SPeter Maydell     }
2010cce81873SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
2011cce81873SPeter Maydell         return true;
2012cce81873SPeter Maydell     }
2013cce81873SPeter Maydell 
2014cce81873SPeter Maydell     qn = mve_qreg_ptr(a->qn);
2015cce81873SPeter Maydell     if (a->rm == 15) {
2016cce81873SPeter Maydell         /* Encoding Rm=0b1111 means "constant zero" */
2017cce81873SPeter Maydell         rm = tcg_constant_i32(0);
2018cce81873SPeter Maydell     } else {
2019cce81873SPeter Maydell         rm = load_reg(s, a->rm);
2020cce81873SPeter Maydell     }
2021cce81873SPeter Maydell     fn(cpu_env, qn, rm);
2022cce81873SPeter Maydell     tcg_temp_free_ptr(qn);
2023cce81873SPeter Maydell     tcg_temp_free_i32(rm);
2024cce81873SPeter Maydell     if (a->mask) {
2025cce81873SPeter Maydell         /* VPT */
2026cce81873SPeter Maydell         gen_vpst(s, a->mask);
2027cce81873SPeter Maydell     }
202826702213SPeter Maydell     /* This insn updates predication bits */
202926702213SPeter Maydell     s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
2030cce81873SPeter Maydell     mve_update_eci(s);
2031cce81873SPeter Maydell     return true;
2032cce81873SPeter Maydell }
2033cce81873SPeter Maydell 
2034eff5d9a9SPeter Maydell #define DO_VCMP(INSN, FN)                                       \
2035eff5d9a9SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vcmp *a)      \
2036eff5d9a9SPeter Maydell     {                                                           \
2037eff5d9a9SPeter Maydell         static MVEGenCmpFn * const fns[] = {                    \
2038eff5d9a9SPeter Maydell             gen_helper_mve_##FN##b,                             \
2039eff5d9a9SPeter Maydell             gen_helper_mve_##FN##h,                             \
2040eff5d9a9SPeter Maydell             gen_helper_mve_##FN##w,                             \
2041eff5d9a9SPeter Maydell             NULL,                                               \
2042eff5d9a9SPeter Maydell         };                                                      \
2043eff5d9a9SPeter Maydell         return do_vcmp(s, a, fns[a->size]);                     \
2044cce81873SPeter Maydell     }                                                           \
2045cce81873SPeter Maydell     static bool trans_##INSN##_scalar(DisasContext *s,          \
2046cce81873SPeter Maydell                                       arg_vcmp_scalar *a)       \
2047cce81873SPeter Maydell     {                                                           \
2048cce81873SPeter Maydell         static MVEGenScalarCmpFn * const fns[] = {              \
2049cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarb,                      \
2050cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarh,                      \
2051cce81873SPeter Maydell             gen_helper_mve_##FN##_scalarw,                      \
2052cce81873SPeter Maydell             NULL,                                               \
2053cce81873SPeter Maydell         };                                                      \
2054cce81873SPeter Maydell         return do_vcmp_scalar(s, a, fns[a->size]);              \
2055eff5d9a9SPeter Maydell     }
2056eff5d9a9SPeter Maydell 
2057eff5d9a9SPeter Maydell DO_VCMP(VCMPEQ, vcmpeq)
2058eff5d9a9SPeter Maydell DO_VCMP(VCMPNE, vcmpne)
2059eff5d9a9SPeter Maydell DO_VCMP(VCMPCS, vcmpcs)
2060eff5d9a9SPeter Maydell DO_VCMP(VCMPHI, vcmphi)
2061eff5d9a9SPeter Maydell DO_VCMP(VCMPGE, vcmpge)
2062eff5d9a9SPeter Maydell DO_VCMP(VCMPLT, vcmplt)
2063eff5d9a9SPeter Maydell DO_VCMP(VCMPGT, vcmpgt)
2064eff5d9a9SPeter Maydell DO_VCMP(VCMPLE, vcmple)
2065688ba4cfSPeter Maydell 
2066c87fe6d2SPeter Maydell #define DO_VCMP_FP(INSN, FN)                                    \
2067c87fe6d2SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vcmp *a)      \
2068c87fe6d2SPeter Maydell     {                                                           \
2069c87fe6d2SPeter Maydell         static MVEGenCmpFn * const fns[] = {                    \
2070c87fe6d2SPeter Maydell             NULL,                                               \
2071c87fe6d2SPeter Maydell             gen_helper_mve_##FN##h,                             \
2072c87fe6d2SPeter Maydell             gen_helper_mve_##FN##s,                             \
2073c87fe6d2SPeter Maydell             NULL,                                               \
2074c87fe6d2SPeter Maydell         };                                                      \
2075c87fe6d2SPeter Maydell         if (!dc_isar_feature(aa32_mve_fp, s)) {                 \
2076c87fe6d2SPeter Maydell             return false;                                       \
2077c87fe6d2SPeter Maydell         }                                                       \
2078c87fe6d2SPeter Maydell         return do_vcmp(s, a, fns[a->size]);                     \
2079c2d8f6bbSPeter Maydell     }                                                           \
2080c2d8f6bbSPeter Maydell     static bool trans_##INSN##_scalar(DisasContext *s,          \
2081c2d8f6bbSPeter Maydell                                       arg_vcmp_scalar *a)       \
2082c2d8f6bbSPeter Maydell     {                                                           \
2083c2d8f6bbSPeter Maydell         static MVEGenScalarCmpFn * const fns[] = {              \
2084c2d8f6bbSPeter Maydell             NULL,                                               \
2085c2d8f6bbSPeter Maydell             gen_helper_mve_##FN##_scalarh,                      \
2086c2d8f6bbSPeter Maydell             gen_helper_mve_##FN##_scalars,                      \
2087c2d8f6bbSPeter Maydell             NULL,                                               \
2088c2d8f6bbSPeter Maydell         };                                                      \
2089c2d8f6bbSPeter Maydell         if (!dc_isar_feature(aa32_mve_fp, s)) {                 \
2090c2d8f6bbSPeter Maydell             return false;                                       \
2091c2d8f6bbSPeter Maydell         }                                                       \
2092c2d8f6bbSPeter Maydell         return do_vcmp_scalar(s, a, fns[a->size]);              \
2093c87fe6d2SPeter Maydell     }
2094c87fe6d2SPeter Maydell 
2095c87fe6d2SPeter Maydell DO_VCMP_FP(VCMPEQ_fp, vfcmpeq)
2096c87fe6d2SPeter Maydell DO_VCMP_FP(VCMPNE_fp, vfcmpne)
2097c87fe6d2SPeter Maydell DO_VCMP_FP(VCMPGE_fp, vfcmpge)
2098c87fe6d2SPeter Maydell DO_VCMP_FP(VCMPLT_fp, vfcmplt)
2099c87fe6d2SPeter Maydell DO_VCMP_FP(VCMPGT_fp, vfcmpgt)
2100c87fe6d2SPeter Maydell DO_VCMP_FP(VCMPLE_fp, vfcmple)
2101c87fe6d2SPeter Maydell 
2102688ba4cfSPeter Maydell static bool do_vmaxv(DisasContext *s, arg_vmaxv *a, MVEGenVADDVFn fn)
2103688ba4cfSPeter Maydell {
2104688ba4cfSPeter Maydell     /*
2105688ba4cfSPeter Maydell      * MIN/MAX operations across a vector: compute the min or
2106688ba4cfSPeter Maydell      * max of the initial value in a general purpose register
2107688ba4cfSPeter Maydell      * and all the elements in the vector, and store it back
2108688ba4cfSPeter Maydell      * into the general purpose register.
2109688ba4cfSPeter Maydell      */
2110688ba4cfSPeter Maydell     TCGv_ptr qm;
2111688ba4cfSPeter Maydell     TCGv_i32 rda;
2112688ba4cfSPeter Maydell 
2113688ba4cfSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qm) ||
2114688ba4cfSPeter Maydell         !fn || a->rda == 13 || a->rda == 15) {
2115688ba4cfSPeter Maydell         /* Rda cases are UNPREDICTABLE */
2116688ba4cfSPeter Maydell         return false;
2117688ba4cfSPeter Maydell     }
2118688ba4cfSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
2119688ba4cfSPeter Maydell         return true;
2120688ba4cfSPeter Maydell     }
2121688ba4cfSPeter Maydell 
2122688ba4cfSPeter Maydell     qm = mve_qreg_ptr(a->qm);
2123688ba4cfSPeter Maydell     rda = load_reg(s, a->rda);
2124688ba4cfSPeter Maydell     fn(rda, cpu_env, qm, rda);
2125688ba4cfSPeter Maydell     store_reg(s, a->rda, rda);
2126688ba4cfSPeter Maydell     tcg_temp_free_ptr(qm);
2127688ba4cfSPeter Maydell     mve_update_eci(s);
2128688ba4cfSPeter Maydell     return true;
2129688ba4cfSPeter Maydell }
2130688ba4cfSPeter Maydell 
2131688ba4cfSPeter Maydell #define DO_VMAXV(INSN, FN)                                      \
2132688ba4cfSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vmaxv *a)     \
2133688ba4cfSPeter Maydell     {                                                           \
2134688ba4cfSPeter Maydell         static MVEGenVADDVFn * const fns[] = {                  \
2135688ba4cfSPeter Maydell             gen_helper_mve_##FN##b,                             \
2136688ba4cfSPeter Maydell             gen_helper_mve_##FN##h,                             \
2137688ba4cfSPeter Maydell             gen_helper_mve_##FN##w,                             \
2138688ba4cfSPeter Maydell             NULL,                                               \
2139688ba4cfSPeter Maydell         };                                                      \
2140688ba4cfSPeter Maydell         return do_vmaxv(s, a, fns[a->size]);                    \
2141688ba4cfSPeter Maydell     }
2142688ba4cfSPeter Maydell 
2143688ba4cfSPeter Maydell DO_VMAXV(VMAXV_S, vmaxvs)
2144688ba4cfSPeter Maydell DO_VMAXV(VMAXV_U, vmaxvu)
2145688ba4cfSPeter Maydell DO_VMAXV(VMAXAV, vmaxav)
2146688ba4cfSPeter Maydell DO_VMAXV(VMINV_S, vminvs)
2147688ba4cfSPeter Maydell DO_VMAXV(VMINV_U, vminvu)
2148688ba4cfSPeter Maydell DO_VMAXV(VMINAV, vminav)
21497f061c0aSPeter Maydell 
215029f80e7dSPeter Maydell #define DO_VMAXV_FP(INSN, FN)                                   \
215129f80e7dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vmaxv *a)     \
215229f80e7dSPeter Maydell     {                                                           \
215329f80e7dSPeter Maydell         static MVEGenVADDVFn * const fns[] = {                  \
215429f80e7dSPeter Maydell             NULL,                                               \
215529f80e7dSPeter Maydell             gen_helper_mve_##FN##h,                             \
215629f80e7dSPeter Maydell             gen_helper_mve_##FN##s,                             \
215729f80e7dSPeter Maydell             NULL,                                               \
215829f80e7dSPeter Maydell         };                                                      \
215929f80e7dSPeter Maydell         if (!dc_isar_feature(aa32_mve_fp, s)) {                 \
216029f80e7dSPeter Maydell             return false;                                       \
216129f80e7dSPeter Maydell         }                                                       \
216229f80e7dSPeter Maydell         return do_vmaxv(s, a, fns[a->size]);                    \
216329f80e7dSPeter Maydell     }
216429f80e7dSPeter Maydell 
216529f80e7dSPeter Maydell DO_VMAXV_FP(VMAXNMV, vmaxnmv)
216629f80e7dSPeter Maydell DO_VMAXV_FP(VMINNMV, vminnmv)
216729f80e7dSPeter Maydell DO_VMAXV_FP(VMAXNMAV, vmaxnmav)
216829f80e7dSPeter Maydell DO_VMAXV_FP(VMINNMAV, vminnmav)
216929f80e7dSPeter Maydell 
21707f061c0aSPeter Maydell static bool do_vabav(DisasContext *s, arg_vabav *a, MVEGenVABAVFn *fn)
21717f061c0aSPeter Maydell {
21727f061c0aSPeter Maydell     /* Absolute difference accumulated across vector */
21737f061c0aSPeter Maydell     TCGv_ptr qn, qm;
21747f061c0aSPeter Maydell     TCGv_i32 rda;
21757f061c0aSPeter Maydell 
21767f061c0aSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
21777f061c0aSPeter Maydell         !mve_check_qreg_bank(s, a->qm | a->qn) ||
21787f061c0aSPeter Maydell         !fn || a->rda == 13 || a->rda == 15) {
21797f061c0aSPeter Maydell         /* Rda cases are UNPREDICTABLE */
21807f061c0aSPeter Maydell         return false;
21817f061c0aSPeter Maydell     }
21827f061c0aSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
21837f061c0aSPeter Maydell         return true;
21847f061c0aSPeter Maydell     }
21857f061c0aSPeter Maydell 
21867f061c0aSPeter Maydell     qm = mve_qreg_ptr(a->qm);
21877f061c0aSPeter Maydell     qn = mve_qreg_ptr(a->qn);
21887f061c0aSPeter Maydell     rda = load_reg(s, a->rda);
21897f061c0aSPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
21907f061c0aSPeter Maydell     store_reg(s, a->rda, rda);
21917f061c0aSPeter Maydell     tcg_temp_free_ptr(qm);
21927f061c0aSPeter Maydell     tcg_temp_free_ptr(qn);
21937f061c0aSPeter Maydell     mve_update_eci(s);
21947f061c0aSPeter Maydell     return true;
21957f061c0aSPeter Maydell }
21967f061c0aSPeter Maydell 
21977f061c0aSPeter Maydell #define DO_VABAV(INSN, FN)                                      \
21987f061c0aSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_vabav *a)     \
21997f061c0aSPeter Maydell     {                                                           \
22007f061c0aSPeter Maydell         static MVEGenVABAVFn * const fns[] = {                  \
22017f061c0aSPeter Maydell             gen_helper_mve_##FN##b,                             \
22027f061c0aSPeter Maydell             gen_helper_mve_##FN##h,                             \
22037f061c0aSPeter Maydell             gen_helper_mve_##FN##w,                             \
22047f061c0aSPeter Maydell             NULL,                                               \
22057f061c0aSPeter Maydell         };                                                      \
22067f061c0aSPeter Maydell         return do_vabav(s, a, fns[a->size]);                    \
22077f061c0aSPeter Maydell     }
22087f061c0aSPeter Maydell 
22097f061c0aSPeter Maydell DO_VABAV(VABAV_S, vabavs)
22107f061c0aSPeter Maydell DO_VABAV(VABAV_U, vabavu)
22111241f148SPeter Maydell 
22121241f148SPeter Maydell static bool trans_VMOV_to_2gp(DisasContext *s, arg_VMOV_to_2gp *a)
22131241f148SPeter Maydell {
22141241f148SPeter Maydell     /*
22151241f148SPeter Maydell      * VMOV two 32-bit vector lanes to two general-purpose registers.
22161241f148SPeter Maydell      * This insn is not predicated but it is subject to beat-wise
22171241f148SPeter Maydell      * execution if it is not in an IT block. For us this means
22181241f148SPeter Maydell      * only that if PSR.ECI says we should not be executing the beat
22191241f148SPeter Maydell      * corresponding to the lane of the vector register being accessed
22201241f148SPeter Maydell      * then we should skip perfoming the move, and that we need to do
22211241f148SPeter Maydell      * the usual check for bad ECI state and advance of ECI state.
22221241f148SPeter Maydell      * (If PSR.ECI is non-zero then we cannot be in an IT block.)
22231241f148SPeter Maydell      */
22241241f148SPeter Maydell     TCGv_i32 tmp;
22251241f148SPeter Maydell     int vd;
22261241f148SPeter Maydell 
22271241f148SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd) ||
22281241f148SPeter Maydell         a->rt == 13 || a->rt == 15 || a->rt2 == 13 || a->rt2 == 15 ||
22291241f148SPeter Maydell         a->rt == a->rt2) {
22301241f148SPeter Maydell         /* Rt/Rt2 cases are UNPREDICTABLE */
22311241f148SPeter Maydell         return false;
22321241f148SPeter Maydell     }
22331241f148SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
22341241f148SPeter Maydell         return true;
22351241f148SPeter Maydell     }
22361241f148SPeter Maydell 
22371241f148SPeter Maydell     /* Convert Qreg index to Dreg for read_neon_element32() etc */
22381241f148SPeter Maydell     vd = a->qd * 2;
22391241f148SPeter Maydell 
22401241f148SPeter Maydell     if (!mve_skip_vmov(s, vd, a->idx, MO_32)) {
22411241f148SPeter Maydell         tmp = tcg_temp_new_i32();
22421241f148SPeter Maydell         read_neon_element32(tmp, vd, a->idx, MO_32);
22431241f148SPeter Maydell         store_reg(s, a->rt, tmp);
22441241f148SPeter Maydell     }
22451241f148SPeter Maydell     if (!mve_skip_vmov(s, vd + 1, a->idx, MO_32)) {
22461241f148SPeter Maydell         tmp = tcg_temp_new_i32();
22471241f148SPeter Maydell         read_neon_element32(tmp, vd + 1, a->idx, MO_32);
22481241f148SPeter Maydell         store_reg(s, a->rt2, tmp);
22491241f148SPeter Maydell     }
22501241f148SPeter Maydell 
22511241f148SPeter Maydell     mve_update_and_store_eci(s);
22521241f148SPeter Maydell     return true;
22531241f148SPeter Maydell }
22541241f148SPeter Maydell 
22551241f148SPeter Maydell static bool trans_VMOV_from_2gp(DisasContext *s, arg_VMOV_to_2gp *a)
22561241f148SPeter Maydell {
22571241f148SPeter Maydell     /*
22581241f148SPeter Maydell      * VMOV two general-purpose registers to two 32-bit vector lanes.
22591241f148SPeter Maydell      * This insn is not predicated but it is subject to beat-wise
22601241f148SPeter Maydell      * execution if it is not in an IT block. For us this means
22611241f148SPeter Maydell      * only that if PSR.ECI says we should not be executing the beat
22621241f148SPeter Maydell      * corresponding to the lane of the vector register being accessed
22631241f148SPeter Maydell      * then we should skip perfoming the move, and that we need to do
22641241f148SPeter Maydell      * the usual check for bad ECI state and advance of ECI state.
22651241f148SPeter Maydell      * (If PSR.ECI is non-zero then we cannot be in an IT block.)
22661241f148SPeter Maydell      */
22671241f148SPeter Maydell     TCGv_i32 tmp;
22681241f148SPeter Maydell     int vd;
22691241f148SPeter Maydell 
22701241f148SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd) ||
22711241f148SPeter Maydell         a->rt == 13 || a->rt == 15 || a->rt2 == 13 || a->rt2 == 15) {
22721241f148SPeter Maydell         /* Rt/Rt2 cases are UNPREDICTABLE */
22731241f148SPeter Maydell         return false;
22741241f148SPeter Maydell     }
22751241f148SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
22761241f148SPeter Maydell         return true;
22771241f148SPeter Maydell     }
22781241f148SPeter Maydell 
22791241f148SPeter Maydell     /* Convert Qreg idx to Dreg for read_neon_element32() etc */
22801241f148SPeter Maydell     vd = a->qd * 2;
22811241f148SPeter Maydell 
22821241f148SPeter Maydell     if (!mve_skip_vmov(s, vd, a->idx, MO_32)) {
22831241f148SPeter Maydell         tmp = load_reg(s, a->rt);
22841241f148SPeter Maydell         write_neon_element32(tmp, vd, a->idx, MO_32);
22851241f148SPeter Maydell         tcg_temp_free_i32(tmp);
22861241f148SPeter Maydell     }
22871241f148SPeter Maydell     if (!mve_skip_vmov(s, vd + 1, a->idx, MO_32)) {
22881241f148SPeter Maydell         tmp = load_reg(s, a->rt2);
22891241f148SPeter Maydell         write_neon_element32(tmp, vd + 1, a->idx, MO_32);
22901241f148SPeter Maydell         tcg_temp_free_i32(tmp);
22911241f148SPeter Maydell     }
22921241f148SPeter Maydell 
22931241f148SPeter Maydell     mve_update_and_store_eci(s);
22941241f148SPeter Maydell     return true;
22951241f148SPeter Maydell }
2296