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); 33507b6a50SPeter Maydell 34507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */ 35507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg) 36507b6a50SPeter Maydell { 37507b6a50SPeter Maydell return offsetof(CPUARMState, vfp.zregs[reg].d[0]); 38507b6a50SPeter Maydell } 39507b6a50SPeter Maydell 40507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg) 41507b6a50SPeter Maydell { 42507b6a50SPeter Maydell TCGv_ptr ret = tcg_temp_new_ptr(); 43507b6a50SPeter Maydell tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg)); 44507b6a50SPeter Maydell return ret; 45507b6a50SPeter Maydell } 46507b6a50SPeter Maydell 47507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask) 48507b6a50SPeter Maydell { 49507b6a50SPeter Maydell /* 50507b6a50SPeter Maydell * Check whether Qregs are in range. For v8.1M only Q0..Q7 51507b6a50SPeter Maydell * are supported, see VFPSmallRegisterBank(). 52507b6a50SPeter Maydell */ 53507b6a50SPeter Maydell return qmask < 8; 54507b6a50SPeter Maydell } 55507b6a50SPeter Maydell 56507b6a50SPeter Maydell static bool mve_eci_check(DisasContext *s) 57507b6a50SPeter Maydell { 58507b6a50SPeter Maydell /* 59507b6a50SPeter Maydell * This is a beatwise insn: check that ECI is valid (not a 60507b6a50SPeter Maydell * reserved value) and note that we are handling it. 61507b6a50SPeter Maydell * Return true if OK, false if we generated an exception. 62507b6a50SPeter Maydell */ 63507b6a50SPeter Maydell s->eci_handled = true; 64507b6a50SPeter Maydell switch (s->eci) { 65507b6a50SPeter Maydell case ECI_NONE: 66507b6a50SPeter Maydell case ECI_A0: 67507b6a50SPeter Maydell case ECI_A0A1: 68507b6a50SPeter Maydell case ECI_A0A1A2: 69507b6a50SPeter Maydell case ECI_A0A1A2B0: 70507b6a50SPeter Maydell return true; 71507b6a50SPeter Maydell default: 72507b6a50SPeter Maydell /* Reserved value: INVSTATE UsageFault */ 73507b6a50SPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(), 74507b6a50SPeter Maydell default_exception_el(s)); 75507b6a50SPeter Maydell return false; 76507b6a50SPeter Maydell } 77507b6a50SPeter Maydell } 78507b6a50SPeter Maydell 79507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s) 80507b6a50SPeter Maydell { 81507b6a50SPeter Maydell /* 82507b6a50SPeter Maydell * The helper function will always update the CPUState field, 83507b6a50SPeter Maydell * so we only need to update the DisasContext field. 84507b6a50SPeter Maydell */ 85507b6a50SPeter Maydell if (s->eci) { 86507b6a50SPeter Maydell s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE; 87507b6a50SPeter Maydell } 88507b6a50SPeter Maydell } 89507b6a50SPeter Maydell 90507b6a50SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn) 91507b6a50SPeter Maydell { 92507b6a50SPeter Maydell TCGv_i32 addr; 93507b6a50SPeter Maydell uint32_t offset; 94507b6a50SPeter Maydell TCGv_ptr qreg; 95507b6a50SPeter Maydell 96507b6a50SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 97507b6a50SPeter Maydell !mve_check_qreg_bank(s, a->qd) || 98507b6a50SPeter Maydell !fn) { 99507b6a50SPeter Maydell return false; 100507b6a50SPeter Maydell } 101507b6a50SPeter Maydell 102507b6a50SPeter Maydell /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */ 103507b6a50SPeter Maydell if (a->rn == 15 || (a->rn == 13 && a->w)) { 104507b6a50SPeter Maydell return false; 105507b6a50SPeter Maydell } 106507b6a50SPeter Maydell 107507b6a50SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 108507b6a50SPeter Maydell return true; 109507b6a50SPeter Maydell } 110507b6a50SPeter Maydell 111507b6a50SPeter Maydell offset = a->imm << a->size; 112507b6a50SPeter Maydell if (!a->a) { 113507b6a50SPeter Maydell offset = -offset; 114507b6a50SPeter Maydell } 115507b6a50SPeter Maydell addr = load_reg(s, a->rn); 116507b6a50SPeter Maydell if (a->p) { 117507b6a50SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 118507b6a50SPeter Maydell } 119507b6a50SPeter Maydell 120507b6a50SPeter Maydell qreg = mve_qreg_ptr(a->qd); 121507b6a50SPeter Maydell fn(cpu_env, qreg, addr); 122507b6a50SPeter Maydell tcg_temp_free_ptr(qreg); 123507b6a50SPeter Maydell 124507b6a50SPeter Maydell /* 125507b6a50SPeter Maydell * Writeback always happens after the last beat of the insn, 126507b6a50SPeter Maydell * regardless of predication 127507b6a50SPeter Maydell */ 128507b6a50SPeter Maydell if (a->w) { 129507b6a50SPeter Maydell if (!a->p) { 130507b6a50SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 131507b6a50SPeter Maydell } 132507b6a50SPeter Maydell store_reg(s, a->rn, addr); 133507b6a50SPeter Maydell } else { 134507b6a50SPeter Maydell tcg_temp_free_i32(addr); 135507b6a50SPeter Maydell } 136507b6a50SPeter Maydell mve_update_eci(s); 137507b6a50SPeter Maydell return true; 138507b6a50SPeter Maydell } 139507b6a50SPeter Maydell 140507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a) 141507b6a50SPeter Maydell { 142507b6a50SPeter Maydell static MVEGenLdStFn * const ldstfns[4][2] = { 143507b6a50SPeter Maydell { gen_helper_mve_vstrb, gen_helper_mve_vldrb }, 144507b6a50SPeter Maydell { gen_helper_mve_vstrh, gen_helper_mve_vldrh }, 145507b6a50SPeter Maydell { gen_helper_mve_vstrw, gen_helper_mve_vldrw }, 146507b6a50SPeter Maydell { NULL, NULL } 147507b6a50SPeter Maydell }; 148507b6a50SPeter Maydell return do_ldst(s, a, ldstfns[a->size][a->l]); 149507b6a50SPeter Maydell } 1502fc6b751SPeter Maydell 1512fc6b751SPeter Maydell #define DO_VLDST_WIDE_NARROW(OP, SLD, ULD, ST) \ 1522fc6b751SPeter Maydell static bool trans_##OP(DisasContext *s, arg_VLDR_VSTR *a) \ 1532fc6b751SPeter Maydell { \ 1542fc6b751SPeter Maydell static MVEGenLdStFn * const ldstfns[2][2] = { \ 1552fc6b751SPeter Maydell { gen_helper_mve_##ST, gen_helper_mve_##SLD }, \ 1562fc6b751SPeter Maydell { NULL, gen_helper_mve_##ULD }, \ 1572fc6b751SPeter Maydell }; \ 1582fc6b751SPeter Maydell return do_ldst(s, a, ldstfns[a->u][a->l]); \ 1592fc6b751SPeter Maydell } 1602fc6b751SPeter Maydell 1612fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_H, vldrb_sh, vldrb_uh, vstrb_h) 1622fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTB_W, vldrb_sw, vldrb_uw, vstrb_w) 1632fc6b751SPeter Maydell DO_VLDST_WIDE_NARROW(VLDSTH_W, vldrh_sw, vldrh_uw, vstrh_w) 1640f0f2bd5SPeter Maydell 1650f0f2bd5SPeter Maydell static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn) 1660f0f2bd5SPeter Maydell { 1670f0f2bd5SPeter Maydell TCGv_ptr qd, qm; 1680f0f2bd5SPeter Maydell 1690f0f2bd5SPeter Maydell if (!dc_isar_feature(aa32_mve, s) || 1700f0f2bd5SPeter Maydell !mve_check_qreg_bank(s, a->qd | a->qm) || 1710f0f2bd5SPeter Maydell !fn) { 1720f0f2bd5SPeter Maydell return false; 1730f0f2bd5SPeter Maydell } 1740f0f2bd5SPeter Maydell 1750f0f2bd5SPeter Maydell if (!mve_eci_check(s) || !vfp_access_check(s)) { 1760f0f2bd5SPeter Maydell return true; 1770f0f2bd5SPeter Maydell } 1780f0f2bd5SPeter Maydell 1790f0f2bd5SPeter Maydell qd = mve_qreg_ptr(a->qd); 1800f0f2bd5SPeter Maydell qm = mve_qreg_ptr(a->qm); 1810f0f2bd5SPeter Maydell fn(cpu_env, qd, qm); 1820f0f2bd5SPeter Maydell tcg_temp_free_ptr(qd); 1830f0f2bd5SPeter Maydell tcg_temp_free_ptr(qm); 1840f0f2bd5SPeter Maydell mve_update_eci(s); 1850f0f2bd5SPeter Maydell return true; 1860f0f2bd5SPeter Maydell } 1870f0f2bd5SPeter Maydell 1880f0f2bd5SPeter Maydell #define DO_1OP(INSN, FN) \ 1890f0f2bd5SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_1op *a) \ 1900f0f2bd5SPeter Maydell { \ 1910f0f2bd5SPeter Maydell static MVEGenOneOpFn * const fns[] = { \ 1920f0f2bd5SPeter Maydell gen_helper_mve_##FN##b, \ 1930f0f2bd5SPeter Maydell gen_helper_mve_##FN##h, \ 1940f0f2bd5SPeter Maydell gen_helper_mve_##FN##w, \ 1950f0f2bd5SPeter Maydell NULL, \ 1960f0f2bd5SPeter Maydell }; \ 1970f0f2bd5SPeter Maydell return do_1op(s, a, fns[a->size]); \ 1980f0f2bd5SPeter Maydell } 1990f0f2bd5SPeter Maydell 2000f0f2bd5SPeter Maydell DO_1OP(VCLZ, vclz) 2016437f1f7SPeter Maydell DO_1OP(VCLS, vcls) 20259c91773SPeter Maydell DO_1OP(VABS, vabs) 203*399a8c76SPeter Maydell DO_1OP(VNEG, vneg) 204249b5309SPeter Maydell 205249b5309SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_1op *a) 206249b5309SPeter Maydell { 207249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 208249b5309SPeter Maydell gen_helper_mve_vrev16b, 209249b5309SPeter Maydell NULL, 210249b5309SPeter Maydell NULL, 211249b5309SPeter Maydell NULL, 212249b5309SPeter Maydell }; 213249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 214249b5309SPeter Maydell } 215249b5309SPeter Maydell 216249b5309SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_1op *a) 217249b5309SPeter Maydell { 218249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 219249b5309SPeter Maydell gen_helper_mve_vrev32b, 220249b5309SPeter Maydell gen_helper_mve_vrev32h, 221249b5309SPeter Maydell NULL, 222249b5309SPeter Maydell NULL, 223249b5309SPeter Maydell }; 224249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 225249b5309SPeter Maydell } 226249b5309SPeter Maydell 227249b5309SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_1op *a) 228249b5309SPeter Maydell { 229249b5309SPeter Maydell static MVEGenOneOpFn * const fns[] = { 230249b5309SPeter Maydell gen_helper_mve_vrev64b, 231249b5309SPeter Maydell gen_helper_mve_vrev64h, 232249b5309SPeter Maydell gen_helper_mve_vrev64w, 233249b5309SPeter Maydell NULL, 234249b5309SPeter Maydell }; 235249b5309SPeter Maydell return do_1op(s, a, fns[a->size]); 236249b5309SPeter Maydell } 2378abd3c80SPeter Maydell 2388abd3c80SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_1op *a) 2398abd3c80SPeter Maydell { 2408abd3c80SPeter Maydell return do_1op(s, a, gen_helper_mve_vmvn); 2418abd3c80SPeter Maydell } 24259c91773SPeter Maydell 24359c91773SPeter Maydell static bool trans_VABS_fp(DisasContext *s, arg_1op *a) 24459c91773SPeter Maydell { 24559c91773SPeter Maydell static MVEGenOneOpFn * const fns[] = { 24659c91773SPeter Maydell NULL, 24759c91773SPeter Maydell gen_helper_mve_vfabsh, 24859c91773SPeter Maydell gen_helper_mve_vfabss, 24959c91773SPeter Maydell NULL, 25059c91773SPeter Maydell }; 25159c91773SPeter Maydell if (!dc_isar_feature(aa32_mve_fp, s)) { 25259c91773SPeter Maydell return false; 25359c91773SPeter Maydell } 25459c91773SPeter Maydell return do_1op(s, a, fns[a->size]); 25559c91773SPeter Maydell } 256*399a8c76SPeter Maydell 257*399a8c76SPeter Maydell static bool trans_VNEG_fp(DisasContext *s, arg_1op *a) 258*399a8c76SPeter Maydell { 259*399a8c76SPeter Maydell static MVEGenOneOpFn * const fns[] = { 260*399a8c76SPeter Maydell NULL, 261*399a8c76SPeter Maydell gen_helper_mve_vfnegh, 262*399a8c76SPeter Maydell gen_helper_mve_vfnegs, 263*399a8c76SPeter Maydell NULL, 264*399a8c76SPeter Maydell }; 265*399a8c76SPeter Maydell if (!dc_isar_feature(aa32_mve_fp, s)) { 266*399a8c76SPeter Maydell return false; 267*399a8c76SPeter Maydell } 268*399a8c76SPeter Maydell return do_1op(s, a, fns[a->size]); 269*399a8c76SPeter Maydell } 270