1625e3dd4SPeter Maydell /* 2625e3dd4SPeter Maydell * ARM translation: AArch32 Neon instructions 3625e3dd4SPeter Maydell * 4625e3dd4SPeter Maydell * Copyright (c) 2003 Fabrice Bellard 5625e3dd4SPeter Maydell * Copyright (c) 2005-2007 CodeSourcery 6625e3dd4SPeter Maydell * Copyright (c) 2007 OpenedHand, Ltd. 7625e3dd4SPeter Maydell * Copyright (c) 2020 Linaro, Ltd. 8625e3dd4SPeter Maydell * 9625e3dd4SPeter Maydell * This library is free software; you can redistribute it and/or 10625e3dd4SPeter Maydell * modify it under the terms of the GNU Lesser General Public 11625e3dd4SPeter Maydell * License as published by the Free Software Foundation; either 12625e3dd4SPeter Maydell * version 2 of the License, or (at your option) any later version. 13625e3dd4SPeter Maydell * 14625e3dd4SPeter Maydell * This library is distributed in the hope that it will be useful, 15625e3dd4SPeter Maydell * but WITHOUT ANY WARRANTY; without even the implied warranty of 16625e3dd4SPeter Maydell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17625e3dd4SPeter Maydell * Lesser General Public License for more details. 18625e3dd4SPeter Maydell * 19625e3dd4SPeter Maydell * You should have received a copy of the GNU Lesser General Public 20625e3dd4SPeter Maydell * License along with this library; if not, see <http://www.gnu.org/licenses/>. 21625e3dd4SPeter Maydell */ 22625e3dd4SPeter Maydell 23625e3dd4SPeter Maydell /* 24625e3dd4SPeter Maydell * This file is intended to be included from translate.c; it uses 25625e3dd4SPeter Maydell * some macros and definitions provided by that file. 26625e3dd4SPeter Maydell * It might be possible to convert it to a standalone .c file eventually. 27625e3dd4SPeter Maydell */ 28625e3dd4SPeter Maydell 29123ce4e3SPeter Maydell static inline int plus1(DisasContext *s, int x) 30123ce4e3SPeter Maydell { 31123ce4e3SPeter Maydell return x + 1; 32123ce4e3SPeter Maydell } 33123ce4e3SPeter Maydell 34625e3dd4SPeter Maydell /* Include the generated Neon decoder */ 35625e3dd4SPeter Maydell #include "decode-neon-dp.inc.c" 36625e3dd4SPeter Maydell #include "decode-neon-ls.inc.c" 37625e3dd4SPeter Maydell #include "decode-neon-shared.inc.c" 38afff8de0SPeter Maydell 39afff8de0SPeter Maydell static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) 40afff8de0SPeter Maydell { 41afff8de0SPeter Maydell int opr_sz; 42afff8de0SPeter Maydell TCGv_ptr fpst; 43afff8de0SPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 44afff8de0SPeter Maydell 45afff8de0SPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 46afff8de0SPeter Maydell || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) { 47afff8de0SPeter Maydell return false; 48afff8de0SPeter Maydell } 49afff8de0SPeter Maydell 50afff8de0SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 51afff8de0SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 52afff8de0SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 53afff8de0SPeter Maydell return false; 54afff8de0SPeter Maydell } 55afff8de0SPeter Maydell 56afff8de0SPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 57afff8de0SPeter Maydell return false; 58afff8de0SPeter Maydell } 59afff8de0SPeter Maydell 60afff8de0SPeter Maydell if (!vfp_access_check(s)) { 61afff8de0SPeter Maydell return true; 62afff8de0SPeter Maydell } 63afff8de0SPeter Maydell 64afff8de0SPeter Maydell opr_sz = (1 + a->q) * 8; 65afff8de0SPeter Maydell fpst = get_fpstatus_ptr(1); 66afff8de0SPeter Maydell fn_gvec_ptr = a->size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah; 67afff8de0SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 68afff8de0SPeter Maydell vfp_reg_offset(1, a->vn), 69afff8de0SPeter Maydell vfp_reg_offset(1, a->vm), 70afff8de0SPeter Maydell fpst, opr_sz, opr_sz, a->rot, 71afff8de0SPeter Maydell fn_gvec_ptr); 72afff8de0SPeter Maydell tcg_temp_free_ptr(fpst); 73afff8de0SPeter Maydell return true; 74afff8de0SPeter Maydell } 7594d5eb7bSPeter Maydell 7694d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a) 7794d5eb7bSPeter Maydell { 7894d5eb7bSPeter Maydell int opr_sz; 7994d5eb7bSPeter Maydell TCGv_ptr fpst; 8094d5eb7bSPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 8194d5eb7bSPeter Maydell 8294d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 8394d5eb7bSPeter Maydell || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) { 8494d5eb7bSPeter Maydell return false; 8594d5eb7bSPeter Maydell } 8694d5eb7bSPeter Maydell 8794d5eb7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 8894d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 8994d5eb7bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 9094d5eb7bSPeter Maydell return false; 9194d5eb7bSPeter Maydell } 9294d5eb7bSPeter Maydell 9394d5eb7bSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 9494d5eb7bSPeter Maydell return false; 9594d5eb7bSPeter Maydell } 9694d5eb7bSPeter Maydell 9794d5eb7bSPeter Maydell if (!vfp_access_check(s)) { 9894d5eb7bSPeter Maydell return true; 9994d5eb7bSPeter Maydell } 10094d5eb7bSPeter Maydell 10194d5eb7bSPeter Maydell opr_sz = (1 + a->q) * 8; 10294d5eb7bSPeter Maydell fpst = get_fpstatus_ptr(1); 10394d5eb7bSPeter Maydell fn_gvec_ptr = a->size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh; 10494d5eb7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 10594d5eb7bSPeter Maydell vfp_reg_offset(1, a->vn), 10694d5eb7bSPeter Maydell vfp_reg_offset(1, a->vm), 10794d5eb7bSPeter Maydell fpst, opr_sz, opr_sz, a->rot, 10894d5eb7bSPeter Maydell fn_gvec_ptr); 10994d5eb7bSPeter Maydell tcg_temp_free_ptr(fpst); 11094d5eb7bSPeter Maydell return true; 11194d5eb7bSPeter Maydell } 11232da0e33SPeter Maydell 11332da0e33SPeter Maydell static bool trans_VDOT(DisasContext *s, arg_VDOT *a) 11432da0e33SPeter Maydell { 11532da0e33SPeter Maydell int opr_sz; 11632da0e33SPeter Maydell gen_helper_gvec_3 *fn_gvec; 11732da0e33SPeter Maydell 11832da0e33SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 11932da0e33SPeter Maydell return false; 12032da0e33SPeter Maydell } 12132da0e33SPeter Maydell 12232da0e33SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 12332da0e33SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 12432da0e33SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 12532da0e33SPeter Maydell return false; 12632da0e33SPeter Maydell } 12732da0e33SPeter Maydell 12832da0e33SPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 12932da0e33SPeter Maydell return false; 13032da0e33SPeter Maydell } 13132da0e33SPeter Maydell 13232da0e33SPeter Maydell if (!vfp_access_check(s)) { 13332da0e33SPeter Maydell return true; 13432da0e33SPeter Maydell } 13532da0e33SPeter Maydell 13632da0e33SPeter Maydell opr_sz = (1 + a->q) * 8; 13732da0e33SPeter Maydell fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b; 13832da0e33SPeter Maydell tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd), 13932da0e33SPeter Maydell vfp_reg_offset(1, a->vn), 14032da0e33SPeter Maydell vfp_reg_offset(1, a->vm), 14132da0e33SPeter Maydell opr_sz, opr_sz, 0, fn_gvec); 14232da0e33SPeter Maydell return true; 14332da0e33SPeter Maydell } 1449a107e7bSPeter Maydell 1459a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a) 1469a107e7bSPeter Maydell { 1479a107e7bSPeter Maydell int opr_sz; 1489a107e7bSPeter Maydell 1499a107e7bSPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 1509a107e7bSPeter Maydell return false; 1519a107e7bSPeter Maydell } 1529a107e7bSPeter Maydell 1539a107e7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1549a107e7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1559a107e7bSPeter Maydell (a->vd & 0x10)) { 1569a107e7bSPeter Maydell return false; 1579a107e7bSPeter Maydell } 1589a107e7bSPeter Maydell 1599a107e7bSPeter Maydell if (a->vd & a->q) { 1609a107e7bSPeter Maydell return false; 1619a107e7bSPeter Maydell } 1629a107e7bSPeter Maydell 1639a107e7bSPeter Maydell if (!vfp_access_check(s)) { 1649a107e7bSPeter Maydell return true; 1659a107e7bSPeter Maydell } 1669a107e7bSPeter Maydell 1679a107e7bSPeter Maydell opr_sz = (1 + a->q) * 8; 1689a107e7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 1699a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vn), 1709a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vm), 1719a107e7bSPeter Maydell cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ 1729a107e7bSPeter Maydell gen_helper_gvec_fmlal_a32); 1739a107e7bSPeter Maydell return true; 1749a107e7bSPeter Maydell } 1757e1b5d61SPeter Maydell 1767e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a) 1777e1b5d61SPeter Maydell { 1787e1b5d61SPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 1797e1b5d61SPeter Maydell int opr_sz; 1807e1b5d61SPeter Maydell TCGv_ptr fpst; 1817e1b5d61SPeter Maydell 1827e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_vcma, s)) { 1837e1b5d61SPeter Maydell return false; 1847e1b5d61SPeter Maydell } 1857e1b5d61SPeter Maydell if (a->size == 0 && !dc_isar_feature(aa32_fp16_arith, s)) { 1867e1b5d61SPeter Maydell return false; 1877e1b5d61SPeter Maydell } 1887e1b5d61SPeter Maydell 1897e1b5d61SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1907e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1917e1b5d61SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1927e1b5d61SPeter Maydell return false; 1937e1b5d61SPeter Maydell } 1947e1b5d61SPeter Maydell 1957e1b5d61SPeter Maydell if ((a->vd | a->vn) & a->q) { 1967e1b5d61SPeter Maydell return false; 1977e1b5d61SPeter Maydell } 1987e1b5d61SPeter Maydell 1997e1b5d61SPeter Maydell if (!vfp_access_check(s)) { 2007e1b5d61SPeter Maydell return true; 2017e1b5d61SPeter Maydell } 2027e1b5d61SPeter Maydell 2037e1b5d61SPeter Maydell fn_gvec_ptr = (a->size ? gen_helper_gvec_fcmlas_idx 2047e1b5d61SPeter Maydell : gen_helper_gvec_fcmlah_idx); 2057e1b5d61SPeter Maydell opr_sz = (1 + a->q) * 8; 2067e1b5d61SPeter Maydell fpst = get_fpstatus_ptr(1); 2077e1b5d61SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 2087e1b5d61SPeter Maydell vfp_reg_offset(1, a->vn), 2097e1b5d61SPeter Maydell vfp_reg_offset(1, a->vm), 2107e1b5d61SPeter Maydell fpst, opr_sz, opr_sz, 2117e1b5d61SPeter Maydell (a->index << 2) | a->rot, fn_gvec_ptr); 2127e1b5d61SPeter Maydell tcg_temp_free_ptr(fpst); 2137e1b5d61SPeter Maydell return true; 2147e1b5d61SPeter Maydell } 21535f5d4d1SPeter Maydell 21635f5d4d1SPeter Maydell static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a) 21735f5d4d1SPeter Maydell { 21835f5d4d1SPeter Maydell gen_helper_gvec_3 *fn_gvec; 21935f5d4d1SPeter Maydell int opr_sz; 22035f5d4d1SPeter Maydell TCGv_ptr fpst; 22135f5d4d1SPeter Maydell 22235f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 22335f5d4d1SPeter Maydell return false; 22435f5d4d1SPeter Maydell } 22535f5d4d1SPeter Maydell 22635f5d4d1SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 22735f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 22835f5d4d1SPeter Maydell ((a->vd | a->vn) & 0x10)) { 22935f5d4d1SPeter Maydell return false; 23035f5d4d1SPeter Maydell } 23135f5d4d1SPeter Maydell 23235f5d4d1SPeter Maydell if ((a->vd | a->vn) & a->q) { 23335f5d4d1SPeter Maydell return false; 23435f5d4d1SPeter Maydell } 23535f5d4d1SPeter Maydell 23635f5d4d1SPeter Maydell if (!vfp_access_check(s)) { 23735f5d4d1SPeter Maydell return true; 23835f5d4d1SPeter Maydell } 23935f5d4d1SPeter Maydell 24035f5d4d1SPeter Maydell fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b; 24135f5d4d1SPeter Maydell opr_sz = (1 + a->q) * 8; 24235f5d4d1SPeter Maydell fpst = get_fpstatus_ptr(1); 24335f5d4d1SPeter Maydell tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd), 24435f5d4d1SPeter Maydell vfp_reg_offset(1, a->vn), 24535f5d4d1SPeter Maydell vfp_reg_offset(1, a->rm), 24635f5d4d1SPeter Maydell opr_sz, opr_sz, a->index, fn_gvec); 24735f5d4d1SPeter Maydell tcg_temp_free_ptr(fpst); 24835f5d4d1SPeter Maydell return true; 24935f5d4d1SPeter Maydell } 250d27e82f7SPeter Maydell 251d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) 252d27e82f7SPeter Maydell { 253d27e82f7SPeter Maydell int opr_sz; 254d27e82f7SPeter Maydell 255d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 256d27e82f7SPeter Maydell return false; 257d27e82f7SPeter Maydell } 258d27e82f7SPeter Maydell 259d27e82f7SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 260d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 261d27e82f7SPeter Maydell ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) { 262d27e82f7SPeter Maydell return false; 263d27e82f7SPeter Maydell } 264d27e82f7SPeter Maydell 265d27e82f7SPeter Maydell if (a->vd & a->q) { 266d27e82f7SPeter Maydell return false; 267d27e82f7SPeter Maydell } 268d27e82f7SPeter Maydell 269d27e82f7SPeter Maydell if (!vfp_access_check(s)) { 270d27e82f7SPeter Maydell return true; 271d27e82f7SPeter Maydell } 272d27e82f7SPeter Maydell 273d27e82f7SPeter Maydell opr_sz = (1 + a->q) * 8; 274d27e82f7SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 275d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->vn), 276d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->rm), 277d27e82f7SPeter Maydell cpu_env, opr_sz, opr_sz, 278d27e82f7SPeter Maydell (a->index << 2) | a->s, /* is_2 == 0 */ 279d27e82f7SPeter Maydell gen_helper_gvec_fmlal_idx_a32); 280d27e82f7SPeter Maydell return true; 281d27e82f7SPeter Maydell } 282a27b4630SPeter Maydell 283a27b4630SPeter Maydell static struct { 284a27b4630SPeter Maydell int nregs; 285a27b4630SPeter Maydell int interleave; 286a27b4630SPeter Maydell int spacing; 287a27b4630SPeter Maydell } const neon_ls_element_type[11] = { 288a27b4630SPeter Maydell {1, 4, 1}, 289a27b4630SPeter Maydell {1, 4, 2}, 290a27b4630SPeter Maydell {4, 1, 1}, 291a27b4630SPeter Maydell {2, 2, 2}, 292a27b4630SPeter Maydell {1, 3, 1}, 293a27b4630SPeter Maydell {1, 3, 2}, 294a27b4630SPeter Maydell {3, 1, 1}, 295a27b4630SPeter Maydell {1, 1, 1}, 296a27b4630SPeter Maydell {1, 2, 1}, 297a27b4630SPeter Maydell {1, 2, 2}, 298a27b4630SPeter Maydell {2, 1, 1} 299a27b4630SPeter Maydell }; 300a27b4630SPeter Maydell 301a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn, 302a27b4630SPeter Maydell int stride) 303a27b4630SPeter Maydell { 304a27b4630SPeter Maydell if (rm != 15) { 305a27b4630SPeter Maydell TCGv_i32 base; 306a27b4630SPeter Maydell 307a27b4630SPeter Maydell base = load_reg(s, rn); 308a27b4630SPeter Maydell if (rm == 13) { 309a27b4630SPeter Maydell tcg_gen_addi_i32(base, base, stride); 310a27b4630SPeter Maydell } else { 311a27b4630SPeter Maydell TCGv_i32 index; 312a27b4630SPeter Maydell index = load_reg(s, rm); 313a27b4630SPeter Maydell tcg_gen_add_i32(base, base, index); 314a27b4630SPeter Maydell tcg_temp_free_i32(index); 315a27b4630SPeter Maydell } 316a27b4630SPeter Maydell store_reg(s, rn, base); 317a27b4630SPeter Maydell } 318a27b4630SPeter Maydell } 319a27b4630SPeter Maydell 320a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) 321a27b4630SPeter Maydell { 322a27b4630SPeter Maydell /* Neon load/store multiple structures */ 323a27b4630SPeter Maydell int nregs, interleave, spacing, reg, n; 324a27b4630SPeter Maydell MemOp endian = s->be_data; 325a27b4630SPeter Maydell int mmu_idx = get_mem_index(s); 326a27b4630SPeter Maydell int size = a->size; 327a27b4630SPeter Maydell TCGv_i64 tmp64; 328a27b4630SPeter Maydell TCGv_i32 addr, tmp; 329a27b4630SPeter Maydell 330a27b4630SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 331a27b4630SPeter Maydell return false; 332a27b4630SPeter Maydell } 333a27b4630SPeter Maydell 334a27b4630SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 335a27b4630SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 336a27b4630SPeter Maydell return false; 337a27b4630SPeter Maydell } 338a27b4630SPeter Maydell if (a->itype > 10) { 339a27b4630SPeter Maydell return false; 340a27b4630SPeter Maydell } 341a27b4630SPeter Maydell /* Catch UNDEF cases for bad values of align field */ 342a27b4630SPeter Maydell switch (a->itype & 0xc) { 343a27b4630SPeter Maydell case 4: 344a27b4630SPeter Maydell if (a->align >= 2) { 345a27b4630SPeter Maydell return false; 346a27b4630SPeter Maydell } 347a27b4630SPeter Maydell break; 348a27b4630SPeter Maydell case 8: 349a27b4630SPeter Maydell if (a->align == 3) { 350a27b4630SPeter Maydell return false; 351a27b4630SPeter Maydell } 352a27b4630SPeter Maydell break; 353a27b4630SPeter Maydell default: 354a27b4630SPeter Maydell break; 355a27b4630SPeter Maydell } 356a27b4630SPeter Maydell nregs = neon_ls_element_type[a->itype].nregs; 357a27b4630SPeter Maydell interleave = neon_ls_element_type[a->itype].interleave; 358a27b4630SPeter Maydell spacing = neon_ls_element_type[a->itype].spacing; 359a27b4630SPeter Maydell if (size == 3 && (interleave | spacing) != 1) { 360a27b4630SPeter Maydell return false; 361a27b4630SPeter Maydell } 362a27b4630SPeter Maydell 363a27b4630SPeter Maydell if (!vfp_access_check(s)) { 364a27b4630SPeter Maydell return true; 365a27b4630SPeter Maydell } 366a27b4630SPeter Maydell 367a27b4630SPeter Maydell /* For our purposes, bytes are always little-endian. */ 368a27b4630SPeter Maydell if (size == 0) { 369a27b4630SPeter Maydell endian = MO_LE; 370a27b4630SPeter Maydell } 371a27b4630SPeter Maydell /* 372a27b4630SPeter Maydell * Consecutive little-endian elements from a single register 373a27b4630SPeter Maydell * can be promoted to a larger little-endian operation. 374a27b4630SPeter Maydell */ 375a27b4630SPeter Maydell if (interleave == 1 && endian == MO_LE) { 376a27b4630SPeter Maydell size = 3; 377a27b4630SPeter Maydell } 378a27b4630SPeter Maydell tmp64 = tcg_temp_new_i64(); 379a27b4630SPeter Maydell addr = tcg_temp_new_i32(); 380a27b4630SPeter Maydell tmp = tcg_const_i32(1 << size); 381a27b4630SPeter Maydell load_reg_var(s, addr, a->rn); 382a27b4630SPeter Maydell for (reg = 0; reg < nregs; reg++) { 383a27b4630SPeter Maydell for (n = 0; n < 8 >> size; n++) { 384a27b4630SPeter Maydell int xs; 385a27b4630SPeter Maydell for (xs = 0; xs < interleave; xs++) { 386a27b4630SPeter Maydell int tt = a->vd + reg + spacing * xs; 387a27b4630SPeter Maydell 388a27b4630SPeter Maydell if (a->l) { 389a27b4630SPeter Maydell gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size); 390a27b4630SPeter Maydell neon_store_element64(tt, n, size, tmp64); 391a27b4630SPeter Maydell } else { 392a27b4630SPeter Maydell neon_load_element64(tmp64, tt, n, size); 393a27b4630SPeter Maydell gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size); 394a27b4630SPeter Maydell } 395a27b4630SPeter Maydell tcg_gen_add_i32(addr, addr, tmp); 396a27b4630SPeter Maydell } 397a27b4630SPeter Maydell } 398a27b4630SPeter Maydell } 399a27b4630SPeter Maydell tcg_temp_free_i32(addr); 400a27b4630SPeter Maydell tcg_temp_free_i32(tmp); 401a27b4630SPeter Maydell tcg_temp_free_i64(tmp64); 402a27b4630SPeter Maydell 403a27b4630SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); 404a27b4630SPeter Maydell return true; 405a27b4630SPeter Maydell } 4063698747cSPeter Maydell 4073698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) 4083698747cSPeter Maydell { 4093698747cSPeter Maydell /* Neon load single structure to all lanes */ 4103698747cSPeter Maydell int reg, stride, vec_size; 4113698747cSPeter Maydell int vd = a->vd; 4123698747cSPeter Maydell int size = a->size; 4133698747cSPeter Maydell int nregs = a->n + 1; 4143698747cSPeter Maydell TCGv_i32 addr, tmp; 4153698747cSPeter Maydell 4163698747cSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 4173698747cSPeter Maydell return false; 4183698747cSPeter Maydell } 4193698747cSPeter Maydell 4203698747cSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 4213698747cSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 4223698747cSPeter Maydell return false; 4233698747cSPeter Maydell } 4243698747cSPeter Maydell 4253698747cSPeter Maydell if (size == 3) { 4263698747cSPeter Maydell if (nregs != 4 || a->a == 0) { 4273698747cSPeter Maydell return false; 4283698747cSPeter Maydell } 4293698747cSPeter Maydell /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */ 4303698747cSPeter Maydell size = 2; 4313698747cSPeter Maydell } 4323698747cSPeter Maydell if (nregs == 1 && a->a == 1 && size == 0) { 4333698747cSPeter Maydell return false; 4343698747cSPeter Maydell } 4353698747cSPeter Maydell if (nregs == 3 && a->a == 1) { 4363698747cSPeter Maydell return false; 4373698747cSPeter Maydell } 4383698747cSPeter Maydell 4393698747cSPeter Maydell if (!vfp_access_check(s)) { 4403698747cSPeter Maydell return true; 4413698747cSPeter Maydell } 4423698747cSPeter Maydell 4433698747cSPeter Maydell /* 4443698747cSPeter Maydell * VLD1 to all lanes: T bit indicates how many Dregs to write. 4453698747cSPeter Maydell * VLD2/3/4 to all lanes: T bit indicates register stride. 4463698747cSPeter Maydell */ 4473698747cSPeter Maydell stride = a->t ? 2 : 1; 4483698747cSPeter Maydell vec_size = nregs == 1 ? stride * 8 : 8; 4493698747cSPeter Maydell 4503698747cSPeter Maydell tmp = tcg_temp_new_i32(); 4513698747cSPeter Maydell addr = tcg_temp_new_i32(); 4523698747cSPeter Maydell load_reg_var(s, addr, a->rn); 4533698747cSPeter Maydell for (reg = 0; reg < nregs; reg++) { 4543698747cSPeter Maydell gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), 4553698747cSPeter Maydell s->be_data | size); 4563698747cSPeter Maydell if ((vd & 1) && vec_size == 16) { 4573698747cSPeter Maydell /* 4583698747cSPeter Maydell * We cannot write 16 bytes at once because the 4593698747cSPeter Maydell * destination is unaligned. 4603698747cSPeter Maydell */ 4613698747cSPeter Maydell tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0), 4623698747cSPeter Maydell 8, 8, tmp); 4633698747cSPeter Maydell tcg_gen_gvec_mov(0, neon_reg_offset(vd + 1, 0), 4643698747cSPeter Maydell neon_reg_offset(vd, 0), 8, 8); 4653698747cSPeter Maydell } else { 4663698747cSPeter Maydell tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0), 4673698747cSPeter Maydell vec_size, vec_size, tmp); 4683698747cSPeter Maydell } 4693698747cSPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << size); 4703698747cSPeter Maydell vd += stride; 4713698747cSPeter Maydell } 4723698747cSPeter Maydell tcg_temp_free_i32(tmp); 4733698747cSPeter Maydell tcg_temp_free_i32(addr); 4743698747cSPeter Maydell 4753698747cSPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs); 4763698747cSPeter Maydell 4773698747cSPeter Maydell return true; 4783698747cSPeter Maydell } 479123ce4e3SPeter Maydell 480123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) 481123ce4e3SPeter Maydell { 482123ce4e3SPeter Maydell /* Neon load/store single structure to one lane */ 483123ce4e3SPeter Maydell int reg; 484123ce4e3SPeter Maydell int nregs = a->n + 1; 485123ce4e3SPeter Maydell int vd = a->vd; 486123ce4e3SPeter Maydell TCGv_i32 addr, tmp; 487123ce4e3SPeter Maydell 488123ce4e3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 489123ce4e3SPeter Maydell return false; 490123ce4e3SPeter Maydell } 491123ce4e3SPeter Maydell 492123ce4e3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 493123ce4e3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 494123ce4e3SPeter Maydell return false; 495123ce4e3SPeter Maydell } 496123ce4e3SPeter Maydell 497123ce4e3SPeter Maydell /* Catch the UNDEF cases. This is unavoidably a bit messy. */ 498123ce4e3SPeter Maydell switch (nregs) { 499123ce4e3SPeter Maydell case 1: 500123ce4e3SPeter Maydell if (((a->align & (1 << a->size)) != 0) || 501123ce4e3SPeter Maydell (a->size == 2 && ((a->align & 3) == 1 || (a->align & 3) == 2))) { 502123ce4e3SPeter Maydell return false; 503123ce4e3SPeter Maydell } 504123ce4e3SPeter Maydell break; 505123ce4e3SPeter Maydell case 3: 506123ce4e3SPeter Maydell if ((a->align & 1) != 0) { 507123ce4e3SPeter Maydell return false; 508123ce4e3SPeter Maydell } 509123ce4e3SPeter Maydell /* fall through */ 510123ce4e3SPeter Maydell case 2: 511123ce4e3SPeter Maydell if (a->size == 2 && (a->align & 2) != 0) { 512123ce4e3SPeter Maydell return false; 513123ce4e3SPeter Maydell } 514123ce4e3SPeter Maydell break; 515123ce4e3SPeter Maydell case 4: 516123ce4e3SPeter Maydell if ((a->size == 2) && ((a->align & 3) == 3)) { 517123ce4e3SPeter Maydell return false; 518123ce4e3SPeter Maydell } 519123ce4e3SPeter Maydell break; 520123ce4e3SPeter Maydell default: 521123ce4e3SPeter Maydell abort(); 522123ce4e3SPeter Maydell } 523123ce4e3SPeter Maydell if ((vd + a->stride * (nregs - 1)) > 31) { 524123ce4e3SPeter Maydell /* 525123ce4e3SPeter Maydell * Attempts to write off the end of the register file are 526123ce4e3SPeter Maydell * UNPREDICTABLE; we choose to UNDEF because otherwise we would 527123ce4e3SPeter Maydell * access off the end of the array that holds the register data. 528123ce4e3SPeter Maydell */ 529123ce4e3SPeter Maydell return false; 530123ce4e3SPeter Maydell } 531123ce4e3SPeter Maydell 532123ce4e3SPeter Maydell if (!vfp_access_check(s)) { 533123ce4e3SPeter Maydell return true; 534123ce4e3SPeter Maydell } 535123ce4e3SPeter Maydell 536123ce4e3SPeter Maydell tmp = tcg_temp_new_i32(); 537123ce4e3SPeter Maydell addr = tcg_temp_new_i32(); 538123ce4e3SPeter Maydell load_reg_var(s, addr, a->rn); 539123ce4e3SPeter Maydell /* 540123ce4e3SPeter Maydell * TODO: if we implemented alignment exceptions, we should check 541123ce4e3SPeter Maydell * addr against the alignment encoded in a->align here. 542123ce4e3SPeter Maydell */ 543123ce4e3SPeter Maydell for (reg = 0; reg < nregs; reg++) { 544123ce4e3SPeter Maydell if (a->l) { 545123ce4e3SPeter Maydell gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), 546123ce4e3SPeter Maydell s->be_data | a->size); 547123ce4e3SPeter Maydell neon_store_element(vd, a->reg_idx, a->size, tmp); 548123ce4e3SPeter Maydell } else { /* Store */ 549123ce4e3SPeter Maydell neon_load_element(tmp, vd, a->reg_idx, a->size); 550123ce4e3SPeter Maydell gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), 551123ce4e3SPeter Maydell s->be_data | a->size); 552123ce4e3SPeter Maydell } 553123ce4e3SPeter Maydell vd += a->stride; 554123ce4e3SPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << a->size); 555123ce4e3SPeter Maydell } 556123ce4e3SPeter Maydell tcg_temp_free_i32(addr); 557123ce4e3SPeter Maydell tcg_temp_free_i32(tmp); 558123ce4e3SPeter Maydell 559123ce4e3SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs); 560123ce4e3SPeter Maydell 561123ce4e3SPeter Maydell return true; 562123ce4e3SPeter Maydell } 563a4e143acSPeter Maydell 564a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) 565a4e143acSPeter Maydell { 566a4e143acSPeter Maydell int vec_size = a->q ? 16 : 8; 567a4e143acSPeter Maydell int rd_ofs = neon_reg_offset(a->vd, 0); 568a4e143acSPeter Maydell int rn_ofs = neon_reg_offset(a->vn, 0); 569a4e143acSPeter Maydell int rm_ofs = neon_reg_offset(a->vm, 0); 570a4e143acSPeter Maydell 571a4e143acSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 572a4e143acSPeter Maydell return false; 573a4e143acSPeter Maydell } 574a4e143acSPeter Maydell 575a4e143acSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 576a4e143acSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 577a4e143acSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 578a4e143acSPeter Maydell return false; 579a4e143acSPeter Maydell } 580a4e143acSPeter Maydell 581a4e143acSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 582a4e143acSPeter Maydell return false; 583a4e143acSPeter Maydell } 584a4e143acSPeter Maydell 585a4e143acSPeter Maydell if (!vfp_access_check(s)) { 586a4e143acSPeter Maydell return true; 587a4e143acSPeter Maydell } 588a4e143acSPeter Maydell 589a4e143acSPeter Maydell fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); 590a4e143acSPeter Maydell return true; 591a4e143acSPeter Maydell } 592a4e143acSPeter Maydell 593a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC) \ 594a4e143acSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 595a4e143acSPeter Maydell { \ 596a4e143acSPeter Maydell return do_3same(s, a, FUNC); \ 597a4e143acSPeter Maydell } 598a4e143acSPeter Maydell 599a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add) 600a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub) 60135a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and) 60235a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc) 60335a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or) 60435a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc) 60535a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor) 6068161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl) 6078161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl) 60835a548edSPeter Maydell 60935a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */ 61035a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ 61135a548edSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 61235a548edSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 61335a548edSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 61435a548edSPeter Maydell { \ 61535a548edSPeter Maydell tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz); \ 61635a548edSPeter Maydell } \ 61735a548edSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 61835a548edSPeter Maydell 61935a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs) 62035a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs) 62135a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs) 62236b59310SPeter Maydell 62336b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC) \ 62436b59310SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 62536b59310SPeter Maydell { \ 62636b59310SPeter Maydell if (a->size == 3) { \ 62736b59310SPeter Maydell return false; \ 62836b59310SPeter Maydell } \ 62936b59310SPeter Maydell return do_3same(s, a, FUNC); \ 63036b59310SPeter Maydell } 63136b59310SPeter Maydell 63236b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) 63336b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) 63436b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) 63536b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) 6360de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) 63727106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) 63827106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) 6398161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst) 64002bd0cdbSPeter Maydell 64102bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND) \ 64202bd0cdbSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 64302bd0cdbSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 64402bd0cdbSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 64502bd0cdbSPeter Maydell { \ 64602bd0cdbSPeter Maydell tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \ 64702bd0cdbSPeter Maydell } \ 64802bd0cdbSPeter Maydell DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) 64902bd0cdbSPeter Maydell 65002bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT) 65102bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU) 65202bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE) 65302bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) 65402bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ) 65502bd0cdbSPeter Maydell 6567a9497f1SPeter Maydell #define DO_3SAME_GVEC4(INSN, OPARRAY) \ 6577a9497f1SPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 6587a9497f1SPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 6597a9497f1SPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 6607a9497f1SPeter Maydell { \ 6617a9497f1SPeter Maydell tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc), \ 6627a9497f1SPeter Maydell rn_ofs, rm_ofs, oprsz, maxsz, &OPARRAY[vece]); \ 6637a9497f1SPeter Maydell } \ 6647a9497f1SPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 6657a9497f1SPeter Maydell 6667a9497f1SPeter Maydell DO_3SAME_GVEC4(VQADD_S, sqadd_op) 6677a9497f1SPeter Maydell DO_3SAME_GVEC4(VQADD_U, uqadd_op) 6687a9497f1SPeter Maydell DO_3SAME_GVEC4(VQSUB_S, sqsub_op) 6697a9497f1SPeter Maydell DO_3SAME_GVEC4(VQSUB_U, uqsub_op) 6700de34fd4SPeter Maydell 6710de34fd4SPeter Maydell static void gen_VMUL_p_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, 6720de34fd4SPeter Maydell uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) 6730de34fd4SPeter Maydell { 6740de34fd4SPeter Maydell tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 6750de34fd4SPeter Maydell 0, gen_helper_gvec_pmul_b); 6760de34fd4SPeter Maydell } 6770de34fd4SPeter Maydell 6780de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) 6790de34fd4SPeter Maydell { 6800de34fd4SPeter Maydell if (a->size != 0) { 6810de34fd4SPeter Maydell return false; 6820de34fd4SPeter Maydell } 6830de34fd4SPeter Maydell return do_3same(s, a, gen_VMUL_p_3s); 6840de34fd4SPeter Maydell } 685