xref: /qemu/target/arm/tcg/translate-mve.c (revision 1d2386f70a0cb2ad9c5fab2cf1eedb80bb5b313d)
16390eed4SPeter Maydell /*
26390eed4SPeter Maydell  *  ARM translation: M-profile MVE instructions
36390eed4SPeter Maydell  *
46390eed4SPeter Maydell  *  Copyright (c) 2021 Linaro, Ltd.
56390eed4SPeter Maydell  *
66390eed4SPeter Maydell  * This library is free software; you can redistribute it and/or
76390eed4SPeter Maydell  * modify it under the terms of the GNU Lesser General Public
86390eed4SPeter Maydell  * License as published by the Free Software Foundation; either
96390eed4SPeter Maydell  * version 2.1 of the License, or (at your option) any later version.
106390eed4SPeter Maydell  *
116390eed4SPeter Maydell  * This library is distributed in the hope that it will be useful,
126390eed4SPeter Maydell  * but WITHOUT ANY WARRANTY; without even the implied warranty of
136390eed4SPeter Maydell  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
146390eed4SPeter Maydell  * Lesser General Public License for more details.
156390eed4SPeter Maydell  *
166390eed4SPeter Maydell  * You should have received a copy of the GNU Lesser General Public
176390eed4SPeter Maydell  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
186390eed4SPeter Maydell  */
196390eed4SPeter Maydell 
206390eed4SPeter Maydell #include "qemu/osdep.h"
216390eed4SPeter Maydell #include "tcg/tcg-op.h"
226390eed4SPeter Maydell #include "tcg/tcg-op-gvec.h"
236390eed4SPeter Maydell #include "exec/exec-all.h"
246390eed4SPeter Maydell #include "exec/gen-icount.h"
256390eed4SPeter Maydell #include "translate.h"
266390eed4SPeter Maydell #include "translate-a32.h"
276390eed4SPeter Maydell 
286390eed4SPeter Maydell /* Include the generated decoder */
296390eed4SPeter Maydell #include "decode-mve.c.inc"
30507b6a50SPeter Maydell 
31507b6a50SPeter Maydell typedef void MVEGenLdStFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
320f0f2bd5SPeter Maydell typedef void MVEGenOneOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
3368245e44SPeter Maydell typedef void MVEGenTwoOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr);
34*1d2386f7SPeter Maydell typedef void MVEGenDualAccOpFn(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64);
35507b6a50SPeter Maydell 
36507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */
37507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg)
38507b6a50SPeter Maydell {
39507b6a50SPeter Maydell     return offsetof(CPUARMState, vfp.zregs[reg].d[0]);
40507b6a50SPeter Maydell }
41507b6a50SPeter Maydell 
42507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg)
43507b6a50SPeter Maydell {
44507b6a50SPeter Maydell     TCGv_ptr ret = tcg_temp_new_ptr();
45507b6a50SPeter Maydell     tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg));
46507b6a50SPeter Maydell     return ret;
47507b6a50SPeter Maydell }
48507b6a50SPeter Maydell 
49507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask)
50507b6a50SPeter Maydell {
51507b6a50SPeter Maydell     /*
52507b6a50SPeter Maydell      * Check whether Qregs are in range. For v8.1M only Q0..Q7
53507b6a50SPeter Maydell      * are supported, see VFPSmallRegisterBank().
54507b6a50SPeter Maydell      */
55507b6a50SPeter Maydell     return qmask < 8;
56507b6a50SPeter Maydell }
57507b6a50SPeter Maydell 
58507b6a50SPeter Maydell static bool mve_eci_check(DisasContext *s)
59507b6a50SPeter Maydell {
60507b6a50SPeter Maydell     /*
61507b6a50SPeter Maydell      * This is a beatwise insn: check that ECI is valid (not a
62507b6a50SPeter Maydell      * reserved value) and note that we are handling it.
63507b6a50SPeter Maydell      * Return true if OK, false if we generated an exception.
64507b6a50SPeter Maydell      */
65507b6a50SPeter Maydell     s->eci_handled = true;
66507b6a50SPeter Maydell     switch (s->eci) {
67507b6a50SPeter Maydell     case ECI_NONE:
68507b6a50SPeter Maydell     case ECI_A0:
69507b6a50SPeter Maydell     case ECI_A0A1:
70507b6a50SPeter Maydell     case ECI_A0A1A2:
71507b6a50SPeter Maydell     case ECI_A0A1A2B0:
72507b6a50SPeter Maydell         return true;
73507b6a50SPeter Maydell     default:
74507b6a50SPeter Maydell         /* Reserved value: INVSTATE UsageFault */
75507b6a50SPeter Maydell         gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(),
76507b6a50SPeter Maydell                            default_exception_el(s));
77507b6a50SPeter Maydell         return false;
78507b6a50SPeter Maydell     }
79507b6a50SPeter Maydell }
80507b6a50SPeter Maydell 
81507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s)
82507b6a50SPeter Maydell {
83507b6a50SPeter Maydell     /*
84507b6a50SPeter Maydell      * The helper function will always update the CPUState field,
85507b6a50SPeter Maydell      * so we only need to update the DisasContext field.
86507b6a50SPeter Maydell      */
87507b6a50SPeter Maydell     if (s->eci) {
88507b6a50SPeter Maydell         s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE;
89507b6a50SPeter Maydell     }
90507b6a50SPeter Maydell }
91507b6a50SPeter Maydell 
92*1d2386f7SPeter Maydell static bool mve_skip_first_beat(DisasContext *s)
93*1d2386f7SPeter Maydell {
94*1d2386f7SPeter Maydell     /* Return true if PSR.ECI says we must skip the first beat of this insn */
95*1d2386f7SPeter Maydell     switch (s->eci) {
96*1d2386f7SPeter Maydell     case ECI_NONE:
97*1d2386f7SPeter Maydell         return false;
98*1d2386f7SPeter Maydell     case ECI_A0:
99*1d2386f7SPeter Maydell     case ECI_A0A1:
100*1d2386f7SPeter Maydell     case ECI_A0A1A2:
101*1d2386f7SPeter Maydell     case ECI_A0A1A2B0:
102*1d2386f7SPeter Maydell         return true;
103*1d2386f7SPeter Maydell     default:
104*1d2386f7SPeter Maydell         g_assert_not_reached();
105*1d2386f7SPeter Maydell     }
106*1d2386f7SPeter Maydell }
107*1d2386f7SPeter Maydell 
108507b6a50SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn)
109507b6a50SPeter Maydell {
110507b6a50SPeter Maydell     TCGv_i32 addr;
111507b6a50SPeter Maydell     uint32_t offset;
112507b6a50SPeter Maydell     TCGv_ptr qreg;
113507b6a50SPeter Maydell 
114507b6a50SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
115507b6a50SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
116507b6a50SPeter Maydell         !fn) {
117507b6a50SPeter Maydell         return false;
118507b6a50SPeter Maydell     }
119507b6a50SPeter Maydell 
120507b6a50SPeter Maydell     /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
121507b6a50SPeter Maydell     if (a->rn == 15 || (a->rn == 13 && a->w)) {
122507b6a50SPeter Maydell         return false;
123507b6a50SPeter Maydell     }
124507b6a50SPeter Maydell 
125507b6a50SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
126507b6a50SPeter Maydell         return true;
127507b6a50SPeter Maydell     }
128507b6a50SPeter Maydell 
129507b6a50SPeter Maydell     offset = a->imm << a->size;
130507b6a50SPeter Maydell     if (!a->a) {
131507b6a50SPeter Maydell         offset = -offset;
132507b6a50SPeter Maydell     }
133507b6a50SPeter Maydell     addr = load_reg(s, a->rn);
134507b6a50SPeter Maydell     if (a->p) {
135507b6a50SPeter Maydell         tcg_gen_addi_i32(addr, addr, offset);
136507b6a50SPeter Maydell     }
137507b6a50SPeter Maydell 
138507b6a50SPeter Maydell     qreg = mve_qreg_ptr(a->qd);
139507b6a50SPeter Maydell     fn(cpu_env, qreg, addr);
140507b6a50SPeter Maydell     tcg_temp_free_ptr(qreg);
141507b6a50SPeter Maydell 
142507b6a50SPeter Maydell     /*
143507b6a50SPeter Maydell      * Writeback always happens after the last beat of the insn,
144507b6a50SPeter Maydell      * regardless of predication
145507b6a50SPeter Maydell      */
146507b6a50SPeter Maydell     if (a->w) {
147507b6a50SPeter Maydell         if (!a->p) {
148507b6a50SPeter Maydell             tcg_gen_addi_i32(addr, addr, offset);
149507b6a50SPeter Maydell         }
150507b6a50SPeter Maydell         store_reg(s, a->rn, addr);
151507b6a50SPeter Maydell     } else {
152507b6a50SPeter Maydell         tcg_temp_free_i32(addr);
153507b6a50SPeter Maydell     }
154507b6a50SPeter Maydell     mve_update_eci(s);
155507b6a50SPeter Maydell     return true;
156507b6a50SPeter Maydell }
157507b6a50SPeter Maydell 
158507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a)
159507b6a50SPeter Maydell {
160507b6a50SPeter Maydell     static MVEGenLdStFn * const ldstfns[4][2] = {
161507b6a50SPeter Maydell         { gen_helper_mve_vstrb, gen_helper_mve_vldrb },
162507b6a50SPeter Maydell         { gen_helper_mve_vstrh, gen_helper_mve_vldrh },
163507b6a50SPeter Maydell         { gen_helper_mve_vstrw, gen_helper_mve_vldrw },
164507b6a50SPeter Maydell         { NULL, NULL }
165507b6a50SPeter Maydell     };
166507b6a50SPeter Maydell     return do_ldst(s, a, ldstfns[a->size][a->l]);
167507b6a50SPeter Maydell }
1682fc6b751SPeter Maydell 
1692fc6b751SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST)                  \
1702fc6b751SPeter Maydell     static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a)   \
1712fc6b751SPeter Maydell     {                                                           \
1722fc6b751SPeter Maydell         static MVEGenLdStFn * const ldstfns[2][2] = {           \
1732fc6b751SPeter Maydell             { gen_helper_mve_##ST, gen_helper_mve_##SLD },      \
1742fc6b751SPeter Maydell             { NULL, gen_helper_mve_##ULD },                     \
1752fc6b751SPeter Maydell         };                                                      \
1762fc6b751SPeter Maydell         return do_ldst(s, a, ldstfns[a->u][a->l]);              \
1772fc6b751SPeter Maydell     }
1782fc6b751SPeter Maydell 
1792fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h)
1802fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w)
1812fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w)
1820f0f2bd5SPeter Maydell 
183ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
184ab59362fSPeter Maydell {
185ab59362fSPeter Maydell     TCGv_ptr qd;
186ab59362fSPeter Maydell     TCGv_i32 rt;
187ab59362fSPeter Maydell 
188ab59362fSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
189ab59362fSPeter Maydell         !mve_check_qreg_bank(s, a->qd)) {
190ab59362fSPeter Maydell         return false;
191ab59362fSPeter Maydell     }
192ab59362fSPeter Maydell     if (a->rt == 13 || a->rt == 15) {
193ab59362fSPeter Maydell         /* UNPREDICTABLE; we choose to UNDEF */
194ab59362fSPeter Maydell         return false;
195ab59362fSPeter Maydell     }
196ab59362fSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
197ab59362fSPeter Maydell         return true;
198ab59362fSPeter Maydell     }
199ab59362fSPeter Maydell 
200ab59362fSPeter Maydell     qd = mve_qreg_ptr(a->qd);
201ab59362fSPeter Maydell     rt = load_reg(s, a->rt);
202ab59362fSPeter Maydell     tcg_gen_dup_i32(a->size, rt, rt);
203ab59362fSPeter Maydell     gen_helper_mve_vdup(cpu_env, qd, rt);
204ab59362fSPeter Maydell     tcg_temp_free_ptr(qd);
205ab59362fSPeter Maydell     tcg_temp_free_i32(rt);
206ab59362fSPeter Maydell     mve_update_eci(s);
207ab59362fSPeter Maydell     return true;
208ab59362fSPeter Maydell }
209ab59362fSPeter Maydell 
2100f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
2110f0f2bd5SPeter Maydell {
2120f0f2bd5SPeter Maydell     TCGv_ptr qd, qm;
2130f0f2bd5SPeter Maydell 
2140f0f2bd5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
2150f0f2bd5SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
2160f0f2bd5SPeter Maydell         !fn) {
2170f0f2bd5SPeter Maydell         return false;
2180f0f2bd5SPeter Maydell     }
2190f0f2bd5SPeter Maydell 
2200f0f2bd5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
2210f0f2bd5SPeter Maydell         return true;
2220f0f2bd5SPeter Maydell     }
2230f0f2bd5SPeter Maydell 
2240f0f2bd5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
2250f0f2bd5SPeter Maydell     qm = mve_qreg_ptr(a->qm);
2260f0f2bd5SPeter Maydell     fn(cpu_env, qd, qm);
2270f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qd);
2280f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qm);
2290f0f2bd5SPeter Maydell     mve_update_eci(s);
2300f0f2bd5SPeter Maydell     return true;
2310f0f2bd5SPeter Maydell }
2320f0f2bd5SPeter Maydell 
2330f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN)                                        \
2340f0f2bd5SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
2350f0f2bd5SPeter Maydell     {                                                           \
2360f0f2bd5SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
2370f0f2bd5SPeter Maydell             gen_helper_mve_##FN##b,                             \
2380f0f2bd5SPeter Maydell             gen_helper_mve_##FN##h,                             \
2390f0f2bd5SPeter Maydell             gen_helper_mve_##FN##w,                             \
2400f0f2bd5SPeter Maydell             NULL,                                               \
2410f0f2bd5SPeter Maydell         };                                                      \
2420f0f2bd5SPeter Maydell         return do_1op(s, a, fns[a->size]);                      \
2430f0f2bd5SPeter Maydell     }
2440f0f2bd5SPeter Maydell 
2450f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz)
2466437f1f7SPeter Maydell DO_1OP(VCLS, vcls)
24759c91773SPeter Maydell DO_1OP(VABS, vabs)
248399a8c76SPeter Maydell DO_1OP(VNEG, vneg)
249249b5309SPeter Maydell 
250249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a)
251249b5309SPeter Maydell {
252249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
253249b5309SPeter Maydell         gen_helper_mve_vrev16b,
254249b5309SPeter Maydell         NULL,
255249b5309SPeter Maydell         NULL,
256249b5309SPeter Maydell         NULL,
257249b5309SPeter Maydell     };
258249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
259249b5309SPeter Maydell }
260249b5309SPeter Maydell 
261249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a)
262249b5309SPeter Maydell {
263249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
264249b5309SPeter Maydell         gen_helper_mve_vrev32b,
265249b5309SPeter Maydell         gen_helper_mve_vrev32h,
266249b5309SPeter Maydell         NULL,
267249b5309SPeter Maydell         NULL,
268249b5309SPeter Maydell     };
269249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
270249b5309SPeter Maydell }
271249b5309SPeter Maydell 
272249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a)
273249b5309SPeter Maydell {
274249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
275249b5309SPeter Maydell         gen_helper_mve_vrev64b,
276249b5309SPeter Maydell         gen_helper_mve_vrev64h,
277249b5309SPeter Maydell         gen_helper_mve_vrev64w,
278249b5309SPeter Maydell         NULL,
279249b5309SPeter Maydell     };
280249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
281249b5309SPeter Maydell }
2828abd3c80SPeter Maydell 
2838abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a)
2848abd3c80SPeter Maydell {
2858abd3c80SPeter Maydell     return do_1op(s, a, gen_helper_mve_vmvn);
2868abd3c80SPeter Maydell }
28759c91773SPeter Maydell 
28859c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a)
28959c91773SPeter Maydell {
29059c91773SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
29159c91773SPeter Maydell         NULL,
29259c91773SPeter Maydell         gen_helper_mve_vfabsh,
29359c91773SPeter Maydell         gen_helper_mve_vfabss,
29459c91773SPeter Maydell         NULL,
29559c91773SPeter Maydell     };
29659c91773SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
29759c91773SPeter Maydell         return false;
29859c91773SPeter Maydell     }
29959c91773SPeter Maydell     return do_1op(s, a, fns[a->size]);
30059c91773SPeter Maydell }
301399a8c76SPeter Maydell 
302399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a)
303399a8c76SPeter Maydell {
304399a8c76SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
305399a8c76SPeter Maydell         NULL,
306399a8c76SPeter Maydell         gen_helper_mve_vfnegh,
307399a8c76SPeter Maydell         gen_helper_mve_vfnegs,
308399a8c76SPeter Maydell         NULL,
309399a8c76SPeter Maydell     };
310399a8c76SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
311399a8c76SPeter Maydell         return false;
312399a8c76SPeter Maydell     }
313399a8c76SPeter Maydell     return do_1op(s, a, fns[a->size]);
314399a8c76SPeter Maydell }
31568245e44SPeter Maydell 
31668245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
31768245e44SPeter Maydell {
31868245e44SPeter Maydell     TCGv_ptr qd, qn, qm;
31968245e44SPeter Maydell 
32068245e44SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
32168245e44SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) ||
32268245e44SPeter Maydell         !fn) {
32368245e44SPeter Maydell         return false;
32468245e44SPeter Maydell     }
32568245e44SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
32668245e44SPeter Maydell         return true;
32768245e44SPeter Maydell     }
32868245e44SPeter Maydell 
32968245e44SPeter Maydell     qd = mve_qreg_ptr(a->qd);
33068245e44SPeter Maydell     qn = mve_qreg_ptr(a->qn);
33168245e44SPeter Maydell     qm = mve_qreg_ptr(a->qm);
33268245e44SPeter Maydell     fn(cpu_env, qd, qn, qm);
33368245e44SPeter Maydell     tcg_temp_free_ptr(qd);
33468245e44SPeter Maydell     tcg_temp_free_ptr(qn);
33568245e44SPeter Maydell     tcg_temp_free_ptr(qm);
33668245e44SPeter Maydell     mve_update_eci(s);
33768245e44SPeter Maydell     return true;
33868245e44SPeter Maydell }
33968245e44SPeter Maydell 
34068245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER)                                  \
34168245e44SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
34268245e44SPeter Maydell     {                                                           \
34368245e44SPeter Maydell         return do_2op(s, a, HELPER);                            \
34468245e44SPeter Maydell     }
34568245e44SPeter Maydell 
34668245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand)
34768245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic)
34868245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr)
34968245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn)
35068245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor)
3519333fe4dSPeter Maydell 
3529333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \
3539333fe4dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
3549333fe4dSPeter Maydell     {                                                           \
3559333fe4dSPeter Maydell         static MVEGenTwoOpFn * const fns[] = {                  \
3569333fe4dSPeter Maydell             gen_helper_mve_##FN##b,                             \
3579333fe4dSPeter Maydell             gen_helper_mve_##FN##h,                             \
3589333fe4dSPeter Maydell             gen_helper_mve_##FN##w,                             \
3599333fe4dSPeter Maydell             NULL,                                               \
3609333fe4dSPeter Maydell         };                                                      \
3619333fe4dSPeter Maydell         return do_2op(s, a, fns[a->size]);                      \
3629333fe4dSPeter Maydell     }
3639333fe4dSPeter Maydell 
3649333fe4dSPeter Maydell DO_2OP(VADD, vadd)
3659333fe4dSPeter Maydell DO_2OP(VSUB, vsub)
3669333fe4dSPeter Maydell DO_2OP(VMUL, vmul)
367ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs)
368ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu)
369fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs)
370fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu)
371cd367ff3SPeter Maydell DO_2OP(VMAX_S, vmaxs)
372cd367ff3SPeter Maydell DO_2OP(VMAX_U, vmaxu)
373cd367ff3SPeter Maydell DO_2OP(VMIN_S, vmins)
374cd367ff3SPeter Maydell DO_2OP(VMIN_U, vminu)
375bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds)
376bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu)
377abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds)
378abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu)
379abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs)
380abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu)
381ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs)
382ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu)
383ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts)
384ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu)
385*1d2386f7SPeter Maydell 
386*1d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a,
387*1d2386f7SPeter Maydell                              MVEGenDualAccOpFn *fn)
388*1d2386f7SPeter Maydell {
389*1d2386f7SPeter Maydell     TCGv_ptr qn, qm;
390*1d2386f7SPeter Maydell     TCGv_i64 rda;
391*1d2386f7SPeter Maydell     TCGv_i32 rdalo, rdahi;
392*1d2386f7SPeter Maydell 
393*1d2386f7SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
394*1d2386f7SPeter Maydell         !mve_check_qreg_bank(s, a->qn | a->qm) ||
395*1d2386f7SPeter Maydell         !fn) {
396*1d2386f7SPeter Maydell         return false;
397*1d2386f7SPeter Maydell     }
398*1d2386f7SPeter Maydell     /*
399*1d2386f7SPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
400*1d2386f7SPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
401*1d2386f7SPeter Maydell      */
402*1d2386f7SPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
403*1d2386f7SPeter Maydell         return false;
404*1d2386f7SPeter Maydell     }
405*1d2386f7SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
406*1d2386f7SPeter Maydell         return true;
407*1d2386f7SPeter Maydell     }
408*1d2386f7SPeter Maydell 
409*1d2386f7SPeter Maydell     qn = mve_qreg_ptr(a->qn);
410*1d2386f7SPeter Maydell     qm = mve_qreg_ptr(a->qm);
411*1d2386f7SPeter Maydell 
412*1d2386f7SPeter Maydell     /*
413*1d2386f7SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
414*1d2386f7SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
415*1d2386f7SPeter Maydell      * beat must start with the current rda value, not 0.
416*1d2386f7SPeter Maydell      */
417*1d2386f7SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
418*1d2386f7SPeter Maydell         rda = tcg_temp_new_i64();
419*1d2386f7SPeter Maydell         rdalo = load_reg(s, a->rdalo);
420*1d2386f7SPeter Maydell         rdahi = load_reg(s, a->rdahi);
421*1d2386f7SPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
422*1d2386f7SPeter Maydell         tcg_temp_free_i32(rdalo);
423*1d2386f7SPeter Maydell         tcg_temp_free_i32(rdahi);
424*1d2386f7SPeter Maydell     } else {
425*1d2386f7SPeter Maydell         rda = tcg_const_i64(0);
426*1d2386f7SPeter Maydell     }
427*1d2386f7SPeter Maydell 
428*1d2386f7SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
429*1d2386f7SPeter Maydell     tcg_temp_free_ptr(qn);
430*1d2386f7SPeter Maydell     tcg_temp_free_ptr(qm);
431*1d2386f7SPeter Maydell 
432*1d2386f7SPeter Maydell     rdalo = tcg_temp_new_i32();
433*1d2386f7SPeter Maydell     rdahi = tcg_temp_new_i32();
434*1d2386f7SPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
435*1d2386f7SPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
436*1d2386f7SPeter Maydell     store_reg(s, a->rdalo, rdalo);
437*1d2386f7SPeter Maydell     store_reg(s, a->rdahi, rdahi);
438*1d2386f7SPeter Maydell     tcg_temp_free_i64(rda);
439*1d2386f7SPeter Maydell     mve_update_eci(s);
440*1d2386f7SPeter Maydell     return true;
441*1d2386f7SPeter Maydell }
442*1d2386f7SPeter Maydell 
443*1d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a)
444*1d2386f7SPeter Maydell {
445*1d2386f7SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
446*1d2386f7SPeter Maydell         { NULL, NULL },
447*1d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh },
448*1d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw },
449*1d2386f7SPeter Maydell         { NULL, NULL },
450*1d2386f7SPeter Maydell     };
451*1d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
452*1d2386f7SPeter Maydell }
453*1d2386f7SPeter Maydell 
454*1d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a)
455*1d2386f7SPeter Maydell {
456*1d2386f7SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
457*1d2386f7SPeter Maydell         { NULL, NULL },
458*1d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuh, NULL },
459*1d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuw, NULL },
460*1d2386f7SPeter Maydell         { NULL, NULL },
461*1d2386f7SPeter Maydell     };
462*1d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
463*1d2386f7SPeter Maydell }
464