16390eed4SPeter Maydell /* 26390eed4SPeter Maydell * ARM translation: M-profile MVE instructions 36390eed4SPeter Maydell * 46390eed4SPeter Maydell * Copyright (c) 2021 Linaro, Ltd. 56390eed4SPeter Maydell * 66390eed4SPeter Maydell * This library is free software; you can redistribute it and/or 76390eed4SPeter Maydell * modify it under the terms of the GNU Lesser General Public 86390eed4SPeter Maydell * License as published by the Free Software Foundation; either 96390eed4SPeter Maydell * version 2.1 of the License, or (at your option) any later version. 106390eed4SPeter Maydell * 116390eed4SPeter Maydell * This library is distributed in the hope that it will be useful, 126390eed4SPeter Maydell * but WITHOUT ANY WARRANTY; without even the implied warranty of 136390eed4SPeter Maydell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 146390eed4SPeter Maydell * Lesser General Public License for more details. 156390eed4SPeter Maydell * 166390eed4SPeter Maydell * You should have received a copy of the GNU Lesser General Public 176390eed4SPeter Maydell * License along with this library; if not, see <http://www.gnu.org/licenses/>. 186390eed4SPeter Maydell */ 196390eed4SPeter Maydell 206390eed4SPeter Maydell #include "qemu/osdep.h" 216390eed4SPeter Maydell #include "tcg/tcg-op.h" 226390eed4SPeter Maydell #include "tcg/tcg-op-gvec.h" 236390eed4SPeter Maydell #include "exec/exec-all.h" 246390eed4SPeter Maydell #include "exec/gen-icount.h" 256390eed4SPeter Maydell #include "translate.h" 266390eed4SPeter Maydell #include "translate-a32.h" 276390eed4SPeter Maydell 286390eed4SPeter Maydell /* Include the generated decoder */ 296390eed4SPeter Maydell #include "decode-mve.c.inc" 30507b6a50SPeter Maydell 31507b6a50SPeter Maydell typedef void MVEGenLdStFn(TCGv_ptr, TCGv_ptr, TCGv_i32); 320f0f2bd5SPeter Maydell typedef void MVEGenOneOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); 3368245e44SPeter Maydell typedef void MVEGenTwoOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr); 34*e51896b3SPeter Maydell typedef void MVEGenTwoOpScalarFn(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32); 351d2386f7SPeter Maydell typedef void MVEGenDualAccOpFn(TCGv_i64, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64); 36507b6a50SPeter Maydell 37507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */ 38507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg) 39507b6a50SPeter Maydell { 40507b6a50SPeter Maydell return offsetof(CPUARMState, vfp.zregs[reg].d[0]); 41507b6a50SPeter Maydell } 42507b6a50SPeter Maydell 43507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg) 44507b6a50SPeter Maydell { 45507b6a50SPeter Maydell TCGv_ptr ret = tcg_temp_new_ptr(); 46507b6a50SPeter Maydell tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg)); 47507b6a50SPeter Maydell return ret; 48507b6a50SPeter Maydell } 49507b6a50SPeter Maydell 50507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask) 51507b6a50SPeter Maydell { 52507b6a50SPeter Maydell /* 53507b6a50SPeter Maydell * Check whether Qregs are in range. For v8.1M only Q0..Q7 54507b6a50SPeter Maydell * are supported, see VFPSmallRegisterBank(). 55507b6a50SPeter Maydell */ 56507b6a50SPeter Maydell return qmask < 8; 57507b6a50SPeter Maydell } 58507b6a50SPeter Maydell 59507b6a50SPeter Maydell static bool mve_eci_check(DisasContext *s) 60507b6a50SPeter Maydell { 61507b6a50SPeter Maydell /* 62507b6a50SPeter Maydell * This is a beatwise insn: check that ECI is valid (not a 63507b6a50SPeter Maydell * reserved value) and note that we are handling it. 64507b6a50SPeter Maydell * Return true if OK, false if we generated an exception. 65507b6a50SPeter Maydell */ 66507b6a50SPeter Maydell s->eci_handled = true; 67507b6a50SPeter Maydell switch (s->eci) { 68507b6a50SPeter Maydell case ECI_NONE: 69507b6a50SPeter Maydell case ECI_A0: 70507b6a50SPeter Maydell case ECI_A0A1: 71507b6a50SPeter Maydell case ECI_A0A1A2: 72507b6a50SPeter Maydell case ECI_A0A1A2B0: 73507b6a50SPeter Maydell return true; 74507b6a50SPeter Maydell default: 75507b6a50SPeter Maydell /* Reserved value: INVSTATE UsageFault */ 76507b6a50SPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(), 77507b6a50SPeter Maydell default_exception_el(s)); 78507b6a50SPeter Maydell return false; 79507b6a50SPeter Maydell } 80507b6a50SPeter Maydell } 81507b6a50SPeter Maydell 82507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s) 83507b6a50SPeter Maydell { 84507b6a50SPeter Maydell /* 85507b6a50SPeter Maydell * The helper function will always update the CPUState field, 86507b6a50SPeter Maydell * so we only need to update the DisasContext field. 87507b6a50SPeter Maydell */ 88507b6a50SPeter Maydell if (s->eci) { 89507b6a50SPeter Maydell s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE; 90507b6a50SPeter Maydell } 91507b6a50SPeter Maydell } 92507b6a50SPeter Maydell 931d2386f7SPeter Maydell static bool mve_skip_first_beat(DisasContext *s) 941d2386f7SPeter Maydell { 951d2386f7SPeter Maydell /* Return true if PSR.ECI says we must skip the first beat of this insn */ 961d2386f7SPeter Maydell switch (s->eci) { 971d2386f7SPeter Maydell case ECI_NONE: 981d2386f7SPeter Maydell return false; 991d2386f7SPeter Maydell case ECI_A0: 1001d2386f7SPeter Maydell case ECI_A0A1: 1011d2386f7SPeter Maydell case ECI_A0A1A2: 1021d2386f7SPeter Maydell case ECI_A0A1A2B0: 1031d2386f7SPeter Maydell return true; 1041d2386f7SPeter Maydell default: 1051d2386f7SPeter Maydell g_assert_not_reached(); 1061d2386f7SPeter Maydell } 1071d2386f7SPeter Maydell } 1081d2386f7SPeter Maydell 109507b6a50SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn) 110507b6a50SPeter Maydell { 111507b6a50SPeter Maydell TCGv_i32 addr; 112507b6a50SPeter Maydell uint32_t offset; 113507b6a50SPeter Maydell TCGv_ptr qreg; 114507b6a50SPeter Maydell 115507b6a50SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 116507b6a50SPeter Maydell !mve_check_qreg_bank(s, a->qd) || 117507b6a50SPeter Maydell !fn) { 118507b6a50SPeter Maydell return false; 119507b6a50SPeter Maydell } 120507b6a50SPeter Maydell 121507b6a50SPeter Maydell /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */ 122507b6a50SPeter Maydell if (a->rn == 15 || (a->rn == 13 && a->w)) { 123507b6a50SPeter Maydell return false; 124507b6a50SPeter Maydell } 125507b6a50SPeter Maydell 126507b6a50SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 127507b6a50SPeter Maydell return true; 128507b6a50SPeter Maydell } 129507b6a50SPeter Maydell 130507b6a50SPeter Maydell offset = a->imm << a->size; 131507b6a50SPeter Maydell if (!a->a) { 132507b6a50SPeter Maydell offset = -offset; 133507b6a50SPeter Maydell } 134507b6a50SPeter Maydell addr = load_reg(s, a->rn); 135507b6a50SPeter Maydell if (a->p) { 136507b6a50SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 137507b6a50SPeter Maydell } 138507b6a50SPeter Maydell 139507b6a50SPeter Maydell qreg = mve_qreg_ptr(a->qd); 140507b6a50SPeter Maydell fn(cpu_env, qreg, addr); 141507b6a50SPeter Maydell tcg_temp_free_ptr(qreg); 142507b6a50SPeter Maydell 143507b6a50SPeter Maydell /* 144507b6a50SPeter Maydell * Writeback always happens after the last beat of the insn, 145507b6a50SPeter Maydell * regardless of predication 146507b6a50SPeter Maydell */ 147507b6a50SPeter Maydell if (a->w) { 148507b6a50SPeter Maydell if (!a->p) { 149507b6a50SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 150507b6a50SPeter Maydell } 151507b6a50SPeter Maydell store_reg(s, a->rn, addr); 152507b6a50SPeter Maydell } else { 153507b6a50SPeter Maydell tcg_temp_free_i32(addr); 154507b6a50SPeter Maydell } 155507b6a50SPeter Maydell mve_update_eci(s); 156507b6a50SPeter Maydell return true; 157507b6a50SPeter Maydell } 158507b6a50SPeter Maydell 159507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a) 160507b6a50SPeter Maydell { 161507b6a50SPeter Maydell static MVEGenLdStFn * const ldstfns[4][2] = { 162507b6a50SPeter Maydell { gen_helper_mve_vstrb, gen_helper_mve_vldrb }, 163507b6a50SPeter Maydell { gen_helper_mve_vstrh, gen_helper_mve_vldrh }, 164507b6a50SPeter Maydell { gen_helper_mve_vstrw, gen_helper_mve_vldrw }, 165507b6a50SPeter Maydell { NULL, NULL } 166507b6a50SPeter Maydell }; 167507b6a50SPeter Maydell return do_ldst(s, a, ldstfns[a->size][a->l]); 168507b6a50SPeter Maydell } 1692fc6b751SPeter Maydell 1702fc6b751SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST) \ 1712fc6b751SPeter Maydell static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a) \ 1722fc6b751SPeter Maydell { \ 1732fc6b751SPeter Maydell static MVEGenLdStFn * const ldstfns[2][2] = { \ 1742fc6b751SPeter Maydell { gen_helper_mve_##ST, gen_helper_mve_##SLD }, \ 1752fc6b751SPeter Maydell { NULL, gen_helper_mve_##ULD }, \ 1762fc6b751SPeter Maydell }; \ 1772fc6b751SPeter Maydell return do_ldst(s, a, ldstfns[a->u][a->l]); \ 1782fc6b751SPeter Maydell } 1792fc6b751SPeter Maydell 1802fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h) 1812fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w) 1822fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w) 1830f0f2bd5SPeter Maydell 184ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a) 185ab59362fSPeter Maydell { 186ab59362fSPeter Maydell TCGv_ptr qd; 187ab59362fSPeter Maydell TCGv_i32 rt; 188ab59362fSPeter Maydell 189ab59362fSPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 190ab59362fSPeter Maydell !mve_check_qreg_bank(s, a->qd)) { 191ab59362fSPeter Maydell return false; 192ab59362fSPeter Maydell } 193ab59362fSPeter Maydell if (a->rt == 13 || a->rt == 15) { 194ab59362fSPeter Maydell /* UNPREDICTABLE; we choose to UNDEF */ 195ab59362fSPeter Maydell return false; 196ab59362fSPeter Maydell } 197ab59362fSPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 198ab59362fSPeter Maydell return true; 199ab59362fSPeter Maydell } 200ab59362fSPeter Maydell 201ab59362fSPeter Maydell qd = mve_qreg_ptr(a->qd); 202ab59362fSPeter Maydell rt = load_reg(s, a->rt); 203ab59362fSPeter Maydell tcg_gen_dup_i32(a->size, rt, rt); 204ab59362fSPeter Maydell gen_helper_mve_vdup(cpu_env, qd, rt); 205ab59362fSPeter Maydell tcg_temp_free_ptr(qd); 206ab59362fSPeter Maydell tcg_temp_free_i32(rt); 207ab59362fSPeter Maydell mve_update_eci(s); 208ab59362fSPeter Maydell return true; 209ab59362fSPeter Maydell } 210ab59362fSPeter Maydell 2110f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn) 2120f0f2bd5SPeter Maydell { 2130f0f2bd5SPeter Maydell TCGv_ptr qd, qm; 2140f0f2bd5SPeter Maydell 2150f0f2bd5SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 2160f0f2bd5SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qm) || 2170f0f2bd5SPeter Maydell !fn) { 2180f0f2bd5SPeter Maydell return false; 2190f0f2bd5SPeter Maydell } 2200f0f2bd5SPeter Maydell 2210f0f2bd5SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 2220f0f2bd5SPeter Maydell return true; 2230f0f2bd5SPeter Maydell } 2240f0f2bd5SPeter Maydell 2250f0f2bd5SPeter Maydell qd = mve_qreg_ptr(a->qd); 2260f0f2bd5SPeter Maydell qm = mve_qreg_ptr(a->qm); 2270f0f2bd5SPeter Maydell fn(cpu_env, qd, qm); 2280f0f2bd5SPeter Maydell tcg_temp_free_ptr(qd); 2290f0f2bd5SPeter Maydell tcg_temp_free_ptr(qm); 2300f0f2bd5SPeter Maydell mve_update_eci(s); 2310f0f2bd5SPeter Maydell return true; 2320f0f2bd5SPeter Maydell } 2330f0f2bd5SPeter Maydell 2340f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN) \ 2350f0f2bd5SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_1op *a) \ 2360f0f2bd5SPeter Maydell { \ 2370f0f2bd5SPeter Maydell static MVEGenOneOpFn * const fns[] = { \ 2380f0f2bd5SPeter Maydell gen_helper_mve_##FN##b, \ 2390f0f2bd5SPeter Maydell gen_helper_mve_##FN##h, \ 2400f0f2bd5SPeter Maydell gen_helper_mve_##FN##w, \ 2410f0f2bd5SPeter Maydell NULL, \ 2420f0f2bd5SPeter Maydell }; \ 2430f0f2bd5SPeter Maydell return do_1op(s, a, fns[a->size]); \ 2440f0f2bd5SPeter Maydell } 2450f0f2bd5SPeter Maydell 2460f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz) 2476437f1f7SPeter Maydell DO_1OP(VCLS, vcls) 24859c91773SPeter Maydell DO_1OP(VABS, vabs) 249399a8c76SPeter Maydell DO_1OP(VNEG, vneg) 250249b5309SPeter Maydell 251249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a) 252249b5309SPeter Maydell { 253249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 254249b5309SPeter Maydell gen_helper_mve_vrev16b, 255249b5309SPeter Maydell NULL, 256249b5309SPeter Maydell NULL, 257249b5309SPeter Maydell NULL, 258249b5309SPeter Maydell }; 259249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 260249b5309SPeter Maydell } 261249b5309SPeter Maydell 262249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a) 263249b5309SPeter Maydell { 264249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 265249b5309SPeter Maydell gen_helper_mve_vrev32b, 266249b5309SPeter Maydell gen_helper_mve_vrev32h, 267249b5309SPeter Maydell NULL, 268249b5309SPeter Maydell NULL, 269249b5309SPeter Maydell }; 270249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 271249b5309SPeter Maydell } 272249b5309SPeter Maydell 273249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a) 274249b5309SPeter Maydell { 275249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 276249b5309SPeter Maydell gen_helper_mve_vrev64b, 277249b5309SPeter Maydell gen_helper_mve_vrev64h, 278249b5309SPeter Maydell gen_helper_mve_vrev64w, 279249b5309SPeter Maydell NULL, 280249b5309SPeter Maydell }; 281249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 282249b5309SPeter Maydell } 2838abd3c80SPeter Maydell 2848abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a) 2858abd3c80SPeter Maydell { 2868abd3c80SPeter Maydell return do_1op(s, a, gen_helper_mve_vmvn); 2878abd3c80SPeter Maydell } 28859c91773SPeter Maydell 28959c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a) 29059c91773SPeter Maydell { 29159c91773SPeter Maydell static MVEGenOneOpFn * const fns[] = { 29259c91773SPeter Maydell NULL, 29359c91773SPeter Maydell gen_helper_mve_vfabsh, 29459c91773SPeter Maydell gen_helper_mve_vfabss, 29559c91773SPeter Maydell NULL, 29659c91773SPeter Maydell }; 29759c91773SPeter Maydell if (!dc_isar_feature(aa32_mve_fp, s)) { 29859c91773SPeter Maydell return false; 29959c91773SPeter Maydell } 30059c91773SPeter Maydell return do_1op(s, a, fns[a->size]); 30159c91773SPeter Maydell } 302399a8c76SPeter Maydell 303399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a) 304399a8c76SPeter Maydell { 305399a8c76SPeter Maydell static MVEGenOneOpFn * const fns[] = { 306399a8c76SPeter Maydell NULL, 307399a8c76SPeter Maydell gen_helper_mve_vfnegh, 308399a8c76SPeter Maydell gen_helper_mve_vfnegs, 309399a8c76SPeter Maydell NULL, 310399a8c76SPeter Maydell }; 311399a8c76SPeter Maydell if (!dc_isar_feature(aa32_mve_fp, s)) { 312399a8c76SPeter Maydell return false; 313399a8c76SPeter Maydell } 314399a8c76SPeter Maydell return do_1op(s, a, fns[a->size]); 315399a8c76SPeter Maydell } 31668245e44SPeter Maydell 31768245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn) 31868245e44SPeter Maydell { 31968245e44SPeter Maydell TCGv_ptr qd, qn, qm; 32068245e44SPeter Maydell 32168245e44SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 32268245e44SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) || 32368245e44SPeter Maydell !fn) { 32468245e44SPeter Maydell return false; 32568245e44SPeter Maydell } 32668245e44SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 32768245e44SPeter Maydell return true; 32868245e44SPeter Maydell } 32968245e44SPeter Maydell 33068245e44SPeter Maydell qd = mve_qreg_ptr(a->qd); 33168245e44SPeter Maydell qn = mve_qreg_ptr(a->qn); 33268245e44SPeter Maydell qm = mve_qreg_ptr(a->qm); 33368245e44SPeter Maydell fn(cpu_env, qd, qn, qm); 33468245e44SPeter Maydell tcg_temp_free_ptr(qd); 33568245e44SPeter Maydell tcg_temp_free_ptr(qn); 33668245e44SPeter Maydell tcg_temp_free_ptr(qm); 33768245e44SPeter Maydell mve_update_eci(s); 33868245e44SPeter Maydell return true; 33968245e44SPeter Maydell } 34068245e44SPeter Maydell 34168245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER) \ 34268245e44SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2op *a) \ 34368245e44SPeter Maydell { \ 34468245e44SPeter Maydell return do_2op(s, a, HELPER); \ 34568245e44SPeter Maydell } 34668245e44SPeter Maydell 34768245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand) 34868245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic) 34968245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr) 35068245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn) 35168245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor) 3529333fe4dSPeter Maydell 3539333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \ 3549333fe4dSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2op *a) \ 3559333fe4dSPeter Maydell { \ 3569333fe4dSPeter Maydell static MVEGenTwoOpFn * const fns[] = { \ 3579333fe4dSPeter Maydell gen_helper_mve_##FN##b, \ 3589333fe4dSPeter Maydell gen_helper_mve_##FN##h, \ 3599333fe4dSPeter Maydell gen_helper_mve_##FN##w, \ 3609333fe4dSPeter Maydell NULL, \ 3619333fe4dSPeter Maydell }; \ 3629333fe4dSPeter Maydell return do_2op(s, a, fns[a->size]); \ 3639333fe4dSPeter Maydell } 3649333fe4dSPeter Maydell 3659333fe4dSPeter Maydell DO_2OP(VADD, vadd) 3669333fe4dSPeter Maydell DO_2OP(VSUB, vsub) 3679333fe4dSPeter Maydell DO_2OP(VMUL, vmul) 368ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs) 369ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu) 370fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs) 371fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu) 372cd367ff3SPeter Maydell DO_2OP(VMAX_S, vmaxs) 373cd367ff3SPeter Maydell DO_2OP(VMAX_U, vmaxu) 374cd367ff3SPeter Maydell DO_2OP(VMIN_S, vmins) 375cd367ff3SPeter Maydell DO_2OP(VMIN_U, vminu) 376bc67aa8dSPeter Maydell DO_2OP(VABD_S, vabds) 377bc67aa8dSPeter Maydell DO_2OP(VABD_U, vabdu) 378abc48e31SPeter Maydell DO_2OP(VHADD_S, vhadds) 379abc48e31SPeter Maydell DO_2OP(VHADD_U, vhaddu) 380abc48e31SPeter Maydell DO_2OP(VHSUB_S, vhsubs) 381abc48e31SPeter Maydell DO_2OP(VHSUB_U, vhsubu) 382ac6ad1dcSPeter Maydell DO_2OP(VMULL_BS, vmullbs) 383ac6ad1dcSPeter Maydell DO_2OP(VMULL_BU, vmullbu) 384ac6ad1dcSPeter Maydell DO_2OP(VMULL_TS, vmullts) 385ac6ad1dcSPeter Maydell DO_2OP(VMULL_TU, vmulltu) 3861d2386f7SPeter Maydell 387*e51896b3SPeter Maydell static bool do_2op_scalar(DisasContext *s, arg_2scalar *a, 388*e51896b3SPeter Maydell MVEGenTwoOpScalarFn fn) 389*e51896b3SPeter Maydell { 390*e51896b3SPeter Maydell TCGv_ptr qd, qn; 391*e51896b3SPeter Maydell TCGv_i32 rm; 392*e51896b3SPeter Maydell 393*e51896b3SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 394*e51896b3SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qn) || 395*e51896b3SPeter Maydell !fn) { 396*e51896b3SPeter Maydell return false; 397*e51896b3SPeter Maydell } 398*e51896b3SPeter Maydell if (a->rm == 13 || a->rm == 15) { 399*e51896b3SPeter Maydell /* UNPREDICTABLE */ 400*e51896b3SPeter Maydell return false; 401*e51896b3SPeter Maydell } 402*e51896b3SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 403*e51896b3SPeter Maydell return true; 404*e51896b3SPeter Maydell } 405*e51896b3SPeter Maydell 406*e51896b3SPeter Maydell qd = mve_qreg_ptr(a->qd); 407*e51896b3SPeter Maydell qn = mve_qreg_ptr(a->qn); 408*e51896b3SPeter Maydell rm = load_reg(s, a->rm); 409*e51896b3SPeter Maydell fn(cpu_env, qd, qn, rm); 410*e51896b3SPeter Maydell tcg_temp_free_i32(rm); 411*e51896b3SPeter Maydell tcg_temp_free_ptr(qd); 412*e51896b3SPeter Maydell tcg_temp_free_ptr(qn); 413*e51896b3SPeter Maydell mve_update_eci(s); 414*e51896b3SPeter Maydell return true; 415*e51896b3SPeter Maydell } 416*e51896b3SPeter Maydell 417*e51896b3SPeter Maydell #define DO_2OP_SCALAR(INSN, FN) \ 418*e51896b3SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2scalar *a) \ 419*e51896b3SPeter Maydell { \ 420*e51896b3SPeter Maydell static MVEGenTwoOpScalarFn * const fns[] = { \ 421*e51896b3SPeter Maydell gen_helper_mve_##FN##b, \ 422*e51896b3SPeter Maydell gen_helper_mve_##FN##h, \ 423*e51896b3SPeter Maydell gen_helper_mve_##FN##w, \ 424*e51896b3SPeter Maydell NULL, \ 425*e51896b3SPeter Maydell }; \ 426*e51896b3SPeter Maydell return do_2op_scalar(s, a, fns[a->size]); \ 427*e51896b3SPeter Maydell } 428*e51896b3SPeter Maydell 429*e51896b3SPeter Maydell DO_2OP_SCALAR(VADD_scalar, vadd_scalar) 430*e51896b3SPeter Maydell 4311d2386f7SPeter Maydell static bool do_long_dual_acc(DisasContext *s, arg_vmlaldav *a, 4321d2386f7SPeter Maydell MVEGenDualAccOpFn *fn) 4331d2386f7SPeter Maydell { 4341d2386f7SPeter Maydell TCGv_ptr qn, qm; 4351d2386f7SPeter Maydell TCGv_i64 rda; 4361d2386f7SPeter Maydell TCGv_i32 rdalo, rdahi; 4371d2386f7SPeter Maydell 4381d2386f7SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 4391d2386f7SPeter Maydell !mve_check_qreg_bank(s, a->qn | a->qm) || 4401d2386f7SPeter Maydell !fn) { 4411d2386f7SPeter Maydell return false; 4421d2386f7SPeter Maydell } 4431d2386f7SPeter Maydell /* 4441d2386f7SPeter Maydell * rdahi == 13 is UNPREDICTABLE; rdahi == 15 is a related 4451d2386f7SPeter Maydell * encoding; rdalo always has bit 0 clear so cannot be 13 or 15. 4461d2386f7SPeter Maydell */ 4471d2386f7SPeter Maydell if (a->rdahi == 13 || a->rdahi == 15) { 4481d2386f7SPeter Maydell return false; 4491d2386f7SPeter Maydell } 4501d2386f7SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 4511d2386f7SPeter Maydell return true; 4521d2386f7SPeter Maydell } 4531d2386f7SPeter Maydell 4541d2386f7SPeter Maydell qn = mve_qreg_ptr(a->qn); 4551d2386f7SPeter Maydell qm = mve_qreg_ptr(a->qm); 4561d2386f7SPeter Maydell 4571d2386f7SPeter Maydell /* 4581d2386f7SPeter Maydell * This insn is subject to beat-wise execution. Partial execution 4591d2386f7SPeter Maydell * of an A=0 (no-accumulate) insn which does not execute the first 4601d2386f7SPeter Maydell * beat must start with the current rda value, not 0. 4611d2386f7SPeter Maydell */ 4621d2386f7SPeter Maydell if (a->a || mve_skip_first_beat(s)) { 4631d2386f7SPeter Maydell rda = tcg_temp_new_i64(); 4641d2386f7SPeter Maydell rdalo = load_reg(s, a->rdalo); 4651d2386f7SPeter Maydell rdahi = load_reg(s, a->rdahi); 4661d2386f7SPeter Maydell tcg_gen_concat_i32_i64(rda, rdalo, rdahi); 4671d2386f7SPeter Maydell tcg_temp_free_i32(rdalo); 4681d2386f7SPeter Maydell tcg_temp_free_i32(rdahi); 4691d2386f7SPeter Maydell } else { 4701d2386f7SPeter Maydell rda = tcg_const_i64(0); 4711d2386f7SPeter Maydell } 4721d2386f7SPeter Maydell 4731d2386f7SPeter Maydell fn(rda, cpu_env, qn, qm, rda); 4741d2386f7SPeter Maydell tcg_temp_free_ptr(qn); 4751d2386f7SPeter Maydell tcg_temp_free_ptr(qm); 4761d2386f7SPeter Maydell 4771d2386f7SPeter Maydell rdalo = tcg_temp_new_i32(); 4781d2386f7SPeter Maydell rdahi = tcg_temp_new_i32(); 4791d2386f7SPeter Maydell tcg_gen_extrl_i64_i32(rdalo, rda); 4801d2386f7SPeter Maydell tcg_gen_extrh_i64_i32(rdahi, rda); 4811d2386f7SPeter Maydell store_reg(s, a->rdalo, rdalo); 4821d2386f7SPeter Maydell store_reg(s, a->rdahi, rdahi); 4831d2386f7SPeter Maydell tcg_temp_free_i64(rda); 4841d2386f7SPeter Maydell mve_update_eci(s); 4851d2386f7SPeter Maydell return true; 4861d2386f7SPeter Maydell } 4871d2386f7SPeter Maydell 4881d2386f7SPeter Maydell static bool trans_VMLALDAV_S(DisasContext *s, arg_vmlaldav *a) 4891d2386f7SPeter Maydell { 4901d2386f7SPeter Maydell static MVEGenDualAccOpFn * const fns[4][2] = { 4911d2386f7SPeter Maydell { NULL, NULL }, 4921d2386f7SPeter Maydell { gen_helper_mve_vmlaldavsh, gen_helper_mve_vmlaldavxsh }, 4931d2386f7SPeter Maydell { gen_helper_mve_vmlaldavsw, gen_helper_mve_vmlaldavxsw }, 4941d2386f7SPeter Maydell { NULL, NULL }, 4951d2386f7SPeter Maydell }; 4961d2386f7SPeter Maydell return do_long_dual_acc(s, a, fns[a->size][a->x]); 4971d2386f7SPeter Maydell } 4981d2386f7SPeter Maydell 4991d2386f7SPeter Maydell static bool trans_VMLALDAV_U(DisasContext *s, arg_vmlaldav *a) 5001d2386f7SPeter Maydell { 5011d2386f7SPeter Maydell static MVEGenDualAccOpFn * const fns[4][2] = { 5021d2386f7SPeter Maydell { NULL, NULL }, 5031d2386f7SPeter Maydell { gen_helper_mve_vmlaldavuh, NULL }, 5041d2386f7SPeter Maydell { gen_helper_mve_vmlaldavuw, NULL }, 5051d2386f7SPeter Maydell { NULL, NULL }, 5061d2386f7SPeter Maydell }; 5071d2386f7SPeter Maydell return do_long_dual_acc(s, a, fns[a->size][a->x]); 5081d2386f7SPeter Maydell } 509181cd971SPeter Maydell 510181cd971SPeter Maydell static bool trans_VMLSLDAV(DisasContext *s, arg_vmlaldav *a) 511181cd971SPeter Maydell { 512181cd971SPeter Maydell static MVEGenDualAccOpFn * const fns[4][2] = { 513181cd971SPeter Maydell { NULL, NULL }, 514181cd971SPeter Maydell { gen_helper_mve_vmlsldavsh, gen_helper_mve_vmlsldavxsh }, 515181cd971SPeter Maydell { gen_helper_mve_vmlsldavsw, gen_helper_mve_vmlsldavxsw }, 516181cd971SPeter Maydell { NULL, NULL }, 517181cd971SPeter Maydell }; 518181cd971SPeter Maydell return do_long_dual_acc(s, a, fns[a->size][a->x]); 519181cd971SPeter Maydell } 52038548747SPeter Maydell 52138548747SPeter Maydell static bool trans_VRMLALDAVH_S(DisasContext *s, arg_vmlaldav *a) 52238548747SPeter Maydell { 52338548747SPeter Maydell static MVEGenDualAccOpFn * const fns[] = { 52438548747SPeter Maydell gen_helper_mve_vrmlaldavhsw, gen_helper_mve_vrmlaldavhxsw, 52538548747SPeter Maydell }; 52638548747SPeter Maydell return do_long_dual_acc(s, a, fns[a->x]); 52738548747SPeter Maydell } 52838548747SPeter Maydell 52938548747SPeter Maydell static bool trans_VRMLALDAVH_U(DisasContext *s, arg_vmlaldav *a) 53038548747SPeter Maydell { 53138548747SPeter Maydell static MVEGenDualAccOpFn * const fns[] = { 53238548747SPeter Maydell gen_helper_mve_vrmlaldavhuw, NULL, 53338548747SPeter Maydell }; 53438548747SPeter Maydell return do_long_dual_acc(s, a, fns[a->x]); 53538548747SPeter Maydell } 53638548747SPeter Maydell 53738548747SPeter Maydell static bool trans_VRMLSLDAVH(DisasContext *s, arg_vmlaldav *a) 53838548747SPeter Maydell { 53938548747SPeter Maydell static MVEGenDualAccOpFn * const fns[] = { 54038548747SPeter Maydell gen_helper_mve_vrmlsldavhsw, gen_helper_mve_vrmlsldavhxsw, 54138548747SPeter Maydell }; 54238548747SPeter Maydell return do_long_dual_acc(s, a, fns[a->x]); 54338548747SPeter Maydell } 544