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); 35*f9ed6174SPeter Maydell typedef void MVEGenTwoOpShiftFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32); 361d2386f7SPeter Maydell typedef void MVEGenDualAccOpFn(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64); 376f060a63SPeter Maydell typedef void MVEGenVADDVFn(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_i32); 38eab84139SPeter Maydell typedef void MVEGenOneOpImmFn(TCGv_ptr, TCGv_ptr, TCGv_i64); 39507b6a50SPeter Maydell 40507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */ 41507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg) 42507b6a50SPeter Maydell { 43507b6a50SPeter Maydell return offsetof(CPUARMState, vfp.zregs[reg].d[0]); 44507b6a50SPeter Maydell } 45507b6a50SPeter Maydell 46507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg) 47507b6a50SPeter Maydell { 48507b6a50SPeter Maydell TCGv_ptr ret = tcg_temp_new_ptr(); 49507b6a50SPeter Maydell tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg)); 50507b6a50SPeter Maydell return ret; 51507b6a50SPeter Maydell } 52507b6a50SPeter Maydell 53507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask) 54507b6a50SPeter Maydell { 55507b6a50SPeter Maydell /* 56507b6a50SPeter Maydell * Check whether Qregs are in range. For v8.1M only Q0..Q7 57507b6a50SPeter Maydell * are supported, see VFPSmallRegisterBank(). 58507b6a50SPeter Maydell */ 59507b6a50SPeter Maydell return qmask < 8; 60507b6a50SPeter Maydell } 61507b6a50SPeter Maydell 624f57ef95SPeter Maydell bool mve_eci_check(DisasContext *s) 63507b6a50SPeter Maydell { 64507b6a50SPeter Maydell /* 65507b6a50SPeter Maydell * This is a beatwise insn: check that ECI is valid (not a 66507b6a50SPeter Maydell * reserved value) and note that we are handling it. 67507b6a50SPeter Maydell * Return true if OK, false if we generated an exception. 68507b6a50SPeter Maydell */ 69507b6a50SPeter Maydell s->eci_handled = true; 70507b6a50SPeter Maydell switch (s->eci) { 71507b6a50SPeter Maydell case ECI_NONE: 72507b6a50SPeter Maydell case ECI_A0: 73507b6a50SPeter Maydell case ECI_A0A1: 74507b6a50SPeter Maydell case ECI_A0A1A2: 75507b6a50SPeter Maydell case ECI_A0A1A2B0: 76507b6a50SPeter Maydell return true; 77507b6a50SPeter Maydell default: 78507b6a50SPeter Maydell /* Reserved value: INVSTATE UsageFault */ 79507b6a50SPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(), 80507b6a50SPeter Maydell default_exception_el(s)); 81507b6a50SPeter Maydell return false; 82507b6a50SPeter Maydell } 83507b6a50SPeter Maydell } 84507b6a50SPeter Maydell 85507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s) 86507b6a50SPeter Maydell { 87507b6a50SPeter Maydell /* 88507b6a50SPeter Maydell * The helper function will always update the CPUState field, 89507b6a50SPeter Maydell * so we only need to update the DisasContext field. 90507b6a50SPeter Maydell */ 91507b6a50SPeter Maydell if (s->eci) { 92507b6a50SPeter Maydell s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE; 93507b6a50SPeter Maydell } 94507b6a50SPeter Maydell } 95507b6a50SPeter Maydell 964f57ef95SPeter Maydell void mve_update_and_store_eci(DisasContext *s) 97387debdbSPeter Maydell { 98387debdbSPeter Maydell /* 99387debdbSPeter Maydell * For insns which don't call a helper function that will call 100387debdbSPeter Maydell * mve_advance_vpt(), this version updates s->eci and also stores 101387debdbSPeter Maydell * it out to the CPUState field. 102387debdbSPeter Maydell */ 103387debdbSPeter Maydell if (s->eci) { 104387debdbSPeter Maydell mve_update_eci(s); 105387debdbSPeter Maydell store_cpu_field(tcg_constant_i32(s->eci << 4), condexec_bits); 106387debdbSPeter Maydell } 107387debdbSPeter Maydell } 108387debdbSPeter Maydell 1091d2386f7SPeter Maydell static bool mve_skip_first_beat(DisasContext *s) 1101d2386f7SPeter Maydell { 1111d2386f7SPeter Maydell /* Return true if PSR.ECI says we must skip the first beat of this insn */ 1121d2386f7SPeter Maydell switch (s->eci) { 1131d2386f7SPeter Maydell case ECI_NONE: 1141d2386f7SPeter Maydell return false; 1151d2386f7SPeter Maydell case ECI_A0: 1161d2386f7SPeter Maydell case ECI_A0A1: 1171d2386f7SPeter Maydell case ECI_A0A1A2: 1181d2386f7SPeter Maydell case ECI_A0A1A2B0: 1191d2386f7SPeter Maydell return true; 1201d2386f7SPeter Maydell default: 1211d2386f7SPeter Maydell g_assert_not_reached(); 1221d2386f7SPeter Maydell } 1231d2386f7SPeter Maydell } 1241d2386f7SPeter Maydell 125d59ccc30SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn, 126d59ccc30SPeter Maydell unsigned msize) 127507b6a50SPeter Maydell { 128507b6a50SPeter Maydell TCGv_i32 addr; 129507b6a50SPeter Maydell uint32_t offset; 130507b6a50SPeter Maydell TCGv_ptr qreg; 131507b6a50SPeter Maydell 132507b6a50SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 133507b6a50SPeter Maydell !mve_check_qreg_bank(s, a->qd) || 134507b6a50SPeter Maydell !fn) { 135507b6a50SPeter Maydell return false; 136507b6a50SPeter Maydell } 137507b6a50SPeter Maydell 138507b6a50SPeter Maydell /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */ 139507b6a50SPeter Maydell if (a->rn == 15 || (a->rn == 13 && a->w)) { 140507b6a50SPeter Maydell return false; 141507b6a50SPeter Maydell } 142507b6a50SPeter Maydell 143507b6a50SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 144507b6a50SPeter Maydell return true; 145507b6a50SPeter Maydell } 146507b6a50SPeter Maydell 147d59ccc30SPeter Maydell offset = a->imm << msize; 148507b6a50SPeter Maydell if (!a->a) { 149507b6a50SPeter Maydell offset = -offset; 150507b6a50SPeter Maydell } 151507b6a50SPeter Maydell addr = load_reg(s, a->rn); 152507b6a50SPeter Maydell if (a->p) { 153507b6a50SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 154507b6a50SPeter Maydell } 155507b6a50SPeter Maydell 156507b6a50SPeter Maydell qreg = mve_qreg_ptr(a->qd); 157507b6a50SPeter Maydell fn(cpu_env, qreg, addr); 158507b6a50SPeter Maydell tcg_temp_free_ptr(qreg); 159507b6a50SPeter Maydell 160507b6a50SPeter Maydell /* 161507b6a50SPeter Maydell * Writeback always happens after the last beat of the insn, 162507b6a50SPeter Maydell * regardless of predication 163507b6a50SPeter Maydell */ 164507b6a50SPeter Maydell if (a->w) { 165507b6a50SPeter Maydell if (!a->p) { 166507b6a50SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 167507b6a50SPeter Maydell } 168507b6a50SPeter Maydell store_reg(s, a->rn, addr); 169507b6a50SPeter Maydell } else { 170507b6a50SPeter Maydell tcg_temp_free_i32(addr); 171507b6a50SPeter Maydell } 172507b6a50SPeter Maydell mve_update_eci(s); 173507b6a50SPeter Maydell return true; 174507b6a50SPeter Maydell } 175507b6a50SPeter Maydell 176507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a) 177507b6a50SPeter Maydell { 178507b6a50SPeter Maydell static MVEGenLdStFn * const ldstfns[4][2] = { 179507b6a50SPeter Maydell { gen_helper_mve_vstrb, gen_helper_mve_vldrb }, 180507b6a50SPeter Maydell { gen_helper_mve_vstrh, gen_helper_mve_vldrh }, 181507b6a50SPeter Maydell { gen_helper_mve_vstrw, gen_helper_mve_vldrw }, 182507b6a50SPeter Maydell { NULL, NULL } 183507b6a50SPeter Maydell }; 184d59ccc30SPeter Maydell return do_ldst(s, a, ldstfns[a->size][a->l], a->size); 185507b6a50SPeter Maydell } 1862fc6b751SPeter Maydell 187d59ccc30SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST, MSIZE) \ 1882fc6b751SPeter Maydell static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a) \ 1892fc6b751SPeter Maydell { \ 1902fc6b751SPeter Maydell static MVEGenLdStFn * const ldstfns[2][2] = { \ 1912fc6b751SPeter Maydell { gen_helper_mve_##ST, gen_helper_mve_##SLD }, \ 1922fc6b751SPeter Maydell { NULL, gen_helper_mve_##ULD }, \ 1932fc6b751SPeter Maydell }; \ 194d59ccc30SPeter Maydell return do_ldst(s, a, ldstfns[a->u][a->l], MSIZE); \ 1952fc6b751SPeter Maydell } 1962fc6b751SPeter Maydell 197d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h, MO_8) 198d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w, MO_8) 199d59ccc30SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w, MO_16) 2000f0f2bd5SPeter Maydell 201ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a) 202ab59362fSPeter Maydell { 203ab59362fSPeter Maydell TCGv_ptr qd; 204ab59362fSPeter Maydell TCGv_i32 rt; 205ab59362fSPeter Maydell 206ab59362fSPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 207ab59362fSPeter Maydell !mve_check_qreg_bank(s, a->qd)) { 208ab59362fSPeter Maydell return false; 209ab59362fSPeter Maydell } 210ab59362fSPeter Maydell if (a->rt == 13 || a->rt == 15) { 211ab59362fSPeter Maydell /* UNPREDICTABLE; we choose to UNDEF */ 212ab59362fSPeter Maydell return false; 213ab59362fSPeter Maydell } 214ab59362fSPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 215ab59362fSPeter Maydell return true; 216ab59362fSPeter Maydell } 217ab59362fSPeter Maydell 218ab59362fSPeter Maydell qd = mve_qreg_ptr(a->qd); 219ab59362fSPeter Maydell rt = load_reg(s, a->rt); 220ab59362fSPeter Maydell tcg_gen_dup_i32(a->size, rt, rt); 221ab59362fSPeter Maydell gen_helper_mve_vdup(cpu_env, qd, rt); 222ab59362fSPeter Maydell tcg_temp_free_ptr(qd); 223ab59362fSPeter Maydell tcg_temp_free_i32(rt); 224ab59362fSPeter Maydell mve_update_eci(s); 225ab59362fSPeter Maydell return true; 226ab59362fSPeter Maydell } 227ab59362fSPeter Maydell 2280f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn) 2290f0f2bd5SPeter Maydell { 2300f0f2bd5SPeter Maydell TCGv_ptr qd, qm; 2310f0f2bd5SPeter Maydell 2320f0f2bd5SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 2330f0f2bd5SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qm) || 2340f0f2bd5SPeter Maydell !fn) { 2350f0f2bd5SPeter Maydell return false; 2360f0f2bd5SPeter Maydell } 2370f0f2bd5SPeter Maydell 2380f0f2bd5SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 2390f0f2bd5SPeter Maydell return true; 2400f0f2bd5SPeter Maydell } 2410f0f2bd5SPeter Maydell 2420f0f2bd5SPeter Maydell qd = mve_qreg_ptr(a->qd); 2430f0f2bd5SPeter Maydell qm = mve_qreg_ptr(a->qm); 2440f0f2bd5SPeter Maydell fn(cpu_env, qd, qm); 2450f0f2bd5SPeter Maydell tcg_temp_free_ptr(qd); 2460f0f2bd5SPeter Maydell tcg_temp_free_ptr(qm); 2470f0f2bd5SPeter Maydell mve_update_eci(s); 2480f0f2bd5SPeter Maydell return true; 2490f0f2bd5SPeter Maydell } 2500f0f2bd5SPeter Maydell 2510f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN) \ 2520f0f2bd5SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_1op *a) \ 2530f0f2bd5SPeter Maydell { \ 2540f0f2bd5SPeter Maydell static MVEGenOneOpFn * const fns[] = { \ 2550f0f2bd5SPeter Maydell gen_helper_mve_##FN##b, \ 2560f0f2bd5SPeter Maydell gen_helper_mve_##FN##h, \ 2570f0f2bd5SPeter Maydell gen_helper_mve_##FN##w, \ 2580f0f2bd5SPeter Maydell NULL, \ 2590f0f2bd5SPeter Maydell }; \ 2600f0f2bd5SPeter Maydell return do_1op(s, a, fns[a->size]); \ 2610f0f2bd5SPeter Maydell } 2620f0f2bd5SPeter Maydell 2630f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz) 2646437f1f7SPeter Maydell DO_1OP(VCLS, vcls) 26559c91773SPeter Maydell DO_1OP(VABS, vabs) 266399a8c76SPeter Maydell DO_1OP(VNEG, vneg) 267249b5309SPeter Maydell 268249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a) 269249b5309SPeter Maydell { 270249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 271249b5309SPeter Maydell gen_helper_mve_vrev16b, 272249b5309SPeter Maydell NULL, 273249b5309SPeter Maydell NULL, 274249b5309SPeter Maydell NULL, 275249b5309SPeter Maydell }; 276249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 277249b5309SPeter Maydell } 278249b5309SPeter Maydell 279249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a) 280249b5309SPeter Maydell { 281249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 282249b5309SPeter Maydell gen_helper_mve_vrev32b, 283249b5309SPeter Maydell gen_helper_mve_vrev32h, 284249b5309SPeter Maydell NULL, 285249b5309SPeter Maydell NULL, 286249b5309SPeter Maydell }; 287249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 288249b5309SPeter Maydell } 289249b5309SPeter Maydell 290249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a) 291249b5309SPeter Maydell { 292249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 293249b5309SPeter Maydell gen_helper_mve_vrev64b, 294249b5309SPeter Maydell gen_helper_mve_vrev64h, 295249b5309SPeter Maydell gen_helper_mve_vrev64w, 296249b5309SPeter Maydell NULL, 297249b5309SPeter Maydell }; 298249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 299249b5309SPeter Maydell } 3008abd3c80SPeter Maydell 3018abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a) 3028abd3c80SPeter Maydell { 3038abd3c80SPeter Maydell return do_1op(s, a, gen_helper_mve_vmvn); 3048abd3c80SPeter Maydell } 30559c91773SPeter Maydell 30659c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a) 30759c91773SPeter Maydell { 30859c91773SPeter Maydell static MVEGenOneOpFn * const fns[] = { 30959c91773SPeter Maydell NULL, 31059c91773SPeter Maydell gen_helper_mve_vfabsh, 31159c91773SPeter Maydell gen_helper_mve_vfabss, 31259c91773SPeter Maydell NULL, 31359c91773SPeter Maydell }; 31459c91773SPeter Maydell if (!dc_isar_feature(aa32_mve_fp, s)) { 31559c91773SPeter Maydell return false; 31659c91773SPeter Maydell } 31759c91773SPeter Maydell return do_1op(s, a, fns[a->size]); 31859c91773SPeter Maydell } 319399a8c76SPeter Maydell 320399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a) 321399a8c76SPeter Maydell { 322399a8c76SPeter Maydell static MVEGenOneOpFn * const fns[] = { 323399a8c76SPeter Maydell NULL, 324399a8c76SPeter Maydell gen_helper_mve_vfnegh, 325399a8c76SPeter Maydell gen_helper_mve_vfnegs, 326399a8c76SPeter Maydell NULL, 327399a8c76SPeter Maydell }; 328399a8c76SPeter Maydell if (!dc_isar_feature(aa32_mve_fp, s)) { 329399a8c76SPeter Maydell return false; 330399a8c76SPeter Maydell } 331399a8c76SPeter Maydell return do_1op(s, a, fns[a->size]); 332399a8c76SPeter Maydell } 33368245e44SPeter Maydell 33468245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn) 33568245e44SPeter Maydell { 33668245e44SPeter Maydell TCGv_ptr qd, qn, qm; 33768245e44SPeter Maydell 33868245e44SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 33968245e44SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) || 34068245e44SPeter Maydell !fn) { 34168245e44SPeter Maydell return false; 34268245e44SPeter Maydell } 34368245e44SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 34468245e44SPeter Maydell return true; 34568245e44SPeter Maydell } 34668245e44SPeter Maydell 34768245e44SPeter Maydell qd = mve_qreg_ptr(a->qd); 34868245e44SPeter Maydell qn = mve_qreg_ptr(a->qn); 34968245e44SPeter Maydell qm = mve_qreg_ptr(a->qm); 35068245e44SPeter Maydell fn(cpu_env, qd, qn, qm); 35168245e44SPeter Maydell tcg_temp_free_ptr(qd); 35268245e44SPeter Maydell tcg_temp_free_ptr(qn); 35368245e44SPeter Maydell tcg_temp_free_ptr(qm); 35468245e44SPeter Maydell mve_update_eci(s); 35568245e44SPeter Maydell return true; 35668245e44SPeter Maydell } 35768245e44SPeter Maydell 35868245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER) \ 35968245e44SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2op *a) \ 36068245e44SPeter Maydell { \ 36168245e44SPeter Maydell return do_2op(s, a, HELPER); \ 36268245e44SPeter Maydell } 36368245e44SPeter Maydell 36468245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand) 36568245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic) 36668245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr) 36768245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn) 36868245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor) 3699333fe4dSPeter Maydell 3709333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \ 3719333fe4dSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2op *a) \ 3729333fe4dSPeter Maydell { \ 3739333fe4dSPeter Maydell static MVEGenTwoOpFn * const fns[] = { \ 3749333fe4dSPeter Maydell gen_helper_mve_##FN##b, \ 3759333fe4dSPeter Maydell gen_helper_mve_##FN##h, \ 3769333fe4dSPeter Maydell gen_helper_mve_##FN##w, \ 3779333fe4dSPeter Maydell NULL, \ 3789333fe4dSPeter Maydell }; \ 3799333fe4dSPeter Maydell return do_2op(s, a, fns[a->size]); \ 3809333fe4dSPeter Maydell } 3819333fe4dSPeter Maydell 3829333fe4dSPeter Maydell DO_2OP(VADD, vadd) 3839333fe4dSPeter Maydell DO_2OP(VSUB, vsub) 3849333fe4dSPeter Maydell DO_2OP(VMUL, vmul) 385ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs) 386ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu) 387fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs) 388fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu) 389cd367ff3SPeter Maydell DO_2OP(VMAX_S, vmaxs) 390cd367ff3SPeter Maydell DO_2OP(VMAX_U, vmaxu) 391cd367ff3SPeter Maydell DO_2OP(VMIN_S, vmins) 392cd367ff3SPeter Maydell DO_2OP(VMIN_U, vminu) 393bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds) 394bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu) 395abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds) 396abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu) 397abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs) 398abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu) 399ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs) 400ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu) 401ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts) 402ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu) 403380caf6cSPeter Maydell DO_2OP(VQDMULH, vqdmulh) 404380caf6cSPeter Maydell DO_2OP(VQRDMULH, vqrdmulh) 405f741707bSPeter Maydell DO_2OP(VQADD_S, vqadds) 406f741707bSPeter Maydell DO_2OP(VQADD_U, vqaddu) 407f741707bSPeter Maydell DO_2OP(VQSUB_S, vqsubs) 408f741707bSPeter Maydell DO_2OP(VQSUB_U, vqsubu) 4090372cad8SPeter Maydell DO_2OP(VSHL_S, vshls) 4100372cad8SPeter Maydell DO_2OP(VSHL_U, vshlu) 411bb002345SPeter Maydell DO_2OP(VRSHL_S, vrshls) 412bb002345SPeter Maydell DO_2OP(VRSHL_U, vrshlu) 413483da661SPeter Maydell DO_2OP(VQSHL_S, vqshls) 414483da661SPeter Maydell DO_2OP(VQSHL_U, vqshlu) 4159dc868c4SPeter Maydell DO_2OP(VQRSHL_S, vqrshls) 4169dc868c4SPeter Maydell DO_2OP(VQRSHL_U, vqrshlu) 417fd677f80SPeter Maydell DO_2OP(VQDMLADH, vqdmladh) 418fd677f80SPeter Maydell DO_2OP(VQDMLADHX, vqdmladhx) 419fd677f80SPeter Maydell DO_2OP(VQRDMLADH, vqrdmladh) 420fd677f80SPeter Maydell DO_2OP(VQRDMLADHX, vqrdmladhx) 42192f11732SPeter Maydell DO_2OP(VQDMLSDH, vqdmlsdh) 42292f11732SPeter Maydell DO_2OP(VQDMLSDHX, vqdmlsdhx) 42392f11732SPeter Maydell DO_2OP(VQRDMLSDH, vqrdmlsdh) 42492f11732SPeter Maydell DO_2OP(VQRDMLSDHX, vqrdmlsdhx) 4251eb987a8SPeter Maydell DO_2OP(VRHADD_S, vrhadds) 4261eb987a8SPeter Maydell DO_2OP(VRHADD_U, vrhaddu) 42767ec113bSPeter Maydell /* 42867ec113bSPeter Maydell * VCADD Qd == Qm at size MO_32 is UNPREDICTABLE; we choose not to diagnose 42967ec113bSPeter Maydell * so we can reuse the DO_2OP macro. (Our implementation calculates the 4308625693aSPeter Maydell * "expected" results in this case.) Similarly for VHCADD. 43167ec113bSPeter Maydell */ 43267ec113bSPeter Maydell DO_2OP(VCADD90, vcadd90) 43367ec113bSPeter Maydell DO_2OP(VCADD270, vcadd270) 4348625693aSPeter Maydell DO_2OP(VHCADD90, vhcadd90) 4358625693aSPeter Maydell DO_2OP(VHCADD270, vhcadd270) 4361d2386f7SPeter Maydell 43743364321SPeter Maydell static bool trans_VQDMULLB(DisasContext *s, arg_2op *a) 43843364321SPeter Maydell { 43943364321SPeter Maydell static MVEGenTwoOpFn * const fns[] = { 44043364321SPeter Maydell NULL, 44143364321SPeter Maydell gen_helper_mve_vqdmullbh, 44243364321SPeter Maydell gen_helper_mve_vqdmullbw, 44343364321SPeter Maydell NULL, 44443364321SPeter Maydell }; 44543364321SPeter Maydell if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) { 44643364321SPeter Maydell /* UNPREDICTABLE; we choose to undef */ 44743364321SPeter Maydell return false; 44843364321SPeter Maydell } 44943364321SPeter Maydell return do_2op(s, a, fns[a->size]); 45043364321SPeter Maydell } 45143364321SPeter Maydell 45243364321SPeter Maydell static bool trans_VQDMULLT(DisasContext *s, arg_2op *a) 45343364321SPeter Maydell { 45443364321SPeter Maydell static MVEGenTwoOpFn * const fns[] = { 45543364321SPeter Maydell NULL, 45643364321SPeter Maydell gen_helper_mve_vqdmullth, 45743364321SPeter Maydell gen_helper_mve_vqdmulltw, 45843364321SPeter Maydell NULL, 45943364321SPeter Maydell }; 46043364321SPeter Maydell if (a->size == MO_32 && (a->qd == a->qm || a->qd == a->qn)) { 46143364321SPeter Maydell /* UNPREDICTABLE; we choose to undef */ 46243364321SPeter Maydell return false; 46343364321SPeter Maydell } 46443364321SPeter Maydell return do_2op(s, a, fns[a->size]); 46543364321SPeter Maydell } 46643364321SPeter Maydell 46789bc4c4fSPeter Maydell /* 46889bc4c4fSPeter Maydell * VADC and VSBC: these perform an add-with-carry or subtract-with-carry 46989bc4c4fSPeter Maydell * of the 32-bit elements in each lane of the input vectors, where the 47089bc4c4fSPeter Maydell * carry-out of each add is the carry-in of the next. The initial carry 47189bc4c4fSPeter Maydell * input is either fixed (0 for VADCI, 1 for VSBCI) or is from FPSCR.C 47289bc4c4fSPeter Maydell * (for VADC and VSBC); the carry out at the end is written back to FPSCR.C. 47389bc4c4fSPeter Maydell * These insns are subject to beat-wise execution. Partial execution 47489bc4c4fSPeter Maydell * of an I=1 (initial carry input fixed) insn which does not 47589bc4c4fSPeter Maydell * execute the first beat must start with the current FPSCR.NZCV 47689bc4c4fSPeter Maydell * value, not the fixed constant input. 47789bc4c4fSPeter Maydell */ 47889bc4c4fSPeter Maydell static bool trans_VADC(DisasContext *s, arg_2op *a) 47989bc4c4fSPeter Maydell { 48089bc4c4fSPeter Maydell return do_2op(s, a, gen_helper_mve_vadc); 48189bc4c4fSPeter Maydell } 48289bc4c4fSPeter Maydell 48389bc4c4fSPeter Maydell static bool trans_VADCI(DisasContext *s, arg_2op *a) 48489bc4c4fSPeter Maydell { 48589bc4c4fSPeter Maydell if (mve_skip_first_beat(s)) { 48689bc4c4fSPeter Maydell return trans_VADC(s, a); 48789bc4c4fSPeter Maydell } 48889bc4c4fSPeter Maydell return do_2op(s, a, gen_helper_mve_vadci); 48989bc4c4fSPeter Maydell } 49089bc4c4fSPeter Maydell 49189bc4c4fSPeter Maydell static bool trans_VSBC(DisasContext *s, arg_2op *a) 49289bc4c4fSPeter Maydell { 49389bc4c4fSPeter Maydell return do_2op(s, a, gen_helper_mve_vsbc); 49489bc4c4fSPeter Maydell } 49589bc4c4fSPeter Maydell 49689bc4c4fSPeter Maydell static bool trans_VSBCI(DisasContext *s, arg_2op *a) 49789bc4c4fSPeter Maydell { 49889bc4c4fSPeter Maydell if (mve_skip_first_beat(s)) { 49989bc4c4fSPeter Maydell return trans_VSBC(s, a); 50089bc4c4fSPeter Maydell } 50189bc4c4fSPeter Maydell return do_2op(s, a, gen_helper_mve_vsbci); 50289bc4c4fSPeter Maydell } 50389bc4c4fSPeter Maydell 504e51896b3SPeter Maydell static bool do_2op_scalar(DisasContext *s, arg_2scalar *a, 505e51896b3SPeter Maydell MVEGenTwoOpScalarFn fn) 506e51896b3SPeter Maydell { 507e51896b3SPeter Maydell TCGv_ptr qd, qn; 508e51896b3SPeter Maydell TCGv_i32 rm; 509e51896b3SPeter Maydell 510e51896b3SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 511e51896b3SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qn) || 512e51896b3SPeter Maydell !fn) { 513e51896b3SPeter Maydell return false; 514e51896b3SPeter Maydell } 515e51896b3SPeter Maydell if (a->rm == 13 || a->rm == 15) { 516e51896b3SPeter Maydell /* UNPREDICTABLE */ 517e51896b3SPeter Maydell return false; 518e51896b3SPeter Maydell } 519e51896b3SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 520e51896b3SPeter Maydell return true; 521e51896b3SPeter Maydell } 522e51896b3SPeter Maydell 523e51896b3SPeter Maydell qd = mve_qreg_ptr(a->qd); 524e51896b3SPeter Maydell qn = mve_qreg_ptr(a->qn); 525e51896b3SPeter Maydell rm = load_reg(s, a->rm); 526e51896b3SPeter Maydell fn(cpu_env, qd, qn, rm); 527e51896b3SPeter Maydell tcg_temp_free_i32(rm); 528e51896b3SPeter Maydell tcg_temp_free_ptr(qd); 529e51896b3SPeter Maydell tcg_temp_free_ptr(qn); 530e51896b3SPeter Maydell mve_update_eci(s); 531e51896b3SPeter Maydell return true; 532e51896b3SPeter Maydell } 533e51896b3SPeter Maydell 534e51896b3SPeter Maydell #define DO_2OP_SCALAR(INSN, FN) \ 535e51896b3SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2scalar *a) \ 536e51896b3SPeter Maydell { \ 537e51896b3SPeter Maydell static MVEGenTwoOpScalarFn * const fns[] = { \ 538e51896b3SPeter Maydell gen_helper_mve_##FN##b, \ 539e51896b3SPeter Maydell gen_helper_mve_##FN##h, \ 540e51896b3SPeter Maydell gen_helper_mve_##FN##w, \ 541e51896b3SPeter Maydell NULL, \ 542e51896b3SPeter Maydell }; \ 543e51896b3SPeter Maydell return do_2op_scalar(s, a, fns[a->size]); \ 544e51896b3SPeter Maydell } 545e51896b3SPeter Maydell 546e51896b3SPeter Maydell DO_2OP_SCALAR(VADD_scalar, vadd_scalar) 54791a358fdSPeter Maydell DO_2OP_SCALAR(VSUB_scalar, vsub_scalar) 54891a358fdSPeter Maydell DO_2OP_SCALAR(VMUL_scalar, vmul_scalar) 549644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_S_scalar, vhadds_scalar) 550644f717cSPeter Maydell DO_2OP_SCALAR(VHADD_U_scalar, vhaddu_scalar) 551644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_S_scalar, vhsubs_scalar) 552644f717cSPeter Maydell DO_2OP_SCALAR(VHSUB_U_scalar, vhsubu_scalar) 55339f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_S_scalar, vqadds_scalar) 55439f2ec85SPeter Maydell DO_2OP_SCALAR(VQADD_U_scalar, vqaddu_scalar) 55539f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_S_scalar, vqsubs_scalar) 55639f2ec85SPeter Maydell DO_2OP_SCALAR(VQSUB_U_scalar, vqsubu_scalar) 55766c05767SPeter Maydell DO_2OP_SCALAR(VQDMULH_scalar, vqdmulh_scalar) 55866c05767SPeter Maydell DO_2OP_SCALAR(VQRDMULH_scalar, vqrdmulh_scalar) 559b050543bSPeter Maydell DO_2OP_SCALAR(VBRSR, vbrsr) 560e51896b3SPeter Maydell 561a8890353SPeter Maydell static bool trans_VQDMULLB_scalar(DisasContext *s, arg_2scalar *a) 562a8890353SPeter Maydell { 563a8890353SPeter Maydell static MVEGenTwoOpScalarFn * const fns[] = { 564a8890353SPeter Maydell NULL, 565a8890353SPeter Maydell gen_helper_mve_vqdmullb_scalarh, 566a8890353SPeter Maydell gen_helper_mve_vqdmullb_scalarw, 567a8890353SPeter Maydell NULL, 568a8890353SPeter Maydell }; 569a8890353SPeter Maydell if (a->qd == a->qn && a->size == MO_32) { 570a8890353SPeter Maydell /* UNPREDICTABLE; we choose to undef */ 571a8890353SPeter Maydell return false; 572a8890353SPeter Maydell } 573a8890353SPeter Maydell return do_2op_scalar(s, a, fns[a->size]); 574a8890353SPeter Maydell } 575a8890353SPeter Maydell 576a8890353SPeter Maydell static bool trans_VQDMULLT_scalar(DisasContext *s, arg_2scalar *a) 577a8890353SPeter Maydell { 578a8890353SPeter Maydell static MVEGenTwoOpScalarFn * const fns[] = { 579a8890353SPeter Maydell NULL, 580a8890353SPeter Maydell gen_helper_mve_vqdmullt_scalarh, 581a8890353SPeter Maydell gen_helper_mve_vqdmullt_scalarw, 582a8890353SPeter Maydell NULL, 583a8890353SPeter Maydell }; 584a8890353SPeter Maydell if (a->qd == a->qn && a->size == MO_32) { 585a8890353SPeter Maydell /* UNPREDICTABLE; we choose to undef */ 586a8890353SPeter Maydell return false; 587a8890353SPeter Maydell } 588a8890353SPeter Maydell return do_2op_scalar(s, a, fns[a->size]); 589a8890353SPeter Maydell } 590a8890353SPeter Maydell 5911d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a, 5921d2386f7SPeter Maydell MVEGenDualAccOpFn *fn) 5931d2386f7SPeter Maydell { 5941d2386f7SPeter Maydell TCGv_ptr qn, qm; 5951d2386f7SPeter Maydell TCGv_i64 rda; 5961d2386f7SPeter Maydell TCGv_i32 rdalo, rdahi; 5971d2386f7SPeter Maydell 5981d2386f7SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 5991d2386f7SPeter Maydell !mve_check_qreg_bank(s, a->qn | a->qm) || 6001d2386f7SPeter Maydell !fn) { 6011d2386f7SPeter Maydell return false; 6021d2386f7SPeter Maydell } 6031d2386f7SPeter Maydell /* 6041d2386f7SPeter Maydell * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related 6051d2386f7SPeter Maydell * encoding; rdalo always has bit 0 clear so cannot be 13 or 15. 6061d2386f7SPeter Maydell */ 6071d2386f7SPeter Maydell if (a->rdahi == 13 || a->rdahi == 15) { 6081d2386f7SPeter Maydell return false; 6091d2386f7SPeter Maydell } 6101d2386f7SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 6111d2386f7SPeter Maydell return true; 6121d2386f7SPeter Maydell } 6131d2386f7SPeter Maydell 6141d2386f7SPeter Maydell qn = mve_qreg_ptr(a->qn); 6151d2386f7SPeter Maydell qm = mve_qreg_ptr(a->qm); 6161d2386f7SPeter Maydell 6171d2386f7SPeter Maydell /* 6181d2386f7SPeter Maydell * This insn is subject to beat-wise execution. Partial execution 6191d2386f7SPeter Maydell * of an A=0 (no-accumulate) insn which does not execute the first 6201d2386f7SPeter Maydell * beat must start with the current rda value, not 0. 6211d2386f7SPeter Maydell */ 6221d2386f7SPeter Maydell if (a->a || mve_skip_first_beat(s)) { 6231d2386f7SPeter Maydell rda = tcg_temp_new_i64(); 6241d2386f7SPeter Maydell rdalo = load_reg(s, a->rdalo); 6251d2386f7SPeter Maydell rdahi = load_reg(s, a->rdahi); 6261d2386f7SPeter Maydell tcg_gen_concat_i32_i64(rda, rdalo, rdahi); 6271d2386f7SPeter Maydell tcg_temp_free_i32(rdalo); 6281d2386f7SPeter Maydell tcg_temp_free_i32(rdahi); 6291d2386f7SPeter Maydell } else { 6301d2386f7SPeter Maydell rda = tcg_const_i64(0); 6311d2386f7SPeter Maydell } 6321d2386f7SPeter Maydell 6331d2386f7SPeter Maydell fn(rda, cpu_env, qn, qm, rda); 6341d2386f7SPeter Maydell tcg_temp_free_ptr(qn); 6351d2386f7SPeter Maydell tcg_temp_free_ptr(qm); 6361d2386f7SPeter Maydell 6371d2386f7SPeter Maydell rdalo = tcg_temp_new_i32(); 6381d2386f7SPeter Maydell rdahi = tcg_temp_new_i32(); 6391d2386f7SPeter Maydell tcg_gen_extrl_i64_i32(rdalo, rda); 6401d2386f7SPeter Maydell tcg_gen_extrh_i64_i32(rdahi, rda); 6411d2386f7SPeter Maydell store_reg(s, a->rdalo, rdalo); 6421d2386f7SPeter Maydell store_reg(s, a->rdahi, rdahi); 6431d2386f7SPeter Maydell tcg_temp_free_i64(rda); 6441d2386f7SPeter Maydell mve_update_eci(s); 6451d2386f7SPeter Maydell return true; 6461d2386f7SPeter Maydell } 6471d2386f7SPeter Maydell 6481d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a) 6491d2386f7SPeter Maydell { 6501d2386f7SPeter Maydell static MVEGenDualAccOpFn * const fns[4][2] = { 6511d2386f7SPeter Maydell { NULL, NULL }, 6521d2386f7SPeter Maydell { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh }, 6531d2386f7SPeter Maydell { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw }, 6541d2386f7SPeter Maydell { NULL, NULL }, 6551d2386f7SPeter Maydell }; 6561d2386f7SPeter Maydell return do_long_dual_acc(s, a, fns[a->size][a->x]); 6571d2386f7SPeter Maydell } 6581d2386f7SPeter Maydell 6591d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a) 6601d2386f7SPeter Maydell { 6611d2386f7SPeter Maydell static MVEGenDualAccOpFn * const fns[4][2] = { 6621d2386f7SPeter Maydell { NULL, NULL }, 6631d2386f7SPeter Maydell { gen_helper_mve_vmlaldavuh, NULL }, 6641d2386f7SPeter Maydell { gen_helper_mve_vmlaldavuw, NULL }, 6651d2386f7SPeter Maydell { NULL, NULL }, 6661d2386f7SPeter Maydell }; 6671d2386f7SPeter Maydell return do_long_dual_acc(s, a, fns[a->size][a->x]); 6681d2386f7SPeter Maydell } 669181cd971SPeter Maydell 670181cd971SPeter Maydell static bool trans_VMLSLDAV(DisasContext *s, arg_vmlaldav *a) 671181cd971SPeter Maydell { 672181cd971SPeter Maydell static MVEGenDualAccOpFn * const fns[4][2] = { 673181cd971SPeter Maydell { NULL, NULL }, 674181cd971SPeter Maydell { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh }, 675181cd971SPeter Maydell { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw }, 676181cd971SPeter Maydell { NULL, NULL }, 677181cd971SPeter Maydell }; 678181cd971SPeter Maydell return do_long_dual_acc(s, a, fns[a->size][a->x]); 679181cd971SPeter Maydell } 68038548747SPeter Maydell 68138548747SPeter Maydell static bool trans_VRMLALDAVH_S(DisasContext *s, arg_vmlaldav *a) 68238548747SPeter Maydell { 68338548747SPeter Maydell static MVEGenDualAccOpFn * const fns[] = { 68438548747SPeter Maydell gen_helper_mve_vrmlaldavhsw, gen_helper_mve_vrmlaldavhxsw, 68538548747SPeter Maydell }; 68638548747SPeter Maydell return do_long_dual_acc(s, a, fns[a->x]); 68738548747SPeter Maydell } 68838548747SPeter Maydell 68938548747SPeter Maydell static bool trans_VRMLALDAVH_U(DisasContext *s, arg_vmlaldav *a) 69038548747SPeter Maydell { 69138548747SPeter Maydell static MVEGenDualAccOpFn * const fns[] = { 69238548747SPeter Maydell gen_helper_mve_vrmlaldavhuw, NULL, 69338548747SPeter Maydell }; 69438548747SPeter Maydell return do_long_dual_acc(s, a, fns[a->x]); 69538548747SPeter Maydell } 69638548747SPeter Maydell 69738548747SPeter Maydell static bool trans_VRMLSLDAVH(DisasContext *s, arg_vmlaldav *a) 69838548747SPeter Maydell { 69938548747SPeter Maydell static MVEGenDualAccOpFn * const fns[] = { 70038548747SPeter Maydell gen_helper_mve_vrmlsldavhsw, gen_helper_mve_vrmlsldavhxsw, 70138548747SPeter Maydell }; 70238548747SPeter Maydell return do_long_dual_acc(s, a, fns[a->x]); 70338548747SPeter Maydell } 704387debdbSPeter Maydell 705387debdbSPeter Maydell static bool trans_VPST(DisasContext *s, arg_VPST *a) 706387debdbSPeter Maydell { 707387debdbSPeter Maydell TCGv_i32 vpr; 708387debdbSPeter Maydell 709387debdbSPeter Maydell /* mask == 0 is a "related encoding" */ 710387debdbSPeter Maydell if (!dc_isar_feature(aa32_mve, s) || !a->mask) { 711387debdbSPeter Maydell return false; 712387debdbSPeter Maydell } 713387debdbSPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 714387debdbSPeter Maydell return true; 715387debdbSPeter Maydell } 716387debdbSPeter Maydell /* 717387debdbSPeter Maydell * Set the VPR mask fields. We take advantage of MASK01 and MASK23 718387debdbSPeter Maydell * being adjacent fields in the register. 719387debdbSPeter Maydell * 720387debdbSPeter Maydell * This insn is not predicated, but it is subject to beat-wise 721387debdbSPeter Maydell * execution, and the mask is updated on the odd-numbered beats. 722387debdbSPeter Maydell * So if PSR.ECI says we should skip beat 1, we mustn't update the 723387debdbSPeter Maydell * 01 mask field. 724387debdbSPeter Maydell */ 725387debdbSPeter Maydell vpr = load_cpu_field(v7m.vpr); 726387debdbSPeter Maydell switch (s->eci) { 727387debdbSPeter Maydell case ECI_NONE: 728387debdbSPeter Maydell case ECI_A0: 729387debdbSPeter Maydell /* Update both 01 and 23 fields */ 730387debdbSPeter Maydell tcg_gen_deposit_i32(vpr, vpr, 731387debdbSPeter Maydell tcg_constant_i32(a->mask | (a->mask << 4)), 732387debdbSPeter Maydell R_V7M_VPR_MASK01_SHIFT, 733387debdbSPeter Maydell R_V7M_VPR_MASK01_LENGTH + R_V7M_VPR_MASK23_LENGTH); 734387debdbSPeter Maydell break; 735387debdbSPeter Maydell case ECI_A0A1: 736387debdbSPeter Maydell case ECI_A0A1A2: 737387debdbSPeter Maydell case ECI_A0A1A2B0: 738387debdbSPeter Maydell /* Update only the 23 mask field */ 739387debdbSPeter Maydell tcg_gen_deposit_i32(vpr, vpr, 740387debdbSPeter Maydell tcg_constant_i32(a->mask), 741387debdbSPeter Maydell R_V7M_VPR_MASK23_SHIFT, R_V7M_VPR_MASK23_LENGTH); 742387debdbSPeter Maydell break; 743387debdbSPeter Maydell default: 744387debdbSPeter Maydell g_assert_not_reached(); 745387debdbSPeter Maydell } 746387debdbSPeter Maydell store_cpu_field(vpr, v7m.vpr); 747387debdbSPeter Maydell mve_update_and_store_eci(s); 748387debdbSPeter Maydell return true; 749387debdbSPeter Maydell } 7506f060a63SPeter Maydell 7516f060a63SPeter Maydell static bool trans_VADDV(DisasContext *s, arg_VADDV *a) 7526f060a63SPeter Maydell { 7536f060a63SPeter Maydell /* VADDV: vector add across vector */ 7546f060a63SPeter Maydell static MVEGenVADDVFn * const fns[4][2] = { 7556f060a63SPeter Maydell { gen_helper_mve_vaddvsb, gen_helper_mve_vaddvub }, 7566f060a63SPeter Maydell { gen_helper_mve_vaddvsh, gen_helper_mve_vaddvuh }, 7576f060a63SPeter Maydell { gen_helper_mve_vaddvsw, gen_helper_mve_vaddvuw }, 7586f060a63SPeter Maydell { NULL, NULL } 7596f060a63SPeter Maydell }; 7606f060a63SPeter Maydell TCGv_ptr qm; 7616f060a63SPeter Maydell TCGv_i32 rda; 7626f060a63SPeter Maydell 7636f060a63SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 7646f060a63SPeter Maydell a->size == 3) { 7656f060a63SPeter Maydell return false; 7666f060a63SPeter Maydell } 7676f060a63SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 7686f060a63SPeter Maydell return true; 7696f060a63SPeter Maydell } 7706f060a63SPeter Maydell 7716f060a63SPeter Maydell /* 7726f060a63SPeter Maydell * This insn is subject to beat-wise execution. Partial execution 7736f060a63SPeter Maydell * of an A=0 (no-accumulate) insn which does not execute the first 7746f060a63SPeter Maydell * beat must start with the current value of Rda, not zero. 7756f060a63SPeter Maydell */ 7766f060a63SPeter Maydell if (a->a || mve_skip_first_beat(s)) { 7776f060a63SPeter Maydell /* Accumulate input from Rda */ 7786f060a63SPeter Maydell rda = load_reg(s, a->rda); 7796f060a63SPeter Maydell } else { 7806f060a63SPeter Maydell /* Accumulate starting at zero */ 7816f060a63SPeter Maydell rda = tcg_const_i32(0); 7826f060a63SPeter Maydell } 7836f060a63SPeter Maydell 7846f060a63SPeter Maydell qm = mve_qreg_ptr(a->qm); 7856f060a63SPeter Maydell fns[a->size][a->u](rda, cpu_env, qm, rda); 7866f060a63SPeter Maydell store_reg(s, a->rda, rda); 7876f060a63SPeter Maydell tcg_temp_free_ptr(qm); 7886f060a63SPeter Maydell 7896f060a63SPeter Maydell mve_update_eci(s); 7906f060a63SPeter Maydell return true; 7916f060a63SPeter Maydell } 792eab84139SPeter Maydell 793eab84139SPeter Maydell static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn) 794eab84139SPeter Maydell { 795eab84139SPeter Maydell TCGv_ptr qd; 796eab84139SPeter Maydell uint64_t imm; 797eab84139SPeter Maydell 798eab84139SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 799eab84139SPeter Maydell !mve_check_qreg_bank(s, a->qd) || 800eab84139SPeter Maydell !fn) { 801eab84139SPeter Maydell return false; 802eab84139SPeter Maydell } 803eab84139SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 804eab84139SPeter Maydell return true; 805eab84139SPeter Maydell } 806eab84139SPeter Maydell 807eab84139SPeter Maydell imm = asimd_imm_const(a->imm, a->cmode, a->op); 808eab84139SPeter Maydell 809eab84139SPeter Maydell qd = mve_qreg_ptr(a->qd); 810eab84139SPeter Maydell fn(cpu_env, qd, tcg_constant_i64(imm)); 811eab84139SPeter Maydell tcg_temp_free_ptr(qd); 812eab84139SPeter Maydell mve_update_eci(s); 813eab84139SPeter Maydell return true; 814eab84139SPeter Maydell } 815eab84139SPeter Maydell 816eab84139SPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a) 817eab84139SPeter Maydell { 818eab84139SPeter Maydell /* Handle decode of cmode/op here between VORR/VBIC/VMOV */ 819eab84139SPeter Maydell MVEGenOneOpImmFn *fn; 820eab84139SPeter Maydell 821eab84139SPeter Maydell if ((a->cmode & 1) && a->cmode < 12) { 822eab84139SPeter Maydell if (a->op) { 823eab84139SPeter Maydell /* 824eab84139SPeter Maydell * For op=1, the immediate will be inverted by asimd_imm_const(), 825eab84139SPeter Maydell * so the VBIC becomes a logical AND operation. 826eab84139SPeter Maydell */ 827eab84139SPeter Maydell fn = gen_helper_mve_vandi; 828eab84139SPeter Maydell } else { 829eab84139SPeter Maydell fn = gen_helper_mve_vorri; 830eab84139SPeter Maydell } 831eab84139SPeter Maydell } else { 832eab84139SPeter Maydell /* There is one unallocated cmode/op combination in this space */ 833eab84139SPeter Maydell if (a->cmode == 15 && a->op == 1) { 834eab84139SPeter Maydell return false; 835eab84139SPeter Maydell } 836eab84139SPeter Maydell /* asimd_imm_const() sorts out VMVNI vs VMOVI for us */ 837eab84139SPeter Maydell fn = gen_helper_mve_vmovi; 838eab84139SPeter Maydell } 839eab84139SPeter Maydell return do_1imm(s, a, fn); 840eab84139SPeter Maydell } 841*f9ed6174SPeter Maydell 842*f9ed6174SPeter Maydell static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn, 843*f9ed6174SPeter Maydell bool negateshift) 844*f9ed6174SPeter Maydell { 845*f9ed6174SPeter Maydell TCGv_ptr qd, qm; 846*f9ed6174SPeter Maydell int shift = a->shift; 847*f9ed6174SPeter Maydell 848*f9ed6174SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 849*f9ed6174SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qm) || 850*f9ed6174SPeter Maydell !fn) { 851*f9ed6174SPeter Maydell return false; 852*f9ed6174SPeter Maydell } 853*f9ed6174SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 854*f9ed6174SPeter Maydell return true; 855*f9ed6174SPeter Maydell } 856*f9ed6174SPeter Maydell 857*f9ed6174SPeter Maydell /* 858*f9ed6174SPeter Maydell * When we handle a right shift insn using a left-shift helper 859*f9ed6174SPeter Maydell * which permits a negative shift count to indicate a right-shift, 860*f9ed6174SPeter Maydell * we must negate the shift count. 861*f9ed6174SPeter Maydell */ 862*f9ed6174SPeter Maydell if (negateshift) { 863*f9ed6174SPeter Maydell shift = -shift; 864*f9ed6174SPeter Maydell } 865*f9ed6174SPeter Maydell 866*f9ed6174SPeter Maydell qd = mve_qreg_ptr(a->qd); 867*f9ed6174SPeter Maydell qm = mve_qreg_ptr(a->qm); 868*f9ed6174SPeter Maydell fn(cpu_env, qd, qm, tcg_constant_i32(shift)); 869*f9ed6174SPeter Maydell tcg_temp_free_ptr(qd); 870*f9ed6174SPeter Maydell tcg_temp_free_ptr(qm); 871*f9ed6174SPeter Maydell mve_update_eci(s); 872*f9ed6174SPeter Maydell return true; 873*f9ed6174SPeter Maydell } 874*f9ed6174SPeter Maydell 875*f9ed6174SPeter Maydell #define DO_2SHIFT(INSN, FN, NEGATESHIFT) \ 876*f9ed6174SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2shift *a) \ 877*f9ed6174SPeter Maydell { \ 878*f9ed6174SPeter Maydell static MVEGenTwoOpShiftFn * const fns[] = { \ 879*f9ed6174SPeter Maydell gen_helper_mve_##FN##b, \ 880*f9ed6174SPeter Maydell gen_helper_mve_##FN##h, \ 881*f9ed6174SPeter Maydell gen_helper_mve_##FN##w, \ 882*f9ed6174SPeter Maydell NULL, \ 883*f9ed6174SPeter Maydell }; \ 884*f9ed6174SPeter Maydell return do_2shift(s, a, fns[a->size], NEGATESHIFT); \ 885*f9ed6174SPeter Maydell } 886*f9ed6174SPeter Maydell 887*f9ed6174SPeter Maydell DO_2SHIFT(VSHLI, vshli_u, false) 888*f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_S, vqshli_s, false) 889*f9ed6174SPeter Maydell DO_2SHIFT(VQSHLI_U, vqshli_u, false) 890*f9ed6174SPeter Maydell DO_2SHIFT(VQSHLUI, vqshlui_s, false) 891