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