xref: /qemu/target/arm/tcg/translate-mve.c (revision bb002345ebfe09f6f96fc41043f93d2e286cd136)
16390eed4SPeter Maydell /*
26390eed4SPeter Maydell  *  ARM translation: M-profile MVE instructions
36390eed4SPeter Maydell  *
46390eed4SPeter Maydell  *  Copyright (c) 2021 Linaro, Ltd.
56390eed4SPeter Maydell  *
66390eed4SPeter Maydell  * This library is free software; you can redistribute it and/or
76390eed4SPeter Maydell  * modify it under the terms of the GNU Lesser General Public
86390eed4SPeter Maydell  * License as published by the Free Software Foundation; either
96390eed4SPeter Maydell  * version 2.1 of the License, or (at your option) any later version.
106390eed4SPeter Maydell  *
116390eed4SPeter Maydell  * This library is distributed in the hope that it will be useful,
126390eed4SPeter Maydell  * but WITHOUT ANY WARRANTY; without even the implied warranty of
136390eed4SPeter Maydell  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
146390eed4SPeter Maydell  * Lesser General Public License for more details.
156390eed4SPeter Maydell  *
166390eed4SPeter Maydell  * You should have received a copy of the GNU Lesser General Public
176390eed4SPeter Maydell  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
186390eed4SPeter Maydell  */
196390eed4SPeter Maydell 
206390eed4SPeter Maydell #include "qemu/osdep.h"
216390eed4SPeter Maydell #include "tcg/tcg-op.h"
226390eed4SPeter Maydell #include "tcg/tcg-op-gvec.h"
236390eed4SPeter Maydell #include "exec/exec-all.h"
246390eed4SPeter Maydell #include "exec/gen-icount.h"
256390eed4SPeter Maydell #include "translate.h"
266390eed4SPeter Maydell #include "translate-a32.h"
276390eed4SPeter Maydell 
286390eed4SPeter Maydell /* Include the generated decoder */
296390eed4SPeter Maydell #include "decode-mve.c.inc"
30507b6a50SPeter Maydell 
31507b6a50SPeter Maydell typedef void MVEGenLdStFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
320f0f2bd5SPeter Maydell typedef void MVEGenOneOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
3368245e44SPeter Maydell typedef void MVEGenTwoOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr);
34e51896b3SPeter Maydell typedef void MVEGenTwoOpScalarFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32);
351d2386f7SPeter Maydell typedef void MVEGenDualAccOpFn(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64);
36507b6a50SPeter Maydell 
37507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */
38507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg)
39507b6a50SPeter Maydell {
40507b6a50SPeter Maydell     return offsetof(CPUARMState, vfp.zregs[reg].d[0]);
41507b6a50SPeter Maydell }
42507b6a50SPeter Maydell 
43507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg)
44507b6a50SPeter Maydell {
45507b6a50SPeter Maydell     TCGv_ptr ret = tcg_temp_new_ptr();
46507b6a50SPeter Maydell     tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg));
47507b6a50SPeter Maydell     return ret;
48507b6a50SPeter Maydell }
49507b6a50SPeter Maydell 
50507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask)
51507b6a50SPeter Maydell {
52507b6a50SPeter Maydell     /*
53507b6a50SPeter Maydell      * Check whether Qregs are in range. For v8.1M only Q0..Q7
54507b6a50SPeter Maydell      * are supported, see VFPSmallRegisterBank().
55507b6a50SPeter Maydell      */
56507b6a50SPeter Maydell     return qmask < 8;
57507b6a50SPeter Maydell }
58507b6a50SPeter Maydell 
59507b6a50SPeter Maydell static bool mve_eci_check(DisasContext *s)
60507b6a50SPeter Maydell {
61507b6a50SPeter Maydell     /*
62507b6a50SPeter Maydell      * This is a beatwise insn: check that ECI is valid (not a
63507b6a50SPeter Maydell      * reserved value) and note that we are handling it.
64507b6a50SPeter Maydell      * Return true if OK, false if we generated an exception.
65507b6a50SPeter Maydell      */
66507b6a50SPeter Maydell     s->eci_handled = true;
67507b6a50SPeter Maydell     switch (s->eci) {
68507b6a50SPeter Maydell     case ECI_NONE:
69507b6a50SPeter Maydell     case ECI_A0:
70507b6a50SPeter Maydell     case ECI_A0A1:
71507b6a50SPeter Maydell     case ECI_A0A1A2:
72507b6a50SPeter Maydell     case ECI_A0A1A2B0:
73507b6a50SPeter Maydell         return true;
74507b6a50SPeter Maydell     default:
75507b6a50SPeter Maydell         /* Reserved value: INVSTATE UsageFault */
76507b6a50SPeter Maydell         gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(),
77507b6a50SPeter Maydell                            default_exception_el(s));
78507b6a50SPeter Maydell         return false;
79507b6a50SPeter Maydell     }
80507b6a50SPeter Maydell }
81507b6a50SPeter Maydell 
82507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s)
83507b6a50SPeter Maydell {
84507b6a50SPeter Maydell     /*
85507b6a50SPeter Maydell      * The helper function will always update the CPUState field,
86507b6a50SPeter Maydell      * so we only need to update the DisasContext field.
87507b6a50SPeter Maydell      */
88507b6a50SPeter Maydell     if (s->eci) {
89507b6a50SPeter Maydell         s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE;
90507b6a50SPeter Maydell     }
91507b6a50SPeter Maydell }
92507b6a50SPeter Maydell 
93387debdbSPeter Maydell static void mve_update_and_store_eci(DisasContext *s)
94387debdbSPeter Maydell {
95387debdbSPeter Maydell     /*
96387debdbSPeter Maydell      * For insns which don't call a helper function that will call
97387debdbSPeter Maydell      * mve_advance_vpt(), this version updates s->eci and also stores
98387debdbSPeter Maydell      * it out to the CPUState field.
99387debdbSPeter Maydell      */
100387debdbSPeter Maydell     if (s->eci) {
101387debdbSPeter Maydell         mve_update_eci(s);
102387debdbSPeter Maydell         store_cpu_field(tcg_constant_i32(s->eci << 4), condexec_bits);
103387debdbSPeter Maydell     }
104387debdbSPeter Maydell }
105387debdbSPeter Maydell 
1061d2386f7SPeter Maydell static bool mve_skip_first_beat(DisasContext *s)
1071d2386f7SPeter Maydell {
1081d2386f7SPeter Maydell     /* Return true if PSR.ECI says we must skip the first beat of this insn */
1091d2386f7SPeter Maydell     switch (s->eci) {
1101d2386f7SPeter Maydell     case ECI_NONE:
1111d2386f7SPeter Maydell         return false;
1121d2386f7SPeter Maydell     case ECI_A0:
1131d2386f7SPeter Maydell     case ECI_A0A1:
1141d2386f7SPeter Maydell     case ECI_A0A1A2:
1151d2386f7SPeter Maydell     case ECI_A0A1A2B0:
1161d2386f7SPeter Maydell         return true;
1171d2386f7SPeter Maydell     default:
1181d2386f7SPeter Maydell         g_assert_not_reached();
1191d2386f7SPeter Maydell     }
1201d2386f7SPeter Maydell }
1211d2386f7SPeter Maydell 
122507b6a50SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn)
123507b6a50SPeter Maydell {
124507b6a50SPeter Maydell     TCGv_i32 addr;
125507b6a50SPeter Maydell     uint32_t offset;
126507b6a50SPeter Maydell     TCGv_ptr qreg;
127507b6a50SPeter Maydell 
128507b6a50SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
129507b6a50SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
130507b6a50SPeter Maydell         !fn) {
131507b6a50SPeter Maydell         return false;
132507b6a50SPeter Maydell     }
133507b6a50SPeter Maydell 
134507b6a50SPeter Maydell     /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
135507b6a50SPeter Maydell     if (a->rn == 15 || (a->rn == 13 && a->w)) {
136507b6a50SPeter Maydell         return false;
137507b6a50SPeter Maydell     }
138507b6a50SPeter Maydell 
139507b6a50SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
140507b6a50SPeter Maydell         return true;
141507b6a50SPeter Maydell     }
142507b6a50SPeter Maydell 
143507b6a50SPeter Maydell     offset = a->imm << a->size;
144507b6a50SPeter Maydell     if (!a->a) {
145507b6a50SPeter Maydell         offset = -offset;
146507b6a50SPeter Maydell     }
147507b6a50SPeter Maydell     addr = load_reg(s, a->rn);
148507b6a50SPeter Maydell     if (a->p) {
149507b6a50SPeter Maydell         tcg_gen_addi_i32(addr, addr, offset);
150507b6a50SPeter Maydell     }
151507b6a50SPeter Maydell 
152507b6a50SPeter Maydell     qreg = mve_qreg_ptr(a->qd);
153507b6a50SPeter Maydell     fn(cpu_env, qreg, addr);
154507b6a50SPeter Maydell     tcg_temp_free_ptr(qreg);
155507b6a50SPeter Maydell 
156507b6a50SPeter Maydell     /*
157507b6a50SPeter Maydell      * Writeback always happens after the last beat of the insn,
158507b6a50SPeter Maydell      * regardless of predication
159507b6a50SPeter Maydell      */
160507b6a50SPeter Maydell     if (a->w) {
161507b6a50SPeter Maydell         if (!a->p) {
162507b6a50SPeter Maydell             tcg_gen_addi_i32(addr, addr, offset);
163507b6a50SPeter Maydell         }
164507b6a50SPeter Maydell         store_reg(s, a->rn, addr);
165507b6a50SPeter Maydell     } else {
166507b6a50SPeter Maydell         tcg_temp_free_i32(addr);
167507b6a50SPeter Maydell     }
168507b6a50SPeter Maydell     mve_update_eci(s);
169507b6a50SPeter Maydell     return true;
170507b6a50SPeter Maydell }
171507b6a50SPeter Maydell 
172507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a)
173507b6a50SPeter Maydell {
174507b6a50SPeter Maydell     static MVEGenLdStFn * const ldstfns[4][2] = {
175507b6a50SPeter Maydell         { gen_helper_mve_vstrb, gen_helper_mve_vldrb },
176507b6a50SPeter Maydell         { gen_helper_mve_vstrh, gen_helper_mve_vldrh },
177507b6a50SPeter Maydell         { gen_helper_mve_vstrw, gen_helper_mve_vldrw },
178507b6a50SPeter Maydell         { NULL, NULL }
179507b6a50SPeter Maydell     };
180507b6a50SPeter Maydell     return do_ldst(s, a, ldstfns[a->size][a->l]);
181507b6a50SPeter Maydell }
1822fc6b751SPeter Maydell 
1832fc6b751SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST)                  \
1842fc6b751SPeter Maydell     static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a)   \
1852fc6b751SPeter Maydell     {                                                           \
1862fc6b751SPeter Maydell         static MVEGenLdStFn * const ldstfns[2][2] = {           \
1872fc6b751SPeter Maydell             { gen_helper_mve_##ST, gen_helper_mve_##SLD },      \
1882fc6b751SPeter Maydell             { NULL, gen_helper_mve_##ULD },                     \
1892fc6b751SPeter Maydell         };                                                      \
1902fc6b751SPeter Maydell         return do_ldst(s, a, ldstfns[a->u][a->l]);              \
1912fc6b751SPeter Maydell     }
1922fc6b751SPeter Maydell 
1932fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h)
1942fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w)
1952fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w)
1960f0f2bd5SPeter Maydell 
197ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
198ab59362fSPeter Maydell {
199ab59362fSPeter Maydell     TCGv_ptr qd;
200ab59362fSPeter Maydell     TCGv_i32 rt;
201ab59362fSPeter Maydell 
202ab59362fSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
203ab59362fSPeter Maydell         !mve_check_qreg_bank(s, a->qd)) {
204ab59362fSPeter Maydell         return false;
205ab59362fSPeter Maydell     }
206ab59362fSPeter Maydell     if (a->rt == 13 || a->rt == 15) {
207ab59362fSPeter Maydell         /* UNPREDICTABLE; we choose to UNDEF */
208ab59362fSPeter Maydell         return false;
209ab59362fSPeter Maydell     }
210ab59362fSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
211ab59362fSPeter Maydell         return true;
212ab59362fSPeter Maydell     }
213ab59362fSPeter Maydell 
214ab59362fSPeter Maydell     qd = mve_qreg_ptr(a->qd);
215ab59362fSPeter Maydell     rt = load_reg(s, a->rt);
216ab59362fSPeter Maydell     tcg_gen_dup_i32(a->size, rt, rt);
217ab59362fSPeter Maydell     gen_helper_mve_vdup(cpu_env, qd, rt);
218ab59362fSPeter Maydell     tcg_temp_free_ptr(qd);
219ab59362fSPeter Maydell     tcg_temp_free_i32(rt);
220ab59362fSPeter Maydell     mve_update_eci(s);
221ab59362fSPeter Maydell     return true;
222ab59362fSPeter Maydell }
223ab59362fSPeter Maydell 
2240f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
2250f0f2bd5SPeter Maydell {
2260f0f2bd5SPeter Maydell     TCGv_ptr qd, qm;
2270f0f2bd5SPeter Maydell 
2280f0f2bd5SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
2290f0f2bd5SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qm) ||
2300f0f2bd5SPeter Maydell         !fn) {
2310f0f2bd5SPeter Maydell         return false;
2320f0f2bd5SPeter Maydell     }
2330f0f2bd5SPeter Maydell 
2340f0f2bd5SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
2350f0f2bd5SPeter Maydell         return true;
2360f0f2bd5SPeter Maydell     }
2370f0f2bd5SPeter Maydell 
2380f0f2bd5SPeter Maydell     qd = mve_qreg_ptr(a->qd);
2390f0f2bd5SPeter Maydell     qm = mve_qreg_ptr(a->qm);
2400f0f2bd5SPeter Maydell     fn(cpu_env, qd, qm);
2410f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qd);
2420f0f2bd5SPeter Maydell     tcg_temp_free_ptr(qm);
2430f0f2bd5SPeter Maydell     mve_update_eci(s);
2440f0f2bd5SPeter Maydell     return true;
2450f0f2bd5SPeter Maydell }
2460f0f2bd5SPeter Maydell 
2470f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN)                                        \
2480f0f2bd5SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_1op *a)       \
2490f0f2bd5SPeter Maydell     {                                                           \
2500f0f2bd5SPeter Maydell         static MVEGenOneOpFn * const fns[] = {                  \
2510f0f2bd5SPeter Maydell             gen_helper_mve_##FN##b,                             \
2520f0f2bd5SPeter Maydell             gen_helper_mve_##FN##h,                             \
2530f0f2bd5SPeter Maydell             gen_helper_mve_##FN##w,                             \
2540f0f2bd5SPeter Maydell             NULL,                                               \
2550f0f2bd5SPeter Maydell         };                                                      \
2560f0f2bd5SPeter Maydell         return do_1op(s, a, fns[a->size]);                      \
2570f0f2bd5SPeter Maydell     }
2580f0f2bd5SPeter Maydell 
2590f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz)
2606437f1f7SPeter Maydell DO_1OP(VCLS, vcls)
26159c91773SPeter Maydell DO_1OP(VABS, vabs)
262399a8c76SPeter Maydell DO_1OP(VNEG, vneg)
263249b5309SPeter Maydell 
264249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a)
265249b5309SPeter Maydell {
266249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
267249b5309SPeter Maydell         gen_helper_mve_vrev16b,
268249b5309SPeter Maydell         NULL,
269249b5309SPeter Maydell         NULL,
270249b5309SPeter Maydell         NULL,
271249b5309SPeter Maydell     };
272249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
273249b5309SPeter Maydell }
274249b5309SPeter Maydell 
275249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a)
276249b5309SPeter Maydell {
277249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
278249b5309SPeter Maydell         gen_helper_mve_vrev32b,
279249b5309SPeter Maydell         gen_helper_mve_vrev32h,
280249b5309SPeter Maydell         NULL,
281249b5309SPeter Maydell         NULL,
282249b5309SPeter Maydell     };
283249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
284249b5309SPeter Maydell }
285249b5309SPeter Maydell 
286249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a)
287249b5309SPeter Maydell {
288249b5309SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
289249b5309SPeter Maydell         gen_helper_mve_vrev64b,
290249b5309SPeter Maydell         gen_helper_mve_vrev64h,
291249b5309SPeter Maydell         gen_helper_mve_vrev64w,
292249b5309SPeter Maydell         NULL,
293249b5309SPeter Maydell     };
294249b5309SPeter Maydell     return do_1op(s, a, fns[a->size]);
295249b5309SPeter Maydell }
2968abd3c80SPeter Maydell 
2978abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a)
2988abd3c80SPeter Maydell {
2998abd3c80SPeter Maydell     return do_1op(s, a, gen_helper_mve_vmvn);
3008abd3c80SPeter Maydell }
30159c91773SPeter Maydell 
30259c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a)
30359c91773SPeter Maydell {
30459c91773SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
30559c91773SPeter Maydell         NULL,
30659c91773SPeter Maydell         gen_helper_mve_vfabsh,
30759c91773SPeter Maydell         gen_helper_mve_vfabss,
30859c91773SPeter Maydell         NULL,
30959c91773SPeter Maydell     };
31059c91773SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
31159c91773SPeter Maydell         return false;
31259c91773SPeter Maydell     }
31359c91773SPeter Maydell     return do_1op(s, a, fns[a->size]);
31459c91773SPeter Maydell }
315399a8c76SPeter Maydell 
316399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a)
317399a8c76SPeter Maydell {
318399a8c76SPeter Maydell     static MVEGenOneOpFn * const fns[] = {
319399a8c76SPeter Maydell         NULL,
320399a8c76SPeter Maydell         gen_helper_mve_vfnegh,
321399a8c76SPeter Maydell         gen_helper_mve_vfnegs,
322399a8c76SPeter Maydell         NULL,
323399a8c76SPeter Maydell     };
324399a8c76SPeter Maydell     if (!dc_isar_feature(aa32_mve_fp, s)) {
325399a8c76SPeter Maydell         return false;
326399a8c76SPeter Maydell     }
327399a8c76SPeter Maydell     return do_1op(s, a, fns[a->size]);
328399a8c76SPeter Maydell }
32968245e44SPeter Maydell 
33068245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
33168245e44SPeter Maydell {
33268245e44SPeter Maydell     TCGv_ptr qd, qn, qm;
33368245e44SPeter Maydell 
33468245e44SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
33568245e44SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) ||
33668245e44SPeter Maydell         !fn) {
33768245e44SPeter Maydell         return false;
33868245e44SPeter Maydell     }
33968245e44SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
34068245e44SPeter Maydell         return true;
34168245e44SPeter Maydell     }
34268245e44SPeter Maydell 
34368245e44SPeter Maydell     qd = mve_qreg_ptr(a->qd);
34468245e44SPeter Maydell     qn = mve_qreg_ptr(a->qn);
34568245e44SPeter Maydell     qm = mve_qreg_ptr(a->qm);
34668245e44SPeter Maydell     fn(cpu_env, qd, qn, qm);
34768245e44SPeter Maydell     tcg_temp_free_ptr(qd);
34868245e44SPeter Maydell     tcg_temp_free_ptr(qn);
34968245e44SPeter Maydell     tcg_temp_free_ptr(qm);
35068245e44SPeter Maydell     mve_update_eci(s);
35168245e44SPeter Maydell     return true;
35268245e44SPeter Maydell }
35368245e44SPeter Maydell 
35468245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER)                                  \
35568245e44SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
35668245e44SPeter Maydell     {                                                           \
35768245e44SPeter Maydell         return do_2op(s, a, HELPER);                            \
35868245e44SPeter Maydell     }
35968245e44SPeter Maydell 
36068245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand)
36168245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic)
36268245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr)
36368245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn)
36468245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor)
3659333fe4dSPeter Maydell 
3669333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \
3679333fe4dSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2op *a)       \
3689333fe4dSPeter Maydell     {                                                           \
3699333fe4dSPeter Maydell         static MVEGenTwoOpFn * const fns[] = {                  \
3709333fe4dSPeter Maydell             gen_helper_mve_##FN##b,                             \
3719333fe4dSPeter Maydell             gen_helper_mve_##FN##h,                             \
3729333fe4dSPeter Maydell             gen_helper_mve_##FN##w,                             \
3739333fe4dSPeter Maydell             NULL,                                               \
3749333fe4dSPeter Maydell         };                                                      \
3759333fe4dSPeter Maydell         return do_2op(s, a, fns[a->size]);                      \
3769333fe4dSPeter Maydell     }
3779333fe4dSPeter Maydell 
3789333fe4dSPeter Maydell DO_2OP(VADD, vadd)
3799333fe4dSPeter Maydell DO_2OP(VSUB, vsub)
3809333fe4dSPeter Maydell DO_2OP(VMUL, vmul)
381ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs)
382ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu)
383fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs)
384fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu)
385cd367ff3SPeter Maydell DO_2OP(VMAX_S, vmaxs)
386cd367ff3SPeter Maydell DO_2OP(VMAX_U, vmaxu)
387cd367ff3SPeter Maydell DO_2OP(VMIN_S, vmins)
388cd367ff3SPeter Maydell DO_2OP(VMIN_U, vminu)
389bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds)
390bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu)
391abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds)
392abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu)
393abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs)
394abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu)
395ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs)
396ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu)
397ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts)
398ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu)
399380caf6cSPeter Maydell DO_2OP(VQDMULH, vqdmulh)
400380caf6cSPeter Maydell DO_2OP(VQRDMULH, vqrdmulh)
401f741707bSPeter Maydell DO_2OP(VQADD_S, vqadds)
402f741707bSPeter Maydell DO_2OP(VQADD_U, vqaddu)
403f741707bSPeter Maydell DO_2OP(VQSUB_S, vqsubs)
404f741707bSPeter Maydell DO_2OP(VQSUB_U, vqsubu)
4050372cad8SPeter Maydell DO_2OP(VSHL_S, vshls)
4060372cad8SPeter Maydell DO_2OP(VSHL_U, vshlu)
407*bb002345SPeter Maydell DO_2OP(VRSHL_S, vrshls)
408*bb002345SPeter Maydell DO_2OP(VRSHL_U, vrshlu)
409483da661SPeter Maydell DO_2OP(VQSHL_S, vqshls)
410483da661SPeter Maydell DO_2OP(VQSHL_U, vqshlu)
4119dc868c4SPeter Maydell DO_2OP(VQRSHL_S, vqrshls)
4129dc868c4SPeter Maydell DO_2OP(VQRSHL_U, vqrshlu)
4131d2386f7SPeter Maydell 
414e51896b3SPeter Maydell static bool do_2op_scalar(DisasContext *s, arg_2scalar *a,
415e51896b3SPeter Maydell                           MVEGenTwoOpScalarFn fn)
416e51896b3SPeter Maydell {
417e51896b3SPeter Maydell     TCGv_ptr qd, qn;
418e51896b3SPeter Maydell     TCGv_i32 rm;
419e51896b3SPeter Maydell 
420e51896b3SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
421e51896b3SPeter Maydell         !mve_check_qreg_bank(s, a->qd | a->qn) ||
422e51896b3SPeter Maydell         !fn) {
423e51896b3SPeter Maydell         return false;
424e51896b3SPeter Maydell     }
425e51896b3SPeter Maydell     if (a->rm == 13 || a->rm == 15) {
426e51896b3SPeter Maydell         /* UNPREDICTABLE */
427e51896b3SPeter Maydell         return false;
428e51896b3SPeter Maydell     }
429e51896b3SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
430e51896b3SPeter Maydell         return true;
431e51896b3SPeter Maydell     }
432e51896b3SPeter Maydell 
433e51896b3SPeter Maydell     qd = mve_qreg_ptr(a->qd);
434e51896b3SPeter Maydell     qn = mve_qreg_ptr(a->qn);
435e51896b3SPeter Maydell     rm = load_reg(s, a->rm);
436e51896b3SPeter Maydell     fn(cpu_env, qd, qn, rm);
437e51896b3SPeter Maydell     tcg_temp_free_i32(rm);
438e51896b3SPeter Maydell     tcg_temp_free_ptr(qd);
439e51896b3SPeter Maydell     tcg_temp_free_ptr(qn);
440e51896b3SPeter Maydell     mve_update_eci(s);
441e51896b3SPeter Maydell     return true;
442e51896b3SPeter Maydell }
443e51896b3SPeter Maydell 
444e51896b3SPeter Maydell #define DO_2OP_SCALAR(INSN, FN) \
445e51896b3SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2scalar *a)   \
446e51896b3SPeter Maydell     {                                                           \
447e51896b3SPeter Maydell         static MVEGenTwoOpScalarFn * const fns[] = {            \
448e51896b3SPeter Maydell             gen_helper_mve_##FN##b,                             \
449e51896b3SPeter Maydell             gen_helper_mve_##FN##h,                             \
450e51896b3SPeter Maydell             gen_helper_mve_##FN##w,                             \
451e51896b3SPeter Maydell             NULL,                                               \
452e51896b3SPeter Maydell         };                                                      \
453e51896b3SPeter Maydell         return do_2op_scalar(s, a, fns[a->size]);               \
454e51896b3SPeter Maydell     }
455e51896b3SPeter Maydell 
456e51896b3SPeter Maydell DO_2OP_SCALAR(VADD_scalar, vadd_scalar)
45791a358fdSPeter Maydell DO_2OP_SCALAR(VSUB_scalar, vsub_scalar)
45891a358fdSPeter Maydell DO_2OP_SCALAR(VMUL_scalar, vmul_scalar)
459644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_S_scalar, vhadds_scalar)
460644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_U_scalar, vhaddu_scalar)
461644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_S_scalar, vhsubs_scalar)
462644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_U_scalar, vhsubu_scalar)
46339f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_S_scalar, vqadds_scalar)
46439f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_U_scalar, vqaddu_scalar)
46539f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_S_scalar, vqsubs_scalar)
46639f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_U_scalar, vqsubu_scalar)
46766c05767SPeter Maydell DO_2OP_SCALAR(VQDMULH_scalar, vqdmulh_scalar)
46866c05767SPeter Maydell DO_2OP_SCALAR(VQRDMULH_scalar, vqrdmulh_scalar)
469b050543bSPeter Maydell DO_2OP_SCALAR(VBRSR, vbrsr)
470e51896b3SPeter Maydell 
471a8890353SPeter Maydell static bool trans_VQDMULLB_scalar(DisasContext *s, arg_2scalar *a)
472a8890353SPeter Maydell {
473a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
474a8890353SPeter Maydell         NULL,
475a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarh,
476a8890353SPeter Maydell         gen_helper_mve_vqdmullb_scalarw,
477a8890353SPeter Maydell         NULL,
478a8890353SPeter Maydell     };
479a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
480a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
481a8890353SPeter Maydell         return false;
482a8890353SPeter Maydell     }
483a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
484a8890353SPeter Maydell }
485a8890353SPeter Maydell 
486a8890353SPeter Maydell static bool trans_VQDMULLT_scalar(DisasContext *s, arg_2scalar *a)
487a8890353SPeter Maydell {
488a8890353SPeter Maydell     static MVEGenTwoOpScalarFn * const fns[] = {
489a8890353SPeter Maydell         NULL,
490a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarh,
491a8890353SPeter Maydell         gen_helper_mve_vqdmullt_scalarw,
492a8890353SPeter Maydell         NULL,
493a8890353SPeter Maydell     };
494a8890353SPeter Maydell     if (a->qd == a->qn && a->size == MO_32) {
495a8890353SPeter Maydell         /* UNPREDICTABLE; we choose to undef */
496a8890353SPeter Maydell         return false;
497a8890353SPeter Maydell     }
498a8890353SPeter Maydell     return do_2op_scalar(s, a, fns[a->size]);
499a8890353SPeter Maydell }
500a8890353SPeter Maydell 
5011d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a,
5021d2386f7SPeter Maydell                              MVEGenDualAccOpFn *fn)
5031d2386f7SPeter Maydell {
5041d2386f7SPeter Maydell     TCGv_ptr qn, qm;
5051d2386f7SPeter Maydell     TCGv_i64 rda;
5061d2386f7SPeter Maydell     TCGv_i32 rdalo, rdahi;
5071d2386f7SPeter Maydell 
5081d2386f7SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
5091d2386f7SPeter Maydell         !mve_check_qreg_bank(s, a->qn | a->qm) ||
5101d2386f7SPeter Maydell         !fn) {
5111d2386f7SPeter Maydell         return false;
5121d2386f7SPeter Maydell     }
5131d2386f7SPeter Maydell     /*
5141d2386f7SPeter Maydell      * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related
5151d2386f7SPeter Maydell      * encoding; rdalo always has bit 0 clear so cannot be 13 or 15.
5161d2386f7SPeter Maydell      */
5171d2386f7SPeter Maydell     if (a->rdahi == 13 || a->rdahi == 15) {
5181d2386f7SPeter Maydell         return false;
5191d2386f7SPeter Maydell     }
5201d2386f7SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
5211d2386f7SPeter Maydell         return true;
5221d2386f7SPeter Maydell     }
5231d2386f7SPeter Maydell 
5241d2386f7SPeter Maydell     qn = mve_qreg_ptr(a->qn);
5251d2386f7SPeter Maydell     qm = mve_qreg_ptr(a->qm);
5261d2386f7SPeter Maydell 
5271d2386f7SPeter Maydell     /*
5281d2386f7SPeter Maydell      * This insn is subject to beat-wise execution. Partial execution
5291d2386f7SPeter Maydell      * of an A=0 (no-accumulate) insn which does not execute the first
5301d2386f7SPeter Maydell      * beat must start with the current rda value, not 0.
5311d2386f7SPeter Maydell      */
5321d2386f7SPeter Maydell     if (a->a || mve_skip_first_beat(s)) {
5331d2386f7SPeter Maydell         rda = tcg_temp_new_i64();
5341d2386f7SPeter Maydell         rdalo = load_reg(s, a->rdalo);
5351d2386f7SPeter Maydell         rdahi = load_reg(s, a->rdahi);
5361d2386f7SPeter Maydell         tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
5371d2386f7SPeter Maydell         tcg_temp_free_i32(rdalo);
5381d2386f7SPeter Maydell         tcg_temp_free_i32(rdahi);
5391d2386f7SPeter Maydell     } else {
5401d2386f7SPeter Maydell         rda = tcg_const_i64(0);
5411d2386f7SPeter Maydell     }
5421d2386f7SPeter Maydell 
5431d2386f7SPeter Maydell     fn(rda, cpu_env, qn, qm, rda);
5441d2386f7SPeter Maydell     tcg_temp_free_ptr(qn);
5451d2386f7SPeter Maydell     tcg_temp_free_ptr(qm);
5461d2386f7SPeter Maydell 
5471d2386f7SPeter Maydell     rdalo = tcg_temp_new_i32();
5481d2386f7SPeter Maydell     rdahi = tcg_temp_new_i32();
5491d2386f7SPeter Maydell     tcg_gen_extrl_i64_i32(rdalo, rda);
5501d2386f7SPeter Maydell     tcg_gen_extrh_i64_i32(rdahi, rda);
5511d2386f7SPeter Maydell     store_reg(s, a->rdalo, rdalo);
5521d2386f7SPeter Maydell     store_reg(s, a->rdahi, rdahi);
5531d2386f7SPeter Maydell     tcg_temp_free_i64(rda);
5541d2386f7SPeter Maydell     mve_update_eci(s);
5551d2386f7SPeter Maydell     return true;
5561d2386f7SPeter Maydell }
5571d2386f7SPeter Maydell 
5581d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a)
5591d2386f7SPeter Maydell {
5601d2386f7SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
5611d2386f7SPeter Maydell         { NULL, NULL },
5621d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh },
5631d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw },
5641d2386f7SPeter Maydell         { NULL, NULL },
5651d2386f7SPeter Maydell     };
5661d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
5671d2386f7SPeter Maydell }
5681d2386f7SPeter Maydell 
5691d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a)
5701d2386f7SPeter Maydell {
5711d2386f7SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
5721d2386f7SPeter Maydell         { NULL, NULL },
5731d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuh, NULL },
5741d2386f7SPeter Maydell         { gen_helper_mve_vmlaldavuw, NULL },
5751d2386f7SPeter Maydell         { NULL, NULL },
5761d2386f7SPeter Maydell     };
5771d2386f7SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
5781d2386f7SPeter Maydell }
579181cd971SPeter Maydell 
580181cd971SPeter Maydell static bool trans_VMLSLDAV(DisasContext *s, arg_vmlaldav *a)
581181cd971SPeter Maydell {
582181cd971SPeter Maydell     static MVEGenDualAccOpFn * const fns[4][2] = {
583181cd971SPeter Maydell         { NULL, NULL },
584181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh },
585181cd971SPeter Maydell         { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw },
586181cd971SPeter Maydell         { NULL, NULL },
587181cd971SPeter Maydell     };
588181cd971SPeter Maydell     return do_long_dual_acc(s, a, fns[a->size][a->x]);
589181cd971SPeter Maydell }
59038548747SPeter Maydell 
59138548747SPeter Maydell static bool trans_VRMLALDAVH_S(DisasContext *s, arg_vmlaldav *a)
59238548747SPeter Maydell {
59338548747SPeter Maydell     static MVEGenDualAccOpFn * const fns[] = {
59438548747SPeter Maydell         gen_helper_mve_vrmlaldavhsw, gen_helper_mve_vrmlaldavhxsw,
59538548747SPeter Maydell     };
59638548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
59738548747SPeter Maydell }
59838548747SPeter Maydell 
59938548747SPeter Maydell static bool trans_VRMLALDAVH_U(DisasContext *s, arg_vmlaldav *a)
60038548747SPeter Maydell {
60138548747SPeter Maydell     static MVEGenDualAccOpFn * const fns[] = {
60238548747SPeter Maydell         gen_helper_mve_vrmlaldavhuw, NULL,
60338548747SPeter Maydell     };
60438548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
60538548747SPeter Maydell }
60638548747SPeter Maydell 
60738548747SPeter Maydell static bool trans_VRMLSLDAVH(DisasContext *s, arg_vmlaldav *a)
60838548747SPeter Maydell {
60938548747SPeter Maydell     static MVEGenDualAccOpFn * const fns[] = {
61038548747SPeter Maydell         gen_helper_mve_vrmlsldavhsw, gen_helper_mve_vrmlsldavhxsw,
61138548747SPeter Maydell     };
61238548747SPeter Maydell     return do_long_dual_acc(s, a, fns[a->x]);
61338548747SPeter Maydell }
614387debdbSPeter Maydell 
615387debdbSPeter Maydell static bool trans_VPST(DisasContext *s, arg_VPST *a)
616387debdbSPeter Maydell {
617387debdbSPeter Maydell     TCGv_i32 vpr;
618387debdbSPeter Maydell 
619387debdbSPeter Maydell     /* mask == 0 is a "related encoding" */
620387debdbSPeter Maydell     if (!dc_isar_feature(aa32_mve, s) || !a->mask) {
621387debdbSPeter Maydell         return false;
622387debdbSPeter Maydell     }
623387debdbSPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
624387debdbSPeter Maydell         return true;
625387debdbSPeter Maydell     }
626387debdbSPeter Maydell     /*
627387debdbSPeter Maydell      * Set the VPR mask fields. We take advantage of MASK01 and MASK23
628387debdbSPeter Maydell      * being adjacent fields in the register.
629387debdbSPeter Maydell      *
630387debdbSPeter Maydell      * This insn is not predicated, but it is subject to beat-wise
631387debdbSPeter Maydell      * execution, and the mask is updated on the odd-numbered beats.
632387debdbSPeter Maydell      * So if PSR.ECI says we should skip beat 1, we mustn't update the
633387debdbSPeter Maydell      * 01 mask field.
634387debdbSPeter Maydell      */
635387debdbSPeter Maydell     vpr = load_cpu_field(v7m.vpr);
636387debdbSPeter Maydell     switch (s->eci) {
637387debdbSPeter Maydell     case ECI_NONE:
638387debdbSPeter Maydell     case ECI_A0:
639387debdbSPeter Maydell         /* Update both 01 and 23 fields */
640387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
641387debdbSPeter Maydell                             tcg_constant_i32(a->mask | (a->mask << 4)),
642387debdbSPeter Maydell                             R_V7M_VPR_MASK01_SHIFT,
643387debdbSPeter Maydell                             R_V7M_VPR_MASK01_LENGTH + R_V7M_VPR_MASK23_LENGTH);
644387debdbSPeter Maydell         break;
645387debdbSPeter Maydell     case ECI_A0A1:
646387debdbSPeter Maydell     case ECI_A0A1A2:
647387debdbSPeter Maydell     case ECI_A0A1A2B0:
648387debdbSPeter Maydell         /* Update only the 23 mask field */
649387debdbSPeter Maydell         tcg_gen_deposit_i32(vpr, vpr,
650387debdbSPeter Maydell                             tcg_constant_i32(a->mask),
651387debdbSPeter Maydell                             R_V7M_VPR_MASK23_SHIFT, R_V7M_VPR_MASK23_LENGTH);
652387debdbSPeter Maydell         break;
653387debdbSPeter Maydell     default:
654387debdbSPeter Maydell         g_assert_not_reached();
655387debdbSPeter Maydell     }
656387debdbSPeter Maydell     store_cpu_field(vpr, v7m.vpr);
657387debdbSPeter Maydell     mve_update_and_store_eci(s);
658387debdbSPeter Maydell     return true;
659387debdbSPeter Maydell }
660