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); 370f0f2bd5SPeter Maydell typedef void MVEGenOneOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); 3868245e44SPeter Maydell typedef void MVEGenTwoOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr); 39e51896b3SPeter Maydell typedef void MVEGenTwoOpScalarFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32); 40f9ed6174SPeter Maydell typedef void MVEGenTwoOpShiftFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32); 411d2386f7SPeter Maydell typedef void MVEGenDualAccOpFn(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64); 426f060a63SPeter Maydell typedef void MVEGenVADDVFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32); 43eab84139SPeter Maydell typedef void MVEGenOneOpImmFn(TCGv_ptr, TCGv_ptr, TCGv_i64); 44395b92d5SPeter Maydell typedef void MVEGenVIDUPFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32, TCGv_i32); 45395b92d5SPeter Maydell typedef void MVEGenVIWDUPFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32, TCGv_i32, TCGv_i32); 46eff5d9a9SPeter Maydell typedef void MVEGenCmpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); 47*cce81873SPeter Maydell typedef void MVEGenScalarCmpFn(TCGv_ptr, TCGv_ptr, TCGv_i32); 48507b6a50SPeter Maydell 49507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */ 50507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg) 51507b6a50SPeter Maydell { 52507b6a50SPeter Maydell return offsetof(CPUARMState, vfp.zregs[reg].d[0]); 53507b6a50SPeter Maydell } 54507b6a50SPeter Maydell 55507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg) 56507b6a50SPeter Maydell { 57507b6a50SPeter Maydell TCGv_ptr ret = tcg_temp_new_ptr(); 58507b6a50SPeter Maydell tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg)); 59507b6a50SPeter Maydell return ret; 60507b6a50SPeter Maydell } 61507b6a50SPeter Maydell 62507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask) 63507b6a50SPeter Maydell { 64507b6a50SPeter Maydell /* 65507b6a50SPeter Maydell * Check whether Qregs are in range. For v8.1M only Q0..Q7 66507b6a50SPeter Maydell * are supported, see VFPSmallRegisterBank(). 67507b6a50SPeter Maydell */ 68507b6a50SPeter Maydell return qmask < 8; 69507b6a50SPeter Maydell } 70507b6a50SPeter Maydell 714f57ef95SPeter Maydell bool mve_eci_check(DisasContext *s) 72507b6a50SPeter Maydell { 73507b6a50SPeter Maydell /* 74507b6a50SPeter Maydell * This is a beatwise insn: check that ECI is valid (not a 75507b6a50SPeter Maydell * reserved value) and note that we are handling it. 76507b6a50SPeter Maydell * Return true if OK, false if we generated an exception. 77507b6a50SPeter Maydell */ 78507b6a50SPeter Maydell s->eci_handled = true; 79507b6a50SPeter Maydell switch (s->eci) { 80507b6a50SPeter Maydell case ECI_NONE: 81507b6a50SPeter Maydell case ECI_A0: 82507b6a50SPeter Maydell case ECI_A0A1: 83507b6a50SPeter Maydell case ECI_A0A1A2: 84507b6a50SPeter Maydell case ECI_A0A1A2B0: 85507b6a50SPeter Maydell return true; 86507b6a50SPeter Maydell default: 87507b6a50SPeter Maydell /* Reserved value: INVSTATE UsageFault */ 88507b6a50SPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(), 89507b6a50SPeter Maydell default_exception_el(s)); 90507b6a50SPeter Maydell return false; 91507b6a50SPeter Maydell } 92507b6a50SPeter Maydell } 93507b6a50SPeter Maydell 94507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s) 95507b6a50SPeter Maydell { 96507b6a50SPeter Maydell /* 97507b6a50SPeter Maydell * The helper function will always update the CPUState field, 98507b6a50SPeter Maydell * so we only need to update the DisasContext field. 99507b6a50SPeter Maydell */ 100507b6a50SPeter Maydell if (s->eci) { 101507b6a50SPeter Maydell s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE; 102507b6a50SPeter Maydell } 103507b6a50SPeter Maydell } 104507b6a50SPeter Maydell 1054f57ef95SPeter Maydell void mve_update_and_store_eci(DisasContext *s) 106387debdbSPeter Maydell { 107387debdbSPeter Maydell /* 108387debdbSPeter Maydell * For insns which don't call a helper function that will call 109387debdbSPeter Maydell * mve_advance_vpt(), this version updates s->eci and also stores 110387debdbSPeter Maydell * it out to the CPUState field. 111387debdbSPeter Maydell */ 112387debdbSPeter Maydell if (s->eci) { 113387debdbSPeter Maydell mve_update_eci(s); 114387debdbSPeter Maydell store_cpu_field(tcg_constant_i32(s->eci << 4), condexec_bits); 115387debdbSPeter Maydell } 116387debdbSPeter Maydell } 117387debdbSPeter Maydell 1181d2386f7SPeter Maydell static bool mve_skip_first_beat(DisasContext *s) 1191d2386f7SPeter Maydell { 1201d2386f7SPeter Maydell /* Return true if PSR.ECI says we must skip the first beat of this insn */ 1211d2386f7SPeter Maydell switch (s->eci) { 1221d2386f7SPeter Maydell case ECI_NONE: 1231d2386f7SPeter Maydell return false; 1241d2386f7SPeter Maydell case ECI_A0: 1251d2386f7SPeter Maydell case ECI_A0A1: 1261d2386f7SPeter Maydell case ECI_A0A1A2: 1271d2386f7SPeter Maydell case ECI_A0A1A2B0: 1281d2386f7SPeter Maydell return true; 1291d2386f7SPeter Maydell default: 1301d2386f7SPeter Maydell g_assert_not_reached(); 1311d2386f7SPeter Maydell } 1321d2386f7SPeter Maydell } 1331d2386f7SPeter Maydell 134d59ccc30SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn, 135d59ccc30SPeter Maydell unsigned msize) 136507b6a50SPeter Maydell { 137507b6a50SPeter Maydell TCGv_i32 addr; 138507b6a50SPeter Maydell uint32_t offset; 139507b6a50SPeter Maydell TCGv_ptr qreg; 140507b6a50SPeter Maydell 141507b6a50SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 142507b6a50SPeter Maydell !mve_check_qreg_bank(s, a->qd) || 143507b6a50SPeter Maydell !fn) { 144507b6a50SPeter Maydell return false; 145507b6a50SPeter Maydell } 146507b6a50SPeter Maydell 147507b6a50SPeter Maydell /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */ 148507b6a50SPeter Maydell if (a->rn == 15 || (a->rn == 13 && a->w)) { 149507b6a50SPeter Maydell return false; 150507b6a50SPeter Maydell } 151507b6a50SPeter Maydell 152507b6a50SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 153507b6a50SPeter Maydell return true; 154507b6a50SPeter Maydell } 155507b6a50SPeter Maydell 156d59ccc30SPeter Maydell offset = a->imm << msize; 157507b6a50SPeter Maydell if (!a->a) { 158507b6a50SPeter Maydell offset = -offset; 159507b6a50SPeter Maydell } 160507b6a50SPeter Maydell addr = load_reg(s, a->rn); 161507b6a50SPeter Maydell if (a->p) { 162507b6a50SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 163507b6a50SPeter Maydell } 164507b6a50SPeter Maydell 165507b6a50SPeter Maydell qreg = mve_qreg_ptr(a->qd); 166507b6a50SPeter Maydell fn(cpu_env, qreg, addr); 167507b6a50SPeter Maydell tcg_temp_free_ptr(qreg); 168507b6a50SPeter Maydell 169507b6a50SPeter Maydell /* 170507b6a50SPeter Maydell * Writeback always happens after the last beat of the insn, 171507b6a50SPeter Maydell * regardless of predication 172507b6a50SPeter Maydell */ 173507b6a50SPeter Maydell if (a->w) { 174507b6a50SPeter Maydell if (!a->p) { 175507b6a50SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 176507b6a50SPeter Maydell } 177507b6a50SPeter Maydell store_reg(s, a->rn, addr); 178507b6a50SPeter Maydell } else { 179507b6a50SPeter Maydell tcg_temp_free_i32(addr); 180507b6a50SPeter Maydell } 181507b6a50SPeter Maydell mve_update_eci(s); 182507b6a50SPeter Maydell return true; 183507b6a50SPeter Maydell } 184507b6a50SPeter Maydell 185507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a) 186507b6a50SPeter Maydell { 187507b6a50SPeter Maydell static MVEGenLdStFn * const ldstfns[4][2] = { 188507b6a50SPeter Maydell { gen_helper_mve_vstrb, gen_helper_mve_vldrb }, 189507b6a50SPeter Maydell { gen_helper_mve_vstrh, gen_helper_mve_vldrh }, 190507b6a50SPeter Maydell { gen_helper_mve_vstrw, gen_helper_mve_vldrw }, 191507b6a50SPeter Maydell { NULL, NULL } 192507b6a50SPeter Maydell }; 193d59ccc30SPeter Maydell return do_ldst(s, a, ldstfns[a->size][a->l], a->size); 194507b6a50SPeter Maydell } 1952fc6b751SPeter Maydell 196d59ccc30SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST, MSIZE) \ 1972fc6b751SPeter Maydell static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a) \ 1982fc6b751SPeter Maydell { \ 1992fc6b751SPeter Maydell static MVEGenLdStFn * const ldstfns[2][2] = { \ 2002fc6b751SPeter Maydell { gen_helper_mve_##ST, gen_helper_mve_##SLD }, \ 2012fc6b751SPeter Maydell { NULL, gen_helper_mve_##ULD }, \ 2022fc6b751SPeter Maydell }; \ 203d59ccc30SPeter Maydell return do_ldst(s, a, ldstfns[a->u][a->l], MSIZE); \ 2042fc6b751SPeter Maydell } 2052fc6b751SPeter Maydell 206d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h, MO_8) 207d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w, MO_8) 208d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w, MO_16) 2090f0f2bd5SPeter Maydell 210ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a) 211ab59362fSPeter Maydell { 212ab59362fSPeter Maydell TCGv_ptr qd; 213ab59362fSPeter Maydell TCGv_i32 rt; 214ab59362fSPeter Maydell 215ab59362fSPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 216ab59362fSPeter Maydell !mve_check_qreg_bank(s, a->qd)) { 217ab59362fSPeter Maydell return false; 218ab59362fSPeter Maydell } 219ab59362fSPeter Maydell if (a->rt == 13 || a->rt == 15) { 220ab59362fSPeter Maydell /* UNPREDICTABLE; we choose to UNDEF */ 221ab59362fSPeter Maydell return false; 222ab59362fSPeter Maydell } 223ab59362fSPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 224ab59362fSPeter Maydell return true; 225ab59362fSPeter Maydell } 226ab59362fSPeter Maydell 227ab59362fSPeter Maydell qd = mve_qreg_ptr(a->qd); 228ab59362fSPeter Maydell rt = load_reg(s, a->rt); 229ab59362fSPeter Maydell tcg_gen_dup_i32(a->size, rt, rt); 230ab59362fSPeter Maydell gen_helper_mve_vdup(cpu_env, qd, rt); 231ab59362fSPeter Maydell tcg_temp_free_ptr(qd); 232ab59362fSPeter Maydell tcg_temp_free_i32(rt); 233ab59362fSPeter Maydell mve_update_eci(s); 234ab59362fSPeter Maydell return true; 235ab59362fSPeter Maydell } 236ab59362fSPeter Maydell 2370f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn) 2380f0f2bd5SPeter Maydell { 2390f0f2bd5SPeter Maydell TCGv_ptr qd, qm; 2400f0f2bd5SPeter Maydell 2410f0f2bd5SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 2420f0f2bd5SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qm) || 2430f0f2bd5SPeter Maydell !fn) { 2440f0f2bd5SPeter Maydell return false; 2450f0f2bd5SPeter Maydell } 2460f0f2bd5SPeter Maydell 2470f0f2bd5SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 2480f0f2bd5SPeter Maydell return true; 2490f0f2bd5SPeter Maydell } 2500f0f2bd5SPeter Maydell 2510f0f2bd5SPeter Maydell qd = mve_qreg_ptr(a->qd); 2520f0f2bd5SPeter Maydell qm = mve_qreg_ptr(a->qm); 2530f0f2bd5SPeter Maydell fn(cpu_env, qd, qm); 2540f0f2bd5SPeter Maydell tcg_temp_free_ptr(qd); 2550f0f2bd5SPeter Maydell tcg_temp_free_ptr(qm); 2560f0f2bd5SPeter Maydell mve_update_eci(s); 2570f0f2bd5SPeter Maydell return true; 2580f0f2bd5SPeter Maydell } 2590f0f2bd5SPeter Maydell 2600f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN) \ 2610f0f2bd5SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_1op *a) \ 2620f0f2bd5SPeter Maydell { \ 2630f0f2bd5SPeter Maydell static MVEGenOneOpFn * const fns[] = { \ 2640f0f2bd5SPeter Maydell gen_helper_mve_##FN##b, \ 2650f0f2bd5SPeter Maydell gen_helper_mve_##FN##h, \ 2660f0f2bd5SPeter Maydell gen_helper_mve_##FN##w, \ 2670f0f2bd5SPeter Maydell NULL, \ 2680f0f2bd5SPeter Maydell }; \ 2690f0f2bd5SPeter Maydell return do_1op(s, a, fns[a->size]); \ 2700f0f2bd5SPeter Maydell } 2710f0f2bd5SPeter Maydell 2720f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz) 2736437f1f7SPeter Maydell DO_1OP(VCLS, vcls) 27459c91773SPeter Maydell DO_1OP(VABS, vabs) 275399a8c76SPeter Maydell DO_1OP(VNEG, vneg) 276249b5309SPeter Maydell 277249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a) 278249b5309SPeter Maydell { 279249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 280249b5309SPeter Maydell gen_helper_mve_vrev16b, 281249b5309SPeter Maydell NULL, 282249b5309SPeter Maydell NULL, 283249b5309SPeter Maydell NULL, 284249b5309SPeter Maydell }; 285249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 286249b5309SPeter Maydell } 287249b5309SPeter Maydell 288249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a) 289249b5309SPeter Maydell { 290249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 291249b5309SPeter Maydell gen_helper_mve_vrev32b, 292249b5309SPeter Maydell gen_helper_mve_vrev32h, 293249b5309SPeter Maydell NULL, 294249b5309SPeter Maydell NULL, 295249b5309SPeter Maydell }; 296249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 297249b5309SPeter Maydell } 298249b5309SPeter Maydell 299249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a) 300249b5309SPeter Maydell { 301249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 302249b5309SPeter Maydell gen_helper_mve_vrev64b, 303249b5309SPeter Maydell gen_helper_mve_vrev64h, 304249b5309SPeter Maydell gen_helper_mve_vrev64w, 305249b5309SPeter Maydell NULL, 306249b5309SPeter Maydell }; 307249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 308249b5309SPeter Maydell } 3098abd3c80SPeter Maydell 3108abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a) 3118abd3c80SPeter Maydell { 3128abd3c80SPeter Maydell return do_1op(s, a, gen_helper_mve_vmvn); 3138abd3c80SPeter Maydell } 31459c91773SPeter Maydell 31559c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a) 31659c91773SPeter Maydell { 31759c91773SPeter Maydell static MVEGenOneOpFn * const fns[] = { 31859c91773SPeter Maydell NULL, 31959c91773SPeter Maydell gen_helper_mve_vfabsh, 32059c91773SPeter Maydell gen_helper_mve_vfabss, 32159c91773SPeter Maydell NULL, 32259c91773SPeter Maydell }; 32359c91773SPeter Maydell if (!dc_isar_feature(aa32_mve_fp, s)) { 32459c91773SPeter Maydell return false; 32559c91773SPeter Maydell } 32659c91773SPeter Maydell return do_1op(s, a, fns[a->size]); 32759c91773SPeter Maydell } 328399a8c76SPeter Maydell 329399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a) 330399a8c76SPeter Maydell { 331399a8c76SPeter Maydell static MVEGenOneOpFn * const fns[] = { 332399a8c76SPeter Maydell NULL, 333399a8c76SPeter Maydell gen_helper_mve_vfnegh, 334399a8c76SPeter Maydell gen_helper_mve_vfnegs, 335399a8c76SPeter Maydell NULL, 336399a8c76SPeter Maydell }; 337399a8c76SPeter Maydell if (!dc_isar_feature(aa32_mve_fp, s)) { 338399a8c76SPeter Maydell return false; 339399a8c76SPeter Maydell } 340399a8c76SPeter Maydell return do_1op(s, a, fns[a->size]); 341399a8c76SPeter Maydell } 34268245e44SPeter Maydell 34368245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn) 34468245e44SPeter Maydell { 34568245e44SPeter Maydell TCGv_ptr qd, qn, qm; 34668245e44SPeter Maydell 34768245e44SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 34868245e44SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) || 34968245e44SPeter Maydell !fn) { 35068245e44SPeter Maydell return false; 35168245e44SPeter Maydell } 35268245e44SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 35368245e44SPeter Maydell return true; 35468245e44SPeter Maydell } 35568245e44SPeter Maydell 35668245e44SPeter Maydell qd = mve_qreg_ptr(a->qd); 35768245e44SPeter Maydell qn = mve_qreg_ptr(a->qn); 35868245e44SPeter Maydell qm = mve_qreg_ptr(a->qm); 35968245e44SPeter Maydell fn(cpu_env, qd, qn, qm); 36068245e44SPeter Maydell tcg_temp_free_ptr(qd); 36168245e44SPeter Maydell tcg_temp_free_ptr(qn); 36268245e44SPeter Maydell tcg_temp_free_ptr(qm); 36368245e44SPeter Maydell mve_update_eci(s); 36468245e44SPeter Maydell return true; 36568245e44SPeter Maydell } 36668245e44SPeter Maydell 36768245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER) \ 36868245e44SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2op *a) \ 36968245e44SPeter Maydell { \ 37068245e44SPeter Maydell return do_2op(s, a, HELPER); \ 37168245e44SPeter Maydell } 37268245e44SPeter Maydell 37368245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand) 37468245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic) 37568245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr) 37668245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn) 37768245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor) 3789333fe4dSPeter Maydell 3799333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \ 3809333fe4dSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2op *a) \ 3819333fe4dSPeter Maydell { \ 3829333fe4dSPeter Maydell static MVEGenTwoOpFn * const fns[] = { \ 3839333fe4dSPeter Maydell gen_helper_mve_##FN##b, \ 3849333fe4dSPeter Maydell gen_helper_mve_##FN##h, \ 3859333fe4dSPeter Maydell gen_helper_mve_##FN##w, \ 3869333fe4dSPeter Maydell NULL, \ 3879333fe4dSPeter Maydell }; \ 3889333fe4dSPeter Maydell return do_2op(s, a, fns[a->size]); \ 3899333fe4dSPeter Maydell } 3909333fe4dSPeter Maydell 3919333fe4dSPeter Maydell DO_2OP(VADD, vadd) 3929333fe4dSPeter Maydell DO_2OP(VSUB, vsub) 3939333fe4dSPeter Maydell DO_2OP(VMUL, vmul) 394ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs) 395ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu) 396fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs) 397fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu) 398cd367ff3SPeter Maydell DO_2OP(VMAX_S, vmaxs) 399cd367ff3SPeter Maydell DO_2OP(VMAX_U, vmaxu) 400cd367ff3SPeter Maydell DO_2OP(VMIN_S, vmins) 401cd367ff3SPeter Maydell DO_2OP(VMIN_U, vminu) 402bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds) 403bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu) 404abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds) 405abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu) 406abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs) 407abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu) 408ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs) 409ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu) 410ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts) 411ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu) 412380caf6cSPeter Maydell DO_2OP(VQDMULH, vqdmulh) 413380caf6cSPeter Maydell DO_2OP(VQRDMULH, vqrdmulh) 414f741707bSPeter Maydell DO_2OP(VQADD_S, vqadds) 415f741707bSPeter Maydell DO_2OP(VQADD_U, vqaddu) 416f741707bSPeter Maydell DO_2OP(VQSUB_S, vqsubs) 417f741707bSPeter Maydell DO_2OP(VQSUB_U, vqsubu) 4180372cad8SPeter Maydell DO_2OP(VSHL_S, vshls) 4190372cad8SPeter Maydell DO_2OP(VSHL_U, vshlu) 420bb002345SPeter Maydell DO_2OP(VRSHL_S, vrshls) 421bb002345SPeter Maydell DO_2OP(VRSHL_U, vrshlu) 422483da661SPeter Maydell DO_2OP(VQSHL_S, vqshls) 423483da661SPeter Maydell DO_2OP(VQSHL_U, vqshlu) 4249dc868c4SPeter Maydell DO_2OP(VQRSHL_S, vqrshls) 4259dc868c4SPeter Maydell DO_2OP(VQRSHL_U, vqrshlu) 426fd677f80SPeter Maydell DO_2OP(VQDMLADH, vqdmladh) 427fd677f80SPeter Maydell DO_2OP(VQDMLADHX, vqdmladhx) 428fd677f80SPeter Maydell DO_2OP(VQRDMLADH, vqrdmladh) 429fd677f80SPeter Maydell DO_2OP(VQRDMLADHX, vqrdmladhx) 43092f11732SPeter Maydell DO_2OP(VQDMLSDH, vqdmlsdh) 43192f11732SPeter Maydell DO_2OP(VQDMLSDHX, vqdmlsdhx) 43292f11732SPeter Maydell DO_2OP(VQRDMLSDH, vqrdmlsdh) 43392f11732SPeter Maydell DO_2OP(VQRDMLSDHX, vqrdmlsdhx) 4341eb987a8SPeter Maydell DO_2OP(VRHADD_S, vrhadds) 4351eb987a8SPeter Maydell DO_2OP(VRHADD_U, vrhaddu) 43667ec113bSPeter Maydell /* 43767ec113bSPeter Maydell * VCADD Qd == Qm at size MO_32 is UNPREDICTABLE; we choose not to diagnose 43867ec113bSPeter Maydell * so we can reuse the DO_2OP macro. (Our implementation calculates the 4398625693aSPeter Maydell * "expected" results in this case.) Similarly for VHCADD. 44067ec113bSPeter Maydell */ 44167ec113bSPeter Maydell DO_2OP(VCADD90, vcadd90) 44267ec113bSPeter Maydell DO_2OP(VCADD270, vcadd270) 4438625693aSPeter Maydell DO_2OP(VHCADD90, vhcadd90) 4448625693aSPeter Maydell DO_2OP(VHCADD270, vhcadd270) 4451d2386f7SPeter Maydell 44643364321SPeter Maydell static bool trans_VQDMULLB(DisasContext *s, arg_2op *a) 44743364321SPeter Maydell { 44843364321SPeter Maydell static MVEGenTwoOpFn * const fns[] = { 44943364321SPeter Maydell NULL, 45043364321SPeter Maydell gen_helper_mve_vqdmullbh, 45143364321SPeter Maydell gen_helper_mve_vqdmullbw, 45243364321SPeter Maydell NULL, 45343364321SPeter Maydell }; 45443364321SPeter Maydell if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) { 45543364321SPeter Maydell /* UNPREDICTABLE; we choose to undef */ 45643364321SPeter Maydell return false; 45743364321SPeter Maydell } 45843364321SPeter Maydell return do_2op(s, a, fns[a->size]); 45943364321SPeter Maydell } 46043364321SPeter Maydell 46143364321SPeter Maydell static bool trans_VQDMULLT(DisasContext *s, arg_2op *a) 46243364321SPeter Maydell { 46343364321SPeter Maydell static MVEGenTwoOpFn * const fns[] = { 46443364321SPeter Maydell NULL, 46543364321SPeter Maydell gen_helper_mve_vqdmullth, 46643364321SPeter Maydell gen_helper_mve_vqdmulltw, 46743364321SPeter Maydell NULL, 46843364321SPeter Maydell }; 46943364321SPeter Maydell if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) { 47043364321SPeter Maydell /* UNPREDICTABLE; we choose to undef */ 47143364321SPeter Maydell return false; 47243364321SPeter Maydell } 47343364321SPeter Maydell return do_2op(s, a, fns[a->size]); 47443364321SPeter Maydell } 47543364321SPeter Maydell 476c1bd78cbSPeter Maydell static bool trans_VMULLP_B(DisasContext *s, arg_2op *a) 477c1bd78cbSPeter Maydell { 478c1bd78cbSPeter Maydell /* 479c1bd78cbSPeter Maydell * Note that a->size indicates the output size, ie VMULL.P8 480c1bd78cbSPeter Maydell * is the 8x8->16 operation and a->size is MO_16; VMULL.P16 481c1bd78cbSPeter Maydell * is the 16x16->32 operation and a->size is MO_32. 482c1bd78cbSPeter Maydell */ 483c1bd78cbSPeter Maydell static MVEGenTwoOpFn * const fns[] = { 484c1bd78cbSPeter Maydell NULL, 485c1bd78cbSPeter Maydell gen_helper_mve_vmullpbh, 486c1bd78cbSPeter Maydell gen_helper_mve_vmullpbw, 487c1bd78cbSPeter Maydell NULL, 488c1bd78cbSPeter Maydell }; 489c1bd78cbSPeter Maydell return do_2op(s, a, fns[a->size]); 490c1bd78cbSPeter Maydell } 491c1bd78cbSPeter Maydell 492c1bd78cbSPeter Maydell static bool trans_VMULLP_T(DisasContext *s, arg_2op *a) 493c1bd78cbSPeter Maydell { 494c1bd78cbSPeter Maydell /* a->size is as for trans_VMULLP_B */ 495c1bd78cbSPeter Maydell static MVEGenTwoOpFn * const fns[] = { 496c1bd78cbSPeter Maydell NULL, 497c1bd78cbSPeter Maydell gen_helper_mve_vmullpth, 498c1bd78cbSPeter Maydell gen_helper_mve_vmullptw, 499c1bd78cbSPeter Maydell NULL, 500c1bd78cbSPeter Maydell }; 501c1bd78cbSPeter Maydell return do_2op(s, a, fns[a->size]); 502c1bd78cbSPeter Maydell } 503c1bd78cbSPeter Maydell 50489bc4c4fSPeter Maydell /* 50589bc4c4fSPeter Maydell * VADC and VSBC: these perform an add-with-carry or subtract-with-carry 50689bc4c4fSPeter Maydell * of the 32-bit elements in each lane of the input vectors, where the 50789bc4c4fSPeter Maydell * carry-out of each add is the carry-in of the next. The initial carry 50889bc4c4fSPeter Maydell * input is either fixed (0 for VADCI, 1 for VSBCI) or is from FPSCR.C 50989bc4c4fSPeter Maydell * (for VADC and VSBC); the carry out at the end is written back to FPSCR.C. 51089bc4c4fSPeter Maydell * These insns are subject to beat-wise execution. Partial execution 51189bc4c4fSPeter Maydell * of an I=1 (initial carry input fixed) insn which does not 51289bc4c4fSPeter Maydell * execute the first beat must start with the current FPSCR.NZCV 51389bc4c4fSPeter Maydell * value, not the fixed constant input. 51489bc4c4fSPeter Maydell */ 51589bc4c4fSPeter Maydell static bool trans_VADC(DisasContext *s, arg_2op *a) 51689bc4c4fSPeter Maydell { 51789bc4c4fSPeter Maydell return do_2op(s, a, gen_helper_mve_vadc); 51889bc4c4fSPeter Maydell } 51989bc4c4fSPeter Maydell 52089bc4c4fSPeter Maydell static bool trans_VADCI(DisasContext *s, arg_2op *a) 52189bc4c4fSPeter Maydell { 52289bc4c4fSPeter Maydell if (mve_skip_first_beat(s)) { 52389bc4c4fSPeter Maydell return trans_VADC(s, a); 52489bc4c4fSPeter Maydell } 52589bc4c4fSPeter Maydell return do_2op(s, a, gen_helper_mve_vadci); 52689bc4c4fSPeter Maydell } 52789bc4c4fSPeter Maydell 52889bc4c4fSPeter Maydell static bool trans_VSBC(DisasContext *s, arg_2op *a) 52989bc4c4fSPeter Maydell { 53089bc4c4fSPeter Maydell return do_2op(s, a, gen_helper_mve_vsbc); 53189bc4c4fSPeter Maydell } 53289bc4c4fSPeter Maydell 53389bc4c4fSPeter Maydell static bool trans_VSBCI(DisasContext *s, arg_2op *a) 53489bc4c4fSPeter Maydell { 53589bc4c4fSPeter Maydell if (mve_skip_first_beat(s)) { 53689bc4c4fSPeter Maydell return trans_VSBC(s, a); 53789bc4c4fSPeter Maydell } 53889bc4c4fSPeter Maydell return do_2op(s, a, gen_helper_mve_vsbci); 53989bc4c4fSPeter Maydell } 54089bc4c4fSPeter Maydell 541e51896b3SPeter Maydell static bool do_2op_scalar(DisasContext *s, arg_2scalar *a, 542e51896b3SPeter Maydell MVEGenTwoOpScalarFn fn) 543e51896b3SPeter Maydell { 544e51896b3SPeter Maydell TCGv_ptr qd, qn; 545e51896b3SPeter Maydell TCGv_i32 rm; 546e51896b3SPeter Maydell 547e51896b3SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 548e51896b3SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qn) || 549e51896b3SPeter Maydell !fn) { 550e51896b3SPeter Maydell return false; 551e51896b3SPeter Maydell } 552e51896b3SPeter Maydell if (a->rm == 13 || a->rm == 15) { 553e51896b3SPeter Maydell /* UNPREDICTABLE */ 554e51896b3SPeter Maydell return false; 555e51896b3SPeter Maydell } 556e51896b3SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 557e51896b3SPeter Maydell return true; 558e51896b3SPeter Maydell } 559e51896b3SPeter Maydell 560e51896b3SPeter Maydell qd = mve_qreg_ptr(a->qd); 561e51896b3SPeter Maydell qn = mve_qreg_ptr(a->qn); 562e51896b3SPeter Maydell rm = load_reg(s, a->rm); 563e51896b3SPeter Maydell fn(cpu_env, qd, qn, rm); 564e51896b3SPeter Maydell tcg_temp_free_i32(rm); 565e51896b3SPeter Maydell tcg_temp_free_ptr(qd); 566e51896b3SPeter Maydell tcg_temp_free_ptr(qn); 567e51896b3SPeter Maydell mve_update_eci(s); 568e51896b3SPeter Maydell return true; 569e51896b3SPeter Maydell } 570e51896b3SPeter Maydell 571e51896b3SPeter Maydell #define DO_2OP_SCALAR(INSN, FN) \ 572e51896b3SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2scalar *a) \ 573e51896b3SPeter Maydell { \ 574e51896b3SPeter Maydell static MVEGenTwoOpScalarFn * const fns[] = { \ 575e51896b3SPeter Maydell gen_helper_mve_##FN##b, \ 576e51896b3SPeter Maydell gen_helper_mve_##FN##h, \ 577e51896b3SPeter Maydell gen_helper_mve_##FN##w, \ 578e51896b3SPeter Maydell NULL, \ 579e51896b3SPeter Maydell }; \ 580e51896b3SPeter Maydell return do_2op_scalar(s, a, fns[a->size]); \ 581e51896b3SPeter Maydell } 582e51896b3SPeter Maydell 583e51896b3SPeter Maydell DO_2OP_SCALAR(VADD_scalar, vadd_scalar) 58491a358fdSPeter Maydell DO_2OP_SCALAR(VSUB_scalar, vsub_scalar) 58591a358fdSPeter Maydell DO_2OP_SCALAR(VMUL_scalar, vmul_scalar) 586644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_S_scalar, vhadds_scalar) 587644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_U_scalar, vhaddu_scalar) 588644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_S_scalar, vhsubs_scalar) 589644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_U_scalar, vhsubu_scalar) 59039f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_S_scalar, vqadds_scalar) 59139f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_U_scalar, vqaddu_scalar) 59239f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_S_scalar, vqsubs_scalar) 59339f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_U_scalar, vqsubu_scalar) 59466c05767SPeter Maydell DO_2OP_SCALAR(VQDMULH_scalar, vqdmulh_scalar) 59566c05767SPeter Maydell DO_2OP_SCALAR(VQRDMULH_scalar, vqrdmulh_scalar) 596b050543bSPeter Maydell DO_2OP_SCALAR(VBRSR, vbrsr) 597e51896b3SPeter Maydell 598a8890353SPeter Maydell static bool trans_VQDMULLB_scalar(DisasContext *s, arg_2scalar *a) 599a8890353SPeter Maydell { 600a8890353SPeter Maydell static MVEGenTwoOpScalarFn * const fns[] = { 601a8890353SPeter Maydell NULL, 602a8890353SPeter Maydell gen_helper_mve_vqdmullb_scalarh, 603a8890353SPeter Maydell gen_helper_mve_vqdmullb_scalarw, 604a8890353SPeter Maydell NULL, 605a8890353SPeter Maydell }; 606a8890353SPeter Maydell if (a->qd == a->qn && a->size == MO_32) { 607a8890353SPeter Maydell /* UNPREDICTABLE; we choose to undef */ 608a8890353SPeter Maydell return false; 609a8890353SPeter Maydell } 610a8890353SPeter Maydell return do_2op_scalar(s, a, fns[a->size]); 611a8890353SPeter Maydell } 612a8890353SPeter Maydell 613a8890353SPeter Maydell static bool trans_VQDMULLT_scalar(DisasContext *s, arg_2scalar *a) 614a8890353SPeter Maydell { 615a8890353SPeter Maydell static MVEGenTwoOpScalarFn * const fns[] = { 616a8890353SPeter Maydell NULL, 617a8890353SPeter Maydell gen_helper_mve_vqdmullt_scalarh, 618a8890353SPeter Maydell gen_helper_mve_vqdmullt_scalarw, 619a8890353SPeter Maydell NULL, 620a8890353SPeter Maydell }; 621a8890353SPeter Maydell if (a->qd == a->qn && a->size == MO_32) { 622a8890353SPeter Maydell /* UNPREDICTABLE; we choose to undef */ 623a8890353SPeter Maydell return false; 624a8890353SPeter Maydell } 625a8890353SPeter Maydell return do_2op_scalar(s, a, fns[a->size]); 626a8890353SPeter Maydell } 627a8890353SPeter Maydell 6281d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a, 6291d2386f7SPeter Maydell MVEGenDualAccOpFn *fn) 6301d2386f7SPeter Maydell { 6311d2386f7SPeter Maydell TCGv_ptr qn, qm; 6321d2386f7SPeter Maydell TCGv_i64 rda; 6331d2386f7SPeter Maydell TCGv_i32 rdalo, rdahi; 6341d2386f7SPeter Maydell 6351d2386f7SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 6361d2386f7SPeter Maydell !mve_check_qreg_bank(s, a->qn | a->qm) || 6371d2386f7SPeter Maydell !fn) { 6381d2386f7SPeter Maydell return false; 6391d2386f7SPeter Maydell } 6401d2386f7SPeter Maydell /* 6411d2386f7SPeter Maydell * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related 6421d2386f7SPeter Maydell * encoding; rdalo always has bit 0 clear so cannot be 13 or 15. 6431d2386f7SPeter Maydell */ 6441d2386f7SPeter Maydell if (a->rdahi == 13 || a->rdahi == 15) { 6451d2386f7SPeter Maydell return false; 6461d2386f7SPeter Maydell } 6471d2386f7SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 6481d2386f7SPeter Maydell return true; 6491d2386f7SPeter Maydell } 6501d2386f7SPeter Maydell 6511d2386f7SPeter Maydell qn = mve_qreg_ptr(a->qn); 6521d2386f7SPeter Maydell qm = mve_qreg_ptr(a->qm); 6531d2386f7SPeter Maydell 6541d2386f7SPeter Maydell /* 6551d2386f7SPeter Maydell * This insn is subject to beat-wise execution. Partial execution 6561d2386f7SPeter Maydell * of an A=0 (no-accumulate) insn which does not execute the first 6571d2386f7SPeter Maydell * beat must start with the current rda value, not 0. 6581d2386f7SPeter Maydell */ 6591d2386f7SPeter Maydell if (a->a || mve_skip_first_beat(s)) { 6601d2386f7SPeter Maydell rda = tcg_temp_new_i64(); 6611d2386f7SPeter Maydell rdalo = load_reg(s, a->rdalo); 6621d2386f7SPeter Maydell rdahi = load_reg(s, a->rdahi); 6631d2386f7SPeter Maydell tcg_gen_concat_i32_i64(rda, rdalo, rdahi); 6641d2386f7SPeter Maydell tcg_temp_free_i32(rdalo); 6651d2386f7SPeter Maydell tcg_temp_free_i32(rdahi); 6661d2386f7SPeter Maydell } else { 6671d2386f7SPeter Maydell rda = tcg_const_i64(0); 6681d2386f7SPeter Maydell } 6691d2386f7SPeter Maydell 6701d2386f7SPeter Maydell fn(rda, cpu_env, qn, qm, rda); 6711d2386f7SPeter Maydell tcg_temp_free_ptr(qn); 6721d2386f7SPeter Maydell tcg_temp_free_ptr(qm); 6731d2386f7SPeter Maydell 6741d2386f7SPeter Maydell rdalo = tcg_temp_new_i32(); 6751d2386f7SPeter Maydell rdahi = tcg_temp_new_i32(); 6761d2386f7SPeter Maydell tcg_gen_extrl_i64_i32(rdalo, rda); 6771d2386f7SPeter Maydell tcg_gen_extrh_i64_i32(rdahi, rda); 6781d2386f7SPeter Maydell store_reg(s, a->rdalo, rdalo); 6791d2386f7SPeter Maydell store_reg(s, a->rdahi, rdahi); 6801d2386f7SPeter Maydell tcg_temp_free_i64(rda); 6811d2386f7SPeter Maydell mve_update_eci(s); 6821d2386f7SPeter Maydell return true; 6831d2386f7SPeter Maydell } 6841d2386f7SPeter Maydell 6851d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a) 6861d2386f7SPeter Maydell { 6871d2386f7SPeter Maydell static MVEGenDualAccOpFn * const fns[4][2] = { 6881d2386f7SPeter Maydell { NULL, NULL }, 6891d2386f7SPeter Maydell { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh }, 6901d2386f7SPeter Maydell { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw }, 6911d2386f7SPeter Maydell { NULL, NULL }, 6921d2386f7SPeter Maydell }; 6931d2386f7SPeter Maydell return do_long_dual_acc(s, a, fns[a->size][a->x]); 6941d2386f7SPeter Maydell } 6951d2386f7SPeter Maydell 6961d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a) 6971d2386f7SPeter Maydell { 6981d2386f7SPeter Maydell static MVEGenDualAccOpFn * const fns[4][2] = { 6991d2386f7SPeter Maydell { NULL, NULL }, 7001d2386f7SPeter Maydell { gen_helper_mve_vmlaldavuh, NULL }, 7011d2386f7SPeter Maydell { gen_helper_mve_vmlaldavuw, NULL }, 7021d2386f7SPeter Maydell { NULL, NULL }, 7031d2386f7SPeter Maydell }; 7041d2386f7SPeter Maydell return do_long_dual_acc(s, a, fns[a->size][a->x]); 7051d2386f7SPeter Maydell } 706181cd971SPeter Maydell 707181cd971SPeter Maydell static bool trans_VMLSLDAV(DisasContext *s, arg_vmlaldav *a) 708181cd971SPeter Maydell { 709181cd971SPeter Maydell static MVEGenDualAccOpFn * const fns[4][2] = { 710181cd971SPeter Maydell { NULL, NULL }, 711181cd971SPeter Maydell { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh }, 712181cd971SPeter Maydell { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw }, 713181cd971SPeter Maydell { NULL, NULL }, 714181cd971SPeter Maydell }; 715181cd971SPeter Maydell return do_long_dual_acc(s, a, fns[a->size][a->x]); 716181cd971SPeter Maydell } 71738548747SPeter Maydell 71838548747SPeter Maydell static bool trans_VRMLALDAVH_S(DisasContext *s, arg_vmlaldav *a) 71938548747SPeter Maydell { 72038548747SPeter Maydell static MVEGenDualAccOpFn * const fns[] = { 72138548747SPeter Maydell gen_helper_mve_vrmlaldavhsw, gen_helper_mve_vrmlaldavhxsw, 72238548747SPeter Maydell }; 72338548747SPeter Maydell return do_long_dual_acc(s, a, fns[a->x]); 72438548747SPeter Maydell } 72538548747SPeter Maydell 72638548747SPeter Maydell static bool trans_VRMLALDAVH_U(DisasContext *s, arg_vmlaldav *a) 72738548747SPeter Maydell { 72838548747SPeter Maydell static MVEGenDualAccOpFn * const fns[] = { 72938548747SPeter Maydell gen_helper_mve_vrmlaldavhuw, NULL, 73038548747SPeter Maydell }; 73138548747SPeter Maydell return do_long_dual_acc(s, a, fns[a->x]); 73238548747SPeter Maydell } 73338548747SPeter Maydell 73438548747SPeter Maydell static bool trans_VRMLSLDAVH(DisasContext *s, arg_vmlaldav *a) 73538548747SPeter Maydell { 73638548747SPeter Maydell static MVEGenDualAccOpFn * const fns[] = { 73738548747SPeter Maydell gen_helper_mve_vrmlsldavhsw, gen_helper_mve_vrmlsldavhxsw, 73838548747SPeter Maydell }; 73938548747SPeter Maydell return do_long_dual_acc(s, a, fns[a->x]); 74038548747SPeter Maydell } 741387debdbSPeter Maydell 74255251786SPeter Maydell static void gen_vpst(DisasContext *s, uint32_t mask) 743387debdbSPeter Maydell { 744387debdbSPeter Maydell /* 745387debdbSPeter Maydell * Set the VPR mask fields. We take advantage of MASK01 and MASK23 746387debdbSPeter Maydell * being adjacent fields in the register. 747387debdbSPeter Maydell * 74855251786SPeter Maydell * Updating the masks is not predicated, but it is subject to beat-wise 749387debdbSPeter Maydell * execution, and the mask is updated on the odd-numbered beats. 750387debdbSPeter Maydell * So if PSR.ECI says we should skip beat 1, we mustn't update the 751387debdbSPeter Maydell * 01 mask field. 752387debdbSPeter Maydell */ 75355251786SPeter Maydell TCGv_i32 vpr = load_cpu_field(v7m.vpr); 754387debdbSPeter Maydell switch (s->eci) { 755387debdbSPeter Maydell case ECI_NONE: 756387debdbSPeter Maydell case ECI_A0: 757387debdbSPeter Maydell /* Update both 01 and 23 fields */ 758387debdbSPeter Maydell tcg_gen_deposit_i32(vpr, vpr, 75955251786SPeter Maydell tcg_constant_i32(mask | (mask << 4)), 760387debdbSPeter Maydell R_V7M_VPR_MASK01_SHIFT, 761387debdbSPeter Maydell R_V7M_VPR_MASK01_LENGTH + R_V7M_VPR_MASK23_LENGTH); 762387debdbSPeter Maydell break; 763387debdbSPeter Maydell case ECI_A0A1: 764387debdbSPeter Maydell case ECI_A0A1A2: 765387debdbSPeter Maydell case ECI_A0A1A2B0: 766387debdbSPeter Maydell /* Update only the 23 mask field */ 767387debdbSPeter Maydell tcg_gen_deposit_i32(vpr, vpr, 76855251786SPeter Maydell tcg_constant_i32(mask), 769387debdbSPeter Maydell R_V7M_VPR_MASK23_SHIFT, R_V7M_VPR_MASK23_LENGTH); 770387debdbSPeter Maydell break; 771387debdbSPeter Maydell default: 772387debdbSPeter Maydell g_assert_not_reached(); 773387debdbSPeter Maydell } 774387debdbSPeter Maydell store_cpu_field(vpr, v7m.vpr); 77555251786SPeter Maydell } 77655251786SPeter Maydell 77755251786SPeter Maydell static bool trans_VPST(DisasContext *s, arg_VPST *a) 77855251786SPeter Maydell { 77955251786SPeter Maydell /* mask == 0 is a "related encoding" */ 78055251786SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || !a->mask) { 78155251786SPeter Maydell return false; 78255251786SPeter Maydell } 78355251786SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 78455251786SPeter Maydell return true; 78555251786SPeter Maydell } 78655251786SPeter Maydell gen_vpst(s, a->mask); 787387debdbSPeter Maydell mve_update_and_store_eci(s); 788387debdbSPeter Maydell return true; 789387debdbSPeter Maydell } 7906f060a63SPeter Maydell 7916f060a63SPeter Maydell static bool trans_VADDV(DisasContext *s, arg_VADDV *a) 7926f060a63SPeter Maydell { 7936f060a63SPeter Maydell /* VADDV: vector add across vector */ 7946f060a63SPeter Maydell static MVEGenVADDVFn * const fns[4][2] = { 7956f060a63SPeter Maydell { gen_helper_mve_vaddvsb, gen_helper_mve_vaddvub }, 7966f060a63SPeter Maydell { gen_helper_mve_vaddvsh, gen_helper_mve_vaddvuh }, 7976f060a63SPeter Maydell { gen_helper_mve_vaddvsw, gen_helper_mve_vaddvuw }, 7986f060a63SPeter Maydell { NULL, NULL } 7996f060a63SPeter Maydell }; 8006f060a63SPeter Maydell TCGv_ptr qm; 8016f060a63SPeter Maydell TCGv_i32 rda; 8026f060a63SPeter Maydell 8036f060a63SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 8046f060a63SPeter Maydell a->size == 3) { 8056f060a63SPeter Maydell return false; 8066f060a63SPeter Maydell } 8076f060a63SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 8086f060a63SPeter Maydell return true; 8096f060a63SPeter Maydell } 8106f060a63SPeter Maydell 8116f060a63SPeter Maydell /* 8126f060a63SPeter Maydell * This insn is subject to beat-wise execution. Partial execution 8136f060a63SPeter Maydell * of an A=0 (no-accumulate) insn which does not execute the first 8146f060a63SPeter Maydell * beat must start with the current value of Rda, not zero. 8156f060a63SPeter Maydell */ 8166f060a63SPeter Maydell if (a->a || mve_skip_first_beat(s)) { 8176f060a63SPeter Maydell /* Accumulate input from Rda */ 8186f060a63SPeter Maydell rda = load_reg(s, a->rda); 8196f060a63SPeter Maydell } else { 8206f060a63SPeter Maydell /* Accumulate starting at zero */ 8216f060a63SPeter Maydell rda = tcg_const_i32(0); 8226f060a63SPeter Maydell } 8236f060a63SPeter Maydell 8246f060a63SPeter Maydell qm = mve_qreg_ptr(a->qm); 8256f060a63SPeter Maydell fns[a->size][a->u](rda, cpu_env, qm, rda); 8266f060a63SPeter Maydell store_reg(s, a->rda, rda); 8276f060a63SPeter Maydell tcg_temp_free_ptr(qm); 8286f060a63SPeter Maydell 8296f060a63SPeter Maydell mve_update_eci(s); 8306f060a63SPeter Maydell return true; 8316f060a63SPeter Maydell } 832eab84139SPeter Maydell 833d43ebd9dSPeter Maydell static bool trans_VADDLV(DisasContext *s, arg_VADDLV *a) 834d43ebd9dSPeter Maydell { 835d43ebd9dSPeter Maydell /* 836d43ebd9dSPeter Maydell * Vector Add Long Across Vector: accumulate the 32-bit 837d43ebd9dSPeter Maydell * elements of the vector into a 64-bit result stored in 838d43ebd9dSPeter Maydell * a pair of general-purpose registers. 839d43ebd9dSPeter Maydell * No need to check Qm's bank: it is only 3 bits in decode. 840d43ebd9dSPeter Maydell */ 841d43ebd9dSPeter Maydell TCGv_ptr qm; 842d43ebd9dSPeter Maydell TCGv_i64 rda; 843d43ebd9dSPeter Maydell TCGv_i32 rdalo, rdahi; 844d43ebd9dSPeter Maydell 845d43ebd9dSPeter Maydell if (!dc_isar_feature(aa32_mve, s)) { 846d43ebd9dSPeter Maydell return false; 847d43ebd9dSPeter Maydell } 848d43ebd9dSPeter Maydell /* 849d43ebd9dSPeter Maydell * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related 850d43ebd9dSPeter Maydell * encoding; rdalo always has bit 0 clear so cannot be 13 or 15. 851d43ebd9dSPeter Maydell */ 852d43ebd9dSPeter Maydell if (a->rdahi == 13 || a->rdahi == 15) { 853d43ebd9dSPeter Maydell return false; 854d43ebd9dSPeter Maydell } 855d43ebd9dSPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 856d43ebd9dSPeter Maydell return true; 857d43ebd9dSPeter Maydell } 858d43ebd9dSPeter Maydell 859d43ebd9dSPeter Maydell /* 860d43ebd9dSPeter Maydell * This insn is subject to beat-wise execution. Partial execution 861d43ebd9dSPeter Maydell * of an A=0 (no-accumulate) insn which does not execute the first 862d43ebd9dSPeter Maydell * beat must start with the current value of RdaHi:RdaLo, not zero. 863d43ebd9dSPeter Maydell */ 864d43ebd9dSPeter Maydell if (a->a || mve_skip_first_beat(s)) { 865d43ebd9dSPeter Maydell /* Accumulate input from RdaHi:RdaLo */ 866d43ebd9dSPeter Maydell rda = tcg_temp_new_i64(); 867d43ebd9dSPeter Maydell rdalo = load_reg(s, a->rdalo); 868d43ebd9dSPeter Maydell rdahi = load_reg(s, a->rdahi); 869d43ebd9dSPeter Maydell tcg_gen_concat_i32_i64(rda, rdalo, rdahi); 870d43ebd9dSPeter Maydell tcg_temp_free_i32(rdalo); 871d43ebd9dSPeter Maydell tcg_temp_free_i32(rdahi); 872d43ebd9dSPeter Maydell } else { 873d43ebd9dSPeter Maydell /* Accumulate starting at zero */ 874d43ebd9dSPeter Maydell rda = tcg_const_i64(0); 875d43ebd9dSPeter Maydell } 876d43ebd9dSPeter Maydell 877d43ebd9dSPeter Maydell qm = mve_qreg_ptr(a->qm); 878d43ebd9dSPeter Maydell if (a->u) { 879d43ebd9dSPeter Maydell gen_helper_mve_vaddlv_u(rda, cpu_env, qm, rda); 880d43ebd9dSPeter Maydell } else { 881d43ebd9dSPeter Maydell gen_helper_mve_vaddlv_s(rda, cpu_env, qm, rda); 882d43ebd9dSPeter Maydell } 883d43ebd9dSPeter Maydell tcg_temp_free_ptr(qm); 884d43ebd9dSPeter Maydell 885d43ebd9dSPeter Maydell rdalo = tcg_temp_new_i32(); 886d43ebd9dSPeter Maydell rdahi = tcg_temp_new_i32(); 887d43ebd9dSPeter Maydell tcg_gen_extrl_i64_i32(rdalo, rda); 888d43ebd9dSPeter Maydell tcg_gen_extrh_i64_i32(rdahi, rda); 889d43ebd9dSPeter Maydell store_reg(s, a->rdalo, rdalo); 890d43ebd9dSPeter Maydell store_reg(s, a->rdahi, rdahi); 891d43ebd9dSPeter Maydell tcg_temp_free_i64(rda); 892d43ebd9dSPeter Maydell mve_update_eci(s); 893d43ebd9dSPeter Maydell return true; 894d43ebd9dSPeter Maydell } 895d43ebd9dSPeter Maydell 896eab84139SPeter Maydell static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn) 897eab84139SPeter Maydell { 898eab84139SPeter Maydell TCGv_ptr qd; 899eab84139SPeter Maydell uint64_t imm; 900eab84139SPeter Maydell 901eab84139SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 902eab84139SPeter Maydell !mve_check_qreg_bank(s, a->qd) || 903eab84139SPeter Maydell !fn) { 904eab84139SPeter Maydell return false; 905eab84139SPeter Maydell } 906eab84139SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 907eab84139SPeter Maydell return true; 908eab84139SPeter Maydell } 909eab84139SPeter Maydell 910eab84139SPeter Maydell imm = asimd_imm_const(a->imm, a->cmode, a->op); 911eab84139SPeter Maydell 912eab84139SPeter Maydell qd = mve_qreg_ptr(a->qd); 913eab84139SPeter Maydell fn(cpu_env, qd, tcg_constant_i64(imm)); 914eab84139SPeter Maydell tcg_temp_free_ptr(qd); 915eab84139SPeter Maydell mve_update_eci(s); 916eab84139SPeter Maydell return true; 917eab84139SPeter Maydell } 918eab84139SPeter Maydell 919eab84139SPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a) 920eab84139SPeter Maydell { 921eab84139SPeter Maydell /* Handle decode of cmode/op here between VORR/VBIC/VMOV */ 922eab84139SPeter Maydell MVEGenOneOpImmFn *fn; 923eab84139SPeter Maydell 924eab84139SPeter Maydell if ((a->cmode & 1) && a->cmode < 12) { 925eab84139SPeter Maydell if (a->op) { 926eab84139SPeter Maydell /* 927eab84139SPeter Maydell * For op=1, the immediate will be inverted by asimd_imm_const(), 928eab84139SPeter Maydell * so the VBIC becomes a logical AND operation. 929eab84139SPeter Maydell */ 930eab84139SPeter Maydell fn = gen_helper_mve_vandi; 931eab84139SPeter Maydell } else { 932eab84139SPeter Maydell fn = gen_helper_mve_vorri; 933eab84139SPeter Maydell } 934eab84139SPeter Maydell } else { 935eab84139SPeter Maydell /* There is one unallocated cmode/op combination in this space */ 936eab84139SPeter Maydell if (a->cmode == 15 && a->op == 1) { 937eab84139SPeter Maydell return false; 938eab84139SPeter Maydell } 939eab84139SPeter Maydell /* asimd_imm_const() sorts out VMVNI vs VMOVI for us */ 940eab84139SPeter Maydell fn = gen_helper_mve_vmovi; 941eab84139SPeter Maydell } 942eab84139SPeter Maydell return do_1imm(s, a, fn); 943eab84139SPeter Maydell } 944f9ed6174SPeter Maydell 945f9ed6174SPeter Maydell static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn, 946f9ed6174SPeter Maydell bool negateshift) 947f9ed6174SPeter Maydell { 948f9ed6174SPeter Maydell TCGv_ptr qd, qm; 949f9ed6174SPeter Maydell int shift = a->shift; 950f9ed6174SPeter Maydell 951f9ed6174SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 952f9ed6174SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qm) || 953f9ed6174SPeter Maydell !fn) { 954f9ed6174SPeter Maydell return false; 955f9ed6174SPeter Maydell } 956f9ed6174SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 957f9ed6174SPeter Maydell return true; 958f9ed6174SPeter Maydell } 959f9ed6174SPeter Maydell 960f9ed6174SPeter Maydell /* 961f9ed6174SPeter Maydell * When we handle a right shift insn using a left-shift helper 962f9ed6174SPeter Maydell * which permits a negative shift count to indicate a right-shift, 963f9ed6174SPeter Maydell * we must negate the shift count. 964f9ed6174SPeter Maydell */ 965f9ed6174SPeter Maydell if (negateshift) { 966f9ed6174SPeter Maydell shift = -shift; 967f9ed6174SPeter Maydell } 968f9ed6174SPeter Maydell 969f9ed6174SPeter Maydell qd = mve_qreg_ptr(a->qd); 970f9ed6174SPeter Maydell qm = mve_qreg_ptr(a->qm); 971f9ed6174SPeter Maydell fn(cpu_env, qd, qm, tcg_constant_i32(shift)); 972f9ed6174SPeter Maydell tcg_temp_free_ptr(qd); 973f9ed6174SPeter Maydell tcg_temp_free_ptr(qm); 974f9ed6174SPeter Maydell mve_update_eci(s); 975f9ed6174SPeter Maydell return true; 976f9ed6174SPeter Maydell } 977f9ed6174SPeter Maydell 978f9ed6174SPeter Maydell #define DO_2SHIFT(INSN, FN, NEGATESHIFT) \ 979f9ed6174SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2shift *a) \ 980f9ed6174SPeter Maydell { \ 981f9ed6174SPeter Maydell static MVEGenTwoOpShiftFn * const fns[] = { \ 982f9ed6174SPeter Maydell gen_helper_mve_##FN##b, \ 983f9ed6174SPeter Maydell gen_helper_mve_##FN##h, \ 984f9ed6174SPeter Maydell gen_helper_mve_##FN##w, \ 985f9ed6174SPeter Maydell NULL, \ 986f9ed6174SPeter Maydell }; \ 987f9ed6174SPeter Maydell return do_2shift(s, a, fns[a->size], NEGATESHIFT); \ 988f9ed6174SPeter Maydell } 989f9ed6174SPeter Maydell 990f9ed6174SPeter Maydell DO_2SHIFT(VSHLI, vshli_u, false) 991f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_S, vqshli_s, false) 992f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_U, vqshli_u, false) 993f9ed6174SPeter Maydell DO_2SHIFT(VQSHLUI, vqshlui_s, false) 9943394116fSPeter Maydell /* These right shifts use a left-shift helper with negated shift count */ 9953394116fSPeter Maydell DO_2SHIFT(VSHRI_S, vshli_s, true) 9963394116fSPeter Maydell DO_2SHIFT(VSHRI_U, vshli_u, true) 9973394116fSPeter Maydell DO_2SHIFT(VRSHRI_S, vrshli_s, true) 9983394116fSPeter Maydell DO_2SHIFT(VRSHRI_U, vrshli_u, true) 999c2262707SPeter Maydell 1000a78b25faSPeter Maydell DO_2SHIFT(VSRI, vsri, false) 1001a78b25faSPeter Maydell DO_2SHIFT(VSLI, vsli, false) 1002a78b25faSPeter Maydell 1003c2262707SPeter Maydell #define DO_VSHLL(INSN, FN) \ 1004c2262707SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2shift *a) \ 1005c2262707SPeter Maydell { \ 1006c2262707SPeter Maydell static MVEGenTwoOpShiftFn * const fns[] = { \ 1007c2262707SPeter Maydell gen_helper_mve_##FN##b, \ 1008c2262707SPeter Maydell gen_helper_mve_##FN##h, \ 1009c2262707SPeter Maydell }; \ 1010c2262707SPeter Maydell return do_2shift(s, a, fns[a->size], false); \ 1011c2262707SPeter Maydell } 1012c2262707SPeter Maydell 1013c2262707SPeter Maydell DO_VSHLL(VSHLL_BS, vshllbs) 1014c2262707SPeter Maydell DO_VSHLL(VSHLL_BU, vshllbu) 1015c2262707SPeter Maydell DO_VSHLL(VSHLL_TS, vshllts) 1016c2262707SPeter Maydell DO_VSHLL(VSHLL_TU, vshlltu) 1017162e2655SPeter Maydell 1018162e2655SPeter Maydell #define DO_2SHIFT_N(INSN, FN) \ 1019162e2655SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2shift *a) \ 1020162e2655SPeter Maydell { \ 1021162e2655SPeter Maydell static MVEGenTwoOpShiftFn * const fns[] = { \ 1022162e2655SPeter Maydell gen_helper_mve_##FN##b, \ 1023162e2655SPeter Maydell gen_helper_mve_##FN##h, \ 1024162e2655SPeter Maydell }; \ 1025162e2655SPeter Maydell return do_2shift(s, a, fns[a->size], false); \ 1026162e2655SPeter Maydell } 1027162e2655SPeter Maydell 1028162e2655SPeter Maydell DO_2SHIFT_N(VSHRNB, vshrnb) 1029162e2655SPeter Maydell DO_2SHIFT_N(VSHRNT, vshrnt) 1030162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNB, vrshrnb) 1031162e2655SPeter Maydell DO_2SHIFT_N(VRSHRNT, vrshrnt) 1032d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_S, vqshrnb_s) 1033d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_S, vqshrnt_s) 1034d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNB_U, vqshrnb_u) 1035d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRNT_U, vqshrnt_u) 1036d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNB, vqshrunb) 1037d6f9e011SPeter Maydell DO_2SHIFT_N(VQSHRUNT, vqshrunt) 1038d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_S, vqrshrnb_s) 1039d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_S, vqrshrnt_s) 1040d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNB_U, vqrshrnb_u) 1041d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRNT_U, vqrshrnt_u) 1042d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNB, vqrshrunb) 1043d6f9e011SPeter Maydell DO_2SHIFT_N(VQRSHRUNT, vqrshrunt) 10442e6a4ce0SPeter Maydell 10452e6a4ce0SPeter Maydell static bool trans_VSHLC(DisasContext *s, arg_VSHLC *a) 10462e6a4ce0SPeter Maydell { 10472e6a4ce0SPeter Maydell /* 10482e6a4ce0SPeter Maydell * Whole Vector Left Shift with Carry. The carry is taken 10492e6a4ce0SPeter Maydell * from a general purpose register and written back there. 10502e6a4ce0SPeter Maydell * An imm of 0 means "shift by 32". 10512e6a4ce0SPeter Maydell */ 10522e6a4ce0SPeter Maydell TCGv_ptr qd; 10532e6a4ce0SPeter Maydell TCGv_i32 rdm; 10542e6a4ce0SPeter Maydell 10552e6a4ce0SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) { 10562e6a4ce0SPeter Maydell return false; 10572e6a4ce0SPeter Maydell } 10582e6a4ce0SPeter Maydell if (a->rdm == 13 || a->rdm == 15) { 10592e6a4ce0SPeter Maydell /* CONSTRAINED UNPREDICTABLE: we UNDEF */ 10602e6a4ce0SPeter Maydell return false; 10612e6a4ce0SPeter Maydell } 10622e6a4ce0SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 10632e6a4ce0SPeter Maydell return true; 10642e6a4ce0SPeter Maydell } 10652e6a4ce0SPeter Maydell 10662e6a4ce0SPeter Maydell qd = mve_qreg_ptr(a->qd); 10672e6a4ce0SPeter Maydell rdm = load_reg(s, a->rdm); 10682e6a4ce0SPeter Maydell gen_helper_mve_vshlc(rdm, cpu_env, qd, rdm, tcg_constant_i32(a->imm)); 10692e6a4ce0SPeter Maydell store_reg(s, a->rdm, rdm); 10702e6a4ce0SPeter Maydell tcg_temp_free_ptr(qd); 10712e6a4ce0SPeter Maydell mve_update_eci(s); 10722e6a4ce0SPeter Maydell return true; 10732e6a4ce0SPeter Maydell } 1074395b92d5SPeter Maydell 1075395b92d5SPeter Maydell static bool do_vidup(DisasContext *s, arg_vidup *a, MVEGenVIDUPFn *fn) 1076395b92d5SPeter Maydell { 1077395b92d5SPeter Maydell TCGv_ptr qd; 1078395b92d5SPeter Maydell TCGv_i32 rn; 1079395b92d5SPeter Maydell 1080395b92d5SPeter Maydell /* 1081395b92d5SPeter Maydell * Vector increment/decrement with wrap and duplicate (VIDUP, VDDUP). 1082395b92d5SPeter Maydell * This fills the vector with elements of successively increasing 1083395b92d5SPeter Maydell * or decreasing values, starting from Rn. 1084395b92d5SPeter Maydell */ 1085395b92d5SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) { 1086395b92d5SPeter Maydell return false; 1087395b92d5SPeter Maydell } 1088395b92d5SPeter Maydell if (a->size == MO_64) { 1089395b92d5SPeter Maydell /* size 0b11 is another encoding */ 1090395b92d5SPeter Maydell return false; 1091395b92d5SPeter Maydell } 1092395b92d5SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 1093395b92d5SPeter Maydell return true; 1094395b92d5SPeter Maydell } 1095395b92d5SPeter Maydell 1096395b92d5SPeter Maydell qd = mve_qreg_ptr(a->qd); 1097395b92d5SPeter Maydell rn = load_reg(s, a->rn); 1098395b92d5SPeter Maydell fn(rn, cpu_env, qd, rn, tcg_constant_i32(a->imm)); 1099395b92d5SPeter Maydell store_reg(s, a->rn, rn); 1100395b92d5SPeter Maydell tcg_temp_free_ptr(qd); 1101395b92d5SPeter Maydell mve_update_eci(s); 1102395b92d5SPeter Maydell return true; 1103395b92d5SPeter Maydell } 1104395b92d5SPeter Maydell 1105395b92d5SPeter Maydell static bool do_viwdup(DisasContext *s, arg_viwdup *a, MVEGenVIWDUPFn *fn) 1106395b92d5SPeter Maydell { 1107395b92d5SPeter Maydell TCGv_ptr qd; 1108395b92d5SPeter Maydell TCGv_i32 rn, rm; 1109395b92d5SPeter Maydell 1110395b92d5SPeter Maydell /* 1111395b92d5SPeter Maydell * Vector increment/decrement with wrap and duplicate (VIWDUp, VDWDUP) 1112395b92d5SPeter Maydell * This fills the vector with elements of successively increasing 1113395b92d5SPeter Maydell * or decreasing values, starting from Rn. Rm specifies a point where 1114395b92d5SPeter Maydell * the count wraps back around to 0. The updated offset is written back 1115395b92d5SPeter Maydell * to Rn. 1116395b92d5SPeter Maydell */ 1117395b92d5SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qd)) { 1118395b92d5SPeter Maydell return false; 1119395b92d5SPeter Maydell } 1120395b92d5SPeter Maydell if (!fn || a->rm == 13 || a->rm == 15) { 1121395b92d5SPeter Maydell /* 1122395b92d5SPeter Maydell * size 0b11 is another encoding; Rm == 13 is UNPREDICTABLE; 1123395b92d5SPeter Maydell * Rm == 13 is VIWDUP, VDWDUP. 1124395b92d5SPeter Maydell */ 1125395b92d5SPeter Maydell return false; 1126395b92d5SPeter Maydell } 1127395b92d5SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 1128395b92d5SPeter Maydell return true; 1129395b92d5SPeter Maydell } 1130395b92d5SPeter Maydell 1131395b92d5SPeter Maydell qd = mve_qreg_ptr(a->qd); 1132395b92d5SPeter Maydell rn = load_reg(s, a->rn); 1133395b92d5SPeter Maydell rm = load_reg(s, a->rm); 1134395b92d5SPeter Maydell fn(rn, cpu_env, qd, rn, rm, tcg_constant_i32(a->imm)); 1135395b92d5SPeter Maydell store_reg(s, a->rn, rn); 1136395b92d5SPeter Maydell tcg_temp_free_ptr(qd); 1137395b92d5SPeter Maydell tcg_temp_free_i32(rm); 1138395b92d5SPeter Maydell mve_update_eci(s); 1139395b92d5SPeter Maydell return true; 1140395b92d5SPeter Maydell } 1141395b92d5SPeter Maydell 1142395b92d5SPeter Maydell static bool trans_VIDUP(DisasContext *s, arg_vidup *a) 1143395b92d5SPeter Maydell { 1144395b92d5SPeter Maydell static MVEGenVIDUPFn * const fns[] = { 1145395b92d5SPeter Maydell gen_helper_mve_vidupb, 1146395b92d5SPeter Maydell gen_helper_mve_viduph, 1147395b92d5SPeter Maydell gen_helper_mve_vidupw, 1148395b92d5SPeter Maydell NULL, 1149395b92d5SPeter Maydell }; 1150395b92d5SPeter Maydell return do_vidup(s, a, fns[a->size]); 1151395b92d5SPeter Maydell } 1152395b92d5SPeter Maydell 1153395b92d5SPeter Maydell static bool trans_VDDUP(DisasContext *s, arg_vidup *a) 1154395b92d5SPeter Maydell { 1155395b92d5SPeter Maydell static MVEGenVIDUPFn * const fns[] = { 1156395b92d5SPeter Maydell gen_helper_mve_vidupb, 1157395b92d5SPeter Maydell gen_helper_mve_viduph, 1158395b92d5SPeter Maydell gen_helper_mve_vidupw, 1159395b92d5SPeter Maydell NULL, 1160395b92d5SPeter Maydell }; 1161395b92d5SPeter Maydell /* VDDUP is just like VIDUP but with a negative immediate */ 1162395b92d5SPeter Maydell a->imm = -a->imm; 1163395b92d5SPeter Maydell return do_vidup(s, a, fns[a->size]); 1164395b92d5SPeter Maydell } 1165395b92d5SPeter Maydell 1166395b92d5SPeter Maydell static bool trans_VIWDUP(DisasContext *s, arg_viwdup *a) 1167395b92d5SPeter Maydell { 1168395b92d5SPeter Maydell static MVEGenVIWDUPFn * const fns[] = { 1169395b92d5SPeter Maydell gen_helper_mve_viwdupb, 1170395b92d5SPeter Maydell gen_helper_mve_viwduph, 1171395b92d5SPeter Maydell gen_helper_mve_viwdupw, 1172395b92d5SPeter Maydell NULL, 1173395b92d5SPeter Maydell }; 1174395b92d5SPeter Maydell return do_viwdup(s, a, fns[a->size]); 1175395b92d5SPeter Maydell } 1176395b92d5SPeter Maydell 1177395b92d5SPeter Maydell static bool trans_VDWDUP(DisasContext *s, arg_viwdup *a) 1178395b92d5SPeter Maydell { 1179395b92d5SPeter Maydell static MVEGenVIWDUPFn * const fns[] = { 1180395b92d5SPeter Maydell gen_helper_mve_vdwdupb, 1181395b92d5SPeter Maydell gen_helper_mve_vdwduph, 1182395b92d5SPeter Maydell gen_helper_mve_vdwdupw, 1183395b92d5SPeter Maydell NULL, 1184395b92d5SPeter Maydell }; 1185395b92d5SPeter Maydell return do_viwdup(s, a, fns[a->size]); 1186395b92d5SPeter Maydell } 1187eff5d9a9SPeter Maydell 1188eff5d9a9SPeter Maydell static bool do_vcmp(DisasContext *s, arg_vcmp *a, MVEGenCmpFn *fn) 1189eff5d9a9SPeter Maydell { 1190eff5d9a9SPeter Maydell TCGv_ptr qn, qm; 1191eff5d9a9SPeter Maydell 1192eff5d9a9SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || !mve_check_qreg_bank(s, a->qm) || 1193eff5d9a9SPeter Maydell !fn) { 1194eff5d9a9SPeter Maydell return false; 1195eff5d9a9SPeter Maydell } 1196eff5d9a9SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 1197eff5d9a9SPeter Maydell return true; 1198eff5d9a9SPeter Maydell } 1199eff5d9a9SPeter Maydell 1200eff5d9a9SPeter Maydell qn = mve_qreg_ptr(a->qn); 1201eff5d9a9SPeter Maydell qm = mve_qreg_ptr(a->qm); 1202eff5d9a9SPeter Maydell fn(cpu_env, qn, qm); 1203eff5d9a9SPeter Maydell tcg_temp_free_ptr(qn); 1204eff5d9a9SPeter Maydell tcg_temp_free_ptr(qm); 1205eff5d9a9SPeter Maydell if (a->mask) { 1206eff5d9a9SPeter Maydell /* VPT */ 1207eff5d9a9SPeter Maydell gen_vpst(s, a->mask); 1208eff5d9a9SPeter Maydell } 1209eff5d9a9SPeter Maydell mve_update_eci(s); 1210eff5d9a9SPeter Maydell return true; 1211eff5d9a9SPeter Maydell } 1212eff5d9a9SPeter Maydell 1213*cce81873SPeter Maydell static bool do_vcmp_scalar(DisasContext *s, arg_vcmp_scalar *a, 1214*cce81873SPeter Maydell MVEGenScalarCmpFn *fn) 1215*cce81873SPeter Maydell { 1216*cce81873SPeter Maydell TCGv_ptr qn; 1217*cce81873SPeter Maydell TCGv_i32 rm; 1218*cce81873SPeter Maydell 1219*cce81873SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || !fn || a->rm == 13) { 1220*cce81873SPeter Maydell return false; 1221*cce81873SPeter Maydell } 1222*cce81873SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 1223*cce81873SPeter Maydell return true; 1224*cce81873SPeter Maydell } 1225*cce81873SPeter Maydell 1226*cce81873SPeter Maydell qn = mve_qreg_ptr(a->qn); 1227*cce81873SPeter Maydell if (a->rm == 15) { 1228*cce81873SPeter Maydell /* Encoding Rm=0b1111 means "constant zero" */ 1229*cce81873SPeter Maydell rm = tcg_constant_i32(0); 1230*cce81873SPeter Maydell } else { 1231*cce81873SPeter Maydell rm = load_reg(s, a->rm); 1232*cce81873SPeter Maydell } 1233*cce81873SPeter Maydell fn(cpu_env, qn, rm); 1234*cce81873SPeter Maydell tcg_temp_free_ptr(qn); 1235*cce81873SPeter Maydell tcg_temp_free_i32(rm); 1236*cce81873SPeter Maydell if (a->mask) { 1237*cce81873SPeter Maydell /* VPT */ 1238*cce81873SPeter Maydell gen_vpst(s, a->mask); 1239*cce81873SPeter Maydell } 1240*cce81873SPeter Maydell mve_update_eci(s); 1241*cce81873SPeter Maydell return true; 1242*cce81873SPeter Maydell } 1243*cce81873SPeter Maydell 1244eff5d9a9SPeter Maydell #define DO_VCMP(INSN, FN) \ 1245eff5d9a9SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_vcmp *a) \ 1246eff5d9a9SPeter Maydell { \ 1247eff5d9a9SPeter Maydell static MVEGenCmpFn * const fns[] = { \ 1248eff5d9a9SPeter Maydell gen_helper_mve_##FN##b, \ 1249eff5d9a9SPeter Maydell gen_helper_mve_##FN##h, \ 1250eff5d9a9SPeter Maydell gen_helper_mve_##FN##w, \ 1251eff5d9a9SPeter Maydell NULL, \ 1252eff5d9a9SPeter Maydell }; \ 1253eff5d9a9SPeter Maydell return do_vcmp(s, a, fns[a->size]); \ 1254*cce81873SPeter Maydell } \ 1255*cce81873SPeter Maydell static bool trans_##INSN##_scalar(DisasContext *s, \ 1256*cce81873SPeter Maydell arg_vcmp_scalar *a) \ 1257*cce81873SPeter Maydell { \ 1258*cce81873SPeter Maydell static MVEGenScalarCmpFn * const fns[] = { \ 1259*cce81873SPeter Maydell gen_helper_mve_##FN##_scalarb, \ 1260*cce81873SPeter Maydell gen_helper_mve_##FN##_scalarh, \ 1261*cce81873SPeter Maydell gen_helper_mve_##FN##_scalarw, \ 1262*cce81873SPeter Maydell NULL, \ 1263*cce81873SPeter Maydell }; \ 1264*cce81873SPeter Maydell return do_vcmp_scalar(s, a, fns[a->size]); \ 1265eff5d9a9SPeter Maydell } 1266eff5d9a9SPeter Maydell 1267eff5d9a9SPeter Maydell DO_VCMP(VCMPEQ, vcmpeq) 1268eff5d9a9SPeter Maydell DO_VCMP(VCMPNE, vcmpne) 1269eff5d9a9SPeter Maydell DO_VCMP(VCMPCS, vcmpcs) 1270eff5d9a9SPeter Maydell DO_VCMP(VCMPHI, vcmphi) 1271eff5d9a9SPeter Maydell DO_VCMP(VCMPGE, vcmpge) 1272eff5d9a9SPeter Maydell DO_VCMP(VCMPLT, vcmplt) 1273eff5d9a9SPeter Maydell DO_VCMP(VCMPGT, vcmpgt) 1274eff5d9a9SPeter Maydell DO_VCMP(VCMPLE, vcmple) 1275