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); 34507b6a50SPeter Maydell 35507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */ 36507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg) 37507b6a50SPeter Maydell { 38507b6a50SPeter Maydell return offsetof(CPUARMState, vfp.zregs[reg].d[0]); 39507b6a50SPeter Maydell } 40507b6a50SPeter Maydell 41507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg) 42507b6a50SPeter Maydell { 43507b6a50SPeter Maydell TCGv_ptr ret = tcg_temp_new_ptr(); 44507b6a50SPeter Maydell tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg)); 45507b6a50SPeter Maydell return ret; 46507b6a50SPeter Maydell } 47507b6a50SPeter Maydell 48507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask) 49507b6a50SPeter Maydell { 50507b6a50SPeter Maydell /* 51507b6a50SPeter Maydell * Check whether Qregs are in range. For v8.1M only Q0..Q7 52507b6a50SPeter Maydell * are supported, see VFPSmallRegisterBank(). 53507b6a50SPeter Maydell */ 54507b6a50SPeter Maydell return qmask < 8; 55507b6a50SPeter Maydell } 56507b6a50SPeter Maydell 57507b6a50SPeter Maydell static bool mve_eci_check(DisasContext *s) 58507b6a50SPeter Maydell { 59507b6a50SPeter Maydell /* 60507b6a50SPeter Maydell * This is a beatwise insn: check that ECI is valid (not a 61507b6a50SPeter Maydell * reserved value) and note that we are handling it. 62507b6a50SPeter Maydell * Return true if OK, false if we generated an exception. 63507b6a50SPeter Maydell */ 64507b6a50SPeter Maydell s->eci_handled = true; 65507b6a50SPeter Maydell switch (s->eci) { 66507b6a50SPeter Maydell case ECI_NONE: 67507b6a50SPeter Maydell case ECI_A0: 68507b6a50SPeter Maydell case ECI_A0A1: 69507b6a50SPeter Maydell case ECI_A0A1A2: 70507b6a50SPeter Maydell case ECI_A0A1A2B0: 71507b6a50SPeter Maydell return true; 72507b6a50SPeter Maydell default: 73507b6a50SPeter Maydell /* Reserved value: INVSTATE UsageFault */ 74507b6a50SPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(), 75507b6a50SPeter Maydell default_exception_el(s)); 76507b6a50SPeter Maydell return false; 77507b6a50SPeter Maydell } 78507b6a50SPeter Maydell } 79507b6a50SPeter Maydell 80507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s) 81507b6a50SPeter Maydell { 82507b6a50SPeter Maydell /* 83507b6a50SPeter Maydell * The helper function will always update the CPUState field, 84507b6a50SPeter Maydell * so we only need to update the DisasContext field. 85507b6a50SPeter Maydell */ 86507b6a50SPeter Maydell if (s->eci) { 87507b6a50SPeter Maydell s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE; 88507b6a50SPeter Maydell } 89507b6a50SPeter Maydell } 90507b6a50SPeter Maydell 91507b6a50SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn) 92507b6a50SPeter Maydell { 93507b6a50SPeter Maydell TCGv_i32 addr; 94507b6a50SPeter Maydell uint32_t offset; 95507b6a50SPeter Maydell TCGv_ptr qreg; 96507b6a50SPeter Maydell 97507b6a50SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 98507b6a50SPeter Maydell !mve_check_qreg_bank(s, a->qd) || 99507b6a50SPeter Maydell !fn) { 100507b6a50SPeter Maydell return false; 101507b6a50SPeter Maydell } 102507b6a50SPeter Maydell 103507b6a50SPeter Maydell /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */ 104507b6a50SPeter Maydell if (a->rn == 15 || (a->rn == 13 && a->w)) { 105507b6a50SPeter Maydell return false; 106507b6a50SPeter Maydell } 107507b6a50SPeter Maydell 108507b6a50SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 109507b6a50SPeter Maydell return true; 110507b6a50SPeter Maydell } 111507b6a50SPeter Maydell 112507b6a50SPeter Maydell offset = a->imm << a->size; 113507b6a50SPeter Maydell if (!a->a) { 114507b6a50SPeter Maydell offset = -offset; 115507b6a50SPeter Maydell } 116507b6a50SPeter Maydell addr = load_reg(s, a->rn); 117507b6a50SPeter Maydell if (a->p) { 118507b6a50SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 119507b6a50SPeter Maydell } 120507b6a50SPeter Maydell 121507b6a50SPeter Maydell qreg = mve_qreg_ptr(a->qd); 122507b6a50SPeter Maydell fn(cpu_env, qreg, addr); 123507b6a50SPeter Maydell tcg_temp_free_ptr(qreg); 124507b6a50SPeter Maydell 125507b6a50SPeter Maydell /* 126507b6a50SPeter Maydell * Writeback always happens after the last beat of the insn, 127507b6a50SPeter Maydell * regardless of predication 128507b6a50SPeter Maydell */ 129507b6a50SPeter Maydell if (a->w) { 130507b6a50SPeter Maydell if (!a->p) { 131507b6a50SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 132507b6a50SPeter Maydell } 133507b6a50SPeter Maydell store_reg(s, a->rn, addr); 134507b6a50SPeter Maydell } else { 135507b6a50SPeter Maydell tcg_temp_free_i32(addr); 136507b6a50SPeter Maydell } 137507b6a50SPeter Maydell mve_update_eci(s); 138507b6a50SPeter Maydell return true; 139507b6a50SPeter Maydell } 140507b6a50SPeter Maydell 141507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a) 142507b6a50SPeter Maydell { 143507b6a50SPeter Maydell static MVEGenLdStFn * const ldstfns[4][2] = { 144507b6a50SPeter Maydell { gen_helper_mve_vstrb, gen_helper_mve_vldrb }, 145507b6a50SPeter Maydell { gen_helper_mve_vstrh, gen_helper_mve_vldrh }, 146507b6a50SPeter Maydell { gen_helper_mve_vstrw, gen_helper_mve_vldrw }, 147507b6a50SPeter Maydell { NULL, NULL } 148507b6a50SPeter Maydell }; 149507b6a50SPeter Maydell return do_ldst(s, a, ldstfns[a->size][a->l]); 150507b6a50SPeter Maydell } 1512fc6b751SPeter Maydell 1522fc6b751SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST) \ 1532fc6b751SPeter Maydell static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a) \ 1542fc6b751SPeter Maydell { \ 1552fc6b751SPeter Maydell static MVEGenLdStFn * const ldstfns[2][2] = { \ 1562fc6b751SPeter Maydell { gen_helper_mve_##ST, gen_helper_mve_##SLD }, \ 1572fc6b751SPeter Maydell { NULL, gen_helper_mve_##ULD }, \ 1582fc6b751SPeter Maydell }; \ 1592fc6b751SPeter Maydell return do_ldst(s, a, ldstfns[a->u][a->l]); \ 1602fc6b751SPeter Maydell } 1612fc6b751SPeter Maydell 1622fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h) 1632fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w) 1642fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w) 1650f0f2bd5SPeter Maydell 166ab59362fSPeter Maydell static bool trans_VDUP(DisasContext *s, arg_VDUP *a) 167ab59362fSPeter Maydell { 168ab59362fSPeter Maydell TCGv_ptr qd; 169ab59362fSPeter Maydell TCGv_i32 rt; 170ab59362fSPeter Maydell 171ab59362fSPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 172ab59362fSPeter Maydell !mve_check_qreg_bank(s, a->qd)) { 173ab59362fSPeter Maydell return false; 174ab59362fSPeter Maydell } 175ab59362fSPeter Maydell if (a->rt == 13 || a->rt == 15) { 176ab59362fSPeter Maydell /* UNPREDICTABLE; we choose to UNDEF */ 177ab59362fSPeter Maydell return false; 178ab59362fSPeter Maydell } 179ab59362fSPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 180ab59362fSPeter Maydell return true; 181ab59362fSPeter Maydell } 182ab59362fSPeter Maydell 183ab59362fSPeter Maydell qd = mve_qreg_ptr(a->qd); 184ab59362fSPeter Maydell rt = load_reg(s, a->rt); 185ab59362fSPeter Maydell tcg_gen_dup_i32(a->size, rt, rt); 186ab59362fSPeter Maydell gen_helper_mve_vdup(cpu_env, qd, rt); 187ab59362fSPeter Maydell tcg_temp_free_ptr(qd); 188ab59362fSPeter Maydell tcg_temp_free_i32(rt); 189ab59362fSPeter Maydell mve_update_eci(s); 190ab59362fSPeter Maydell return true; 191ab59362fSPeter Maydell } 192ab59362fSPeter Maydell 1930f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn) 1940f0f2bd5SPeter Maydell { 1950f0f2bd5SPeter Maydell TCGv_ptr qd, qm; 1960f0f2bd5SPeter Maydell 1970f0f2bd5SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 1980f0f2bd5SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qm) || 1990f0f2bd5SPeter Maydell !fn) { 2000f0f2bd5SPeter Maydell return false; 2010f0f2bd5SPeter Maydell } 2020f0f2bd5SPeter Maydell 2030f0f2bd5SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 2040f0f2bd5SPeter Maydell return true; 2050f0f2bd5SPeter Maydell } 2060f0f2bd5SPeter Maydell 2070f0f2bd5SPeter Maydell qd = mve_qreg_ptr(a->qd); 2080f0f2bd5SPeter Maydell qm = mve_qreg_ptr(a->qm); 2090f0f2bd5SPeter Maydell fn(cpu_env, qd, qm); 2100f0f2bd5SPeter Maydell tcg_temp_free_ptr(qd); 2110f0f2bd5SPeter Maydell tcg_temp_free_ptr(qm); 2120f0f2bd5SPeter Maydell mve_update_eci(s); 2130f0f2bd5SPeter Maydell return true; 2140f0f2bd5SPeter Maydell } 2150f0f2bd5SPeter Maydell 2160f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN) \ 2170f0f2bd5SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_1op *a) \ 2180f0f2bd5SPeter Maydell { \ 2190f0f2bd5SPeter Maydell static MVEGenOneOpFn * const fns[] = { \ 2200f0f2bd5SPeter Maydell gen_helper_mve_##FN##b, \ 2210f0f2bd5SPeter Maydell gen_helper_mve_##FN##h, \ 2220f0f2bd5SPeter Maydell gen_helper_mve_##FN##w, \ 2230f0f2bd5SPeter Maydell NULL, \ 2240f0f2bd5SPeter Maydell }; \ 2250f0f2bd5SPeter Maydell return do_1op(s, a, fns[a->size]); \ 2260f0f2bd5SPeter Maydell } 2270f0f2bd5SPeter Maydell 2280f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz) 2296437f1f7SPeter Maydell DO_1OP(VCLS, vcls) 23059c91773SPeter Maydell DO_1OP(VABS, vabs) 231399a8c76SPeter Maydell DO_1OP(VNEG, vneg) 232249b5309SPeter Maydell 233249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a) 234249b5309SPeter Maydell { 235249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 236249b5309SPeter Maydell gen_helper_mve_vrev16b, 237249b5309SPeter Maydell NULL, 238249b5309SPeter Maydell NULL, 239249b5309SPeter Maydell NULL, 240249b5309SPeter Maydell }; 241249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 242249b5309SPeter Maydell } 243249b5309SPeter Maydell 244249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a) 245249b5309SPeter Maydell { 246249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 247249b5309SPeter Maydell gen_helper_mve_vrev32b, 248249b5309SPeter Maydell gen_helper_mve_vrev32h, 249249b5309SPeter Maydell NULL, 250249b5309SPeter Maydell NULL, 251249b5309SPeter Maydell }; 252249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 253249b5309SPeter Maydell } 254249b5309SPeter Maydell 255249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a) 256249b5309SPeter Maydell { 257249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 258249b5309SPeter Maydell gen_helper_mve_vrev64b, 259249b5309SPeter Maydell gen_helper_mve_vrev64h, 260249b5309SPeter Maydell gen_helper_mve_vrev64w, 261249b5309SPeter Maydell NULL, 262249b5309SPeter Maydell }; 263249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 264249b5309SPeter Maydell } 2658abd3c80SPeter Maydell 2668abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a) 2678abd3c80SPeter Maydell { 2688abd3c80SPeter Maydell return do_1op(s, a, gen_helper_mve_vmvn); 2698abd3c80SPeter Maydell } 27059c91773SPeter Maydell 27159c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a) 27259c91773SPeter Maydell { 27359c91773SPeter Maydell static MVEGenOneOpFn * const fns[] = { 27459c91773SPeter Maydell NULL, 27559c91773SPeter Maydell gen_helper_mve_vfabsh, 27659c91773SPeter Maydell gen_helper_mve_vfabss, 27759c91773SPeter Maydell NULL, 27859c91773SPeter Maydell }; 27959c91773SPeter Maydell if (!dc_isar_feature(aa32_mve_fp, s)) { 28059c91773SPeter Maydell return false; 28159c91773SPeter Maydell } 28259c91773SPeter Maydell return do_1op(s, a, fns[a->size]); 28359c91773SPeter Maydell } 284399a8c76SPeter Maydell 285399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a) 286399a8c76SPeter Maydell { 287399a8c76SPeter Maydell static MVEGenOneOpFn * const fns[] = { 288399a8c76SPeter Maydell NULL, 289399a8c76SPeter Maydell gen_helper_mve_vfnegh, 290399a8c76SPeter Maydell gen_helper_mve_vfnegs, 291399a8c76SPeter Maydell NULL, 292399a8c76SPeter Maydell }; 293399a8c76SPeter Maydell if (!dc_isar_feature(aa32_mve_fp, s)) { 294399a8c76SPeter Maydell return false; 295399a8c76SPeter Maydell } 296399a8c76SPeter Maydell return do_1op(s, a, fns[a->size]); 297399a8c76SPeter Maydell } 29868245e44SPeter Maydell 29968245e44SPeter Maydell static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn) 30068245e44SPeter Maydell { 30168245e44SPeter Maydell TCGv_ptr qd, qn, qm; 30268245e44SPeter Maydell 30368245e44SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 30468245e44SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qn | a->qm) || 30568245e44SPeter Maydell !fn) { 30668245e44SPeter Maydell return false; 30768245e44SPeter Maydell } 30868245e44SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 30968245e44SPeter Maydell return true; 31068245e44SPeter Maydell } 31168245e44SPeter Maydell 31268245e44SPeter Maydell qd = mve_qreg_ptr(a->qd); 31368245e44SPeter Maydell qn = mve_qreg_ptr(a->qn); 31468245e44SPeter Maydell qm = mve_qreg_ptr(a->qm); 31568245e44SPeter Maydell fn(cpu_env, qd, qn, qm); 31668245e44SPeter Maydell tcg_temp_free_ptr(qd); 31768245e44SPeter Maydell tcg_temp_free_ptr(qn); 31868245e44SPeter Maydell tcg_temp_free_ptr(qm); 31968245e44SPeter Maydell mve_update_eci(s); 32068245e44SPeter Maydell return true; 32168245e44SPeter Maydell } 32268245e44SPeter Maydell 32368245e44SPeter Maydell #define DO_LOGIC(INSN, HELPER) \ 32468245e44SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2op *a) \ 32568245e44SPeter Maydell { \ 32668245e44SPeter Maydell return do_2op(s, a, HELPER); \ 32768245e44SPeter Maydell } 32868245e44SPeter Maydell 32968245e44SPeter Maydell DO_LOGIC(VAND, gen_helper_mve_vand) 33068245e44SPeter Maydell DO_LOGIC(VBIC, gen_helper_mve_vbic) 33168245e44SPeter Maydell DO_LOGIC(VORR, gen_helper_mve_vorr) 33268245e44SPeter Maydell DO_LOGIC(VORN, gen_helper_mve_vorn) 33368245e44SPeter Maydell DO_LOGIC(VEOR, gen_helper_mve_veor) 3349333fe4dSPeter Maydell 3359333fe4dSPeter Maydell #define DO_2OP(INSN, FN) \ 3369333fe4dSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2op *a) \ 3379333fe4dSPeter Maydell { \ 3389333fe4dSPeter Maydell static MVEGenTwoOpFn * const fns[] = { \ 3399333fe4dSPeter Maydell gen_helper_mve_##FN##b, \ 3409333fe4dSPeter Maydell gen_helper_mve_##FN##h, \ 3419333fe4dSPeter Maydell gen_helper_mve_##FN##w, \ 3429333fe4dSPeter Maydell NULL, \ 3439333fe4dSPeter Maydell }; \ 3449333fe4dSPeter Maydell return do_2op(s, a, fns[a->size]); \ 3459333fe4dSPeter Maydell } 3469333fe4dSPeter Maydell 3479333fe4dSPeter Maydell DO_2OP(VADD, vadd) 3489333fe4dSPeter Maydell DO_2OP(VSUB, vsub) 3499333fe4dSPeter Maydell DO_2OP(VMUL, vmul) 350ba62cc56SPeter Maydell DO_2OP(VMULH_S, vmulhs) 351ba62cc56SPeter Maydell DO_2OP(VMULH_U, vmulhu) 352*fca87b78SPeter Maydell DO_2OP(VRMULH_S, vrmulhs) 353*fca87b78SPeter Maydell DO_2OP(VRMULH_U, vrmulhu) 354