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