1 /* 2 * ARM translation: AArch32 VFP instructions 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * Copyright (c) 2005-2007 CodeSourcery 6 * Copyright (c) 2007 OpenedHand, Ltd. 7 * Copyright (c) 2019 Linaro, Ltd. 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 21 */ 22 23 #include "qemu/osdep.h" 24 #include "tcg/tcg-op.h" 25 #include "tcg/tcg-op-gvec.h" 26 #include "exec/exec-all.h" 27 #include "exec/gen-icount.h" 28 #include "translate.h" 29 #include "translate-a32.h" 30 31 /* Include the generated VFP decoder */ 32 #include "decode-vfp.c.inc" 33 #include "decode-vfp-uncond.c.inc" 34 35 static inline void vfp_load_reg64(TCGv_i64 var, int reg) 36 { 37 tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(true, reg)); 38 } 39 40 static inline void vfp_store_reg64(TCGv_i64 var, int reg) 41 { 42 tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(true, reg)); 43 } 44 45 static inline void vfp_load_reg32(TCGv_i32 var, int reg) 46 { 47 tcg_gen_ld_i32(var, cpu_env, vfp_reg_offset(false, reg)); 48 } 49 50 static inline void vfp_store_reg32(TCGv_i32 var, int reg) 51 { 52 tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg)); 53 } 54 55 /* 56 * The imm8 encodes the sign bit, enough bits to represent an exponent in 57 * the range 01....1xx to 10....0xx, and the most significant 4 bits of 58 * the mantissa; see VFPExpandImm() in the v8 ARM ARM. 59 */ 60 uint64_t vfp_expand_imm(int size, uint8_t imm8) 61 { 62 uint64_t imm; 63 64 switch (size) { 65 case MO_64: 66 imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | 67 (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) | 68 extract32(imm8, 0, 6); 69 imm <<= 48; 70 break; 71 case MO_32: 72 imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | 73 (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) | 74 (extract32(imm8, 0, 6) << 3); 75 imm <<= 16; 76 break; 77 case MO_16: 78 imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | 79 (extract32(imm8, 6, 1) ? 0x3000 : 0x4000) | 80 (extract32(imm8, 0, 6) << 6); 81 break; 82 default: 83 g_assert_not_reached(); 84 } 85 return imm; 86 } 87 88 /* 89 * Return the offset of a 16-bit half of the specified VFP single-precision 90 * register. If top is true, returns the top 16 bits; otherwise the bottom 91 * 16 bits. 92 */ 93 static inline long vfp_f16_offset(unsigned reg, bool top) 94 { 95 long offs = vfp_reg_offset(false, reg); 96 #if HOST_BIG_ENDIAN 97 if (!top) { 98 offs += 2; 99 } 100 #else 101 if (top) { 102 offs += 2; 103 } 104 #endif 105 return offs; 106 } 107 108 /* 109 * Generate code for M-profile lazy FP state preservation if needed; 110 * this corresponds to the pseudocode PreserveFPState() function. 111 */ 112 static void gen_preserve_fp_state(DisasContext *s, bool skip_context_update) 113 { 114 if (s->v7m_lspact) { 115 /* 116 * Lazy state saving affects external memory and also the NVIC, 117 * so we must mark it as an IO operation for icount (and cause 118 * this to be the last insn in the TB). 119 */ 120 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { 121 s->base.is_jmp = DISAS_UPDATE_EXIT; 122 gen_io_start(); 123 } 124 gen_helper_v7m_preserve_fp_state(cpu_env); 125 /* 126 * If the preserve_fp_state helper doesn't throw an exception 127 * then it will clear LSPACT; we don't need to repeat this for 128 * any further FP insns in this TB. 129 */ 130 s->v7m_lspact = false; 131 /* 132 * The helper might have zeroed VPR, so we do not know the 133 * correct value for the MVE_NO_PRED TB flag any more. 134 * If we're about to create a new fp context then that 135 * will precisely determine the MVE_NO_PRED value (see 136 * gen_update_fp_context()). Otherwise, we must: 137 * - set s->mve_no_pred to false, so this instruction 138 * is generated to use helper functions 139 * - end the TB now, without chaining to the next TB 140 */ 141 if (skip_context_update || !s->v7m_new_fp_ctxt_needed) { 142 s->mve_no_pred = false; 143 s->base.is_jmp = DISAS_UPDATE_NOCHAIN; 144 } 145 } 146 } 147 148 /* 149 * Generate code for M-profile FP context handling: update the 150 * ownership of the FP context, and create a new context if 151 * necessary. This corresponds to the parts of the pseudocode 152 * ExecuteFPCheck() after the inital PreserveFPState() call. 153 */ 154 static void gen_update_fp_context(DisasContext *s) 155 { 156 /* Update ownership of FP context: set FPCCR.S to match current state */ 157 if (s->v8m_fpccr_s_wrong) { 158 TCGv_i32 tmp; 159 160 tmp = load_cpu_field(v7m.fpccr[M_REG_S]); 161 if (s->v8m_secure) { 162 tcg_gen_ori_i32(tmp, tmp, R_V7M_FPCCR_S_MASK); 163 } else { 164 tcg_gen_andi_i32(tmp, tmp, ~R_V7M_FPCCR_S_MASK); 165 } 166 store_cpu_field(tmp, v7m.fpccr[M_REG_S]); 167 /* Don't need to do this for any further FP insns in this TB */ 168 s->v8m_fpccr_s_wrong = false; 169 } 170 171 if (s->v7m_new_fp_ctxt_needed) { 172 /* 173 * Create new FP context by updating CONTROL.FPCA, CONTROL.SFPA, 174 * the FPSCR, and VPR. 175 */ 176 TCGv_i32 control, fpscr; 177 uint32_t bits = R_V7M_CONTROL_FPCA_MASK; 178 179 fpscr = load_cpu_field(v7m.fpdscr[s->v8m_secure]); 180 gen_helper_vfp_set_fpscr(cpu_env, fpscr); 181 if (dc_isar_feature(aa32_mve, s)) { 182 store_cpu_field(tcg_constant_i32(0), v7m.vpr); 183 } 184 /* 185 * We just updated the FPSCR and VPR. Some of this state is cached 186 * in the MVE_NO_PRED TB flag. We want to avoid having to end the 187 * TB here, which means we need the new value of the MVE_NO_PRED 188 * flag to be exactly known here and the same for all executions. 189 * Luckily FPDSCR.LTPSIZE is always constant 4 and the VPR is 190 * always set to 0, so the new MVE_NO_PRED flag is always 1 191 * if and only if we have MVE. 192 * 193 * (The other FPSCR state cached in TB flags is VECLEN and VECSTRIDE, 194 * but those do not exist for M-profile, so are not relevant here.) 195 */ 196 s->mve_no_pred = dc_isar_feature(aa32_mve, s); 197 198 if (s->v8m_secure) { 199 bits |= R_V7M_CONTROL_SFPA_MASK; 200 } 201 control = load_cpu_field(v7m.control[M_REG_S]); 202 tcg_gen_ori_i32(control, control, bits); 203 store_cpu_field(control, v7m.control[M_REG_S]); 204 /* Don't need to do this for any further FP insns in this TB */ 205 s->v7m_new_fp_ctxt_needed = false; 206 } 207 } 208 209 /* 210 * Check that VFP access is enabled, A-profile specific version. 211 * 212 * If VFP is enabled, return true. If not, emit code to generate an 213 * appropriate exception and return false. 214 * The ignore_vfp_enabled argument specifies that we should ignore 215 * whether VFP is enabled via FPEXC.EN: this should be true for FMXR/FMRX 216 * accesses to FPSID, FPEXC, MVFR0, MVFR1, MVFR2, and false for all other insns. 217 */ 218 static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled) 219 { 220 if (s->fp_excp_el) { 221 /* 222 * The full syndrome is only used for HSR when HCPTR traps: 223 * For v8, when TA==0, coproc is RES0. 224 * For v7, any use of a Floating-point instruction or access 225 * to a Floating-point Extension register that is trapped to 226 * Hyp mode because of a trap configured in the HCPTR sets 227 * this field to 0xA. 228 */ 229 int coproc = arm_dc_feature(s, ARM_FEATURE_V8) ? 0 : 0xa; 230 uint32_t syn = syn_fp_access_trap(1, 0xe, false, coproc); 231 232 gen_exception_insn_el(s, 0, EXCP_UDEF, syn, s->fp_excp_el); 233 return false; 234 } 235 236 /* 237 * Note that rebuild_hflags_a32 has already accounted for being in EL0 238 * and the higher EL in A64 mode, etc. Unlike A64 mode, there do not 239 * appear to be any insns which touch VFP which are allowed. 240 */ 241 if (s->sme_trap_nonstreaming) { 242 gen_exception_insn(s, 0, EXCP_UDEF, 243 syn_smetrap(SME_ET_Streaming, 244 curr_insn_len(s) == 2)); 245 return false; 246 } 247 248 if (!s->vfp_enabled && !ignore_vfp_enabled) { 249 assert(!arm_dc_feature(s, ARM_FEATURE_M)); 250 unallocated_encoding(s); 251 return false; 252 } 253 return true; 254 } 255 256 /* 257 * Check that VFP access is enabled, M-profile specific version. 258 * 259 * If VFP is enabled, do the necessary M-profile lazy-FP handling and then 260 * return true. If not, emit code to generate an appropriate exception and 261 * return false. 262 * skip_context_update is true to skip the "update FP context" part of this. 263 */ 264 bool vfp_access_check_m(DisasContext *s, bool skip_context_update) 265 { 266 if (s->fp_excp_el) { 267 /* 268 * M-profile mostly catches the "FPU disabled" case early, in 269 * disas_m_nocp(), but a few insns (eg LCTP, WLSTP, DLSTP) 270 * which do coprocessor-checks are outside the large ranges of 271 * the encoding space handled by the patterns in m-nocp.decode, 272 * and for them we may need to raise NOCP here. 273 */ 274 gen_exception_insn_el(s, 0, EXCP_NOCP, 275 syn_uncategorized(), s->fp_excp_el); 276 return false; 277 } 278 279 /* Handle M-profile lazy FP state mechanics */ 280 281 /* Trigger lazy-state preservation if necessary */ 282 gen_preserve_fp_state(s, skip_context_update); 283 284 if (!skip_context_update) { 285 /* Update ownership of FP context and create new FP context if needed */ 286 gen_update_fp_context(s); 287 } 288 289 return true; 290 } 291 292 /* 293 * The most usual kind of VFP access check, for everything except 294 * FMXR/FMRX to the always-available special registers. 295 */ 296 bool vfp_access_check(DisasContext *s) 297 { 298 if (arm_dc_feature(s, ARM_FEATURE_M)) { 299 return vfp_access_check_m(s, false); 300 } else { 301 return vfp_access_check_a(s, false); 302 } 303 } 304 305 static bool trans_VSEL(DisasContext *s, arg_VSEL *a) 306 { 307 uint32_t rd, rn, rm; 308 int sz = a->sz; 309 310 if (!dc_isar_feature(aa32_vsel, s)) { 311 return false; 312 } 313 314 if (sz == 3 && !dc_isar_feature(aa32_fpdp_v2, s)) { 315 return false; 316 } 317 318 if (sz == 1 && !dc_isar_feature(aa32_fp16_arith, s)) { 319 return false; 320 } 321 322 /* UNDEF accesses to D16-D31 if they don't exist */ 323 if (sz == 3 && !dc_isar_feature(aa32_simd_r32, s) && 324 ((a->vm | a->vn | a->vd) & 0x10)) { 325 return false; 326 } 327 328 rd = a->vd; 329 rn = a->vn; 330 rm = a->vm; 331 332 if (!vfp_access_check(s)) { 333 return true; 334 } 335 336 if (sz == 3) { 337 TCGv_i64 frn, frm, dest; 338 TCGv_i64 tmp, zero, zf, nf, vf; 339 340 zero = tcg_constant_i64(0); 341 342 frn = tcg_temp_new_i64(); 343 frm = tcg_temp_new_i64(); 344 dest = tcg_temp_new_i64(); 345 346 zf = tcg_temp_new_i64(); 347 nf = tcg_temp_new_i64(); 348 vf = tcg_temp_new_i64(); 349 350 tcg_gen_extu_i32_i64(zf, cpu_ZF); 351 tcg_gen_ext_i32_i64(nf, cpu_NF); 352 tcg_gen_ext_i32_i64(vf, cpu_VF); 353 354 vfp_load_reg64(frn, rn); 355 vfp_load_reg64(frm, rm); 356 switch (a->cc) { 357 case 0: /* eq: Z */ 358 tcg_gen_movcond_i64(TCG_COND_EQ, dest, zf, zero, frn, frm); 359 break; 360 case 1: /* vs: V */ 361 tcg_gen_movcond_i64(TCG_COND_LT, dest, vf, zero, frn, frm); 362 break; 363 case 2: /* ge: N == V -> N ^ V == 0 */ 364 tmp = tcg_temp_new_i64(); 365 tcg_gen_xor_i64(tmp, vf, nf); 366 tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero, frn, frm); 367 break; 368 case 3: /* gt: !Z && N == V */ 369 tcg_gen_movcond_i64(TCG_COND_NE, dest, zf, zero, frn, frm); 370 tmp = tcg_temp_new_i64(); 371 tcg_gen_xor_i64(tmp, vf, nf); 372 tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero, dest, frm); 373 break; 374 } 375 vfp_store_reg64(dest, rd); 376 } else { 377 TCGv_i32 frn, frm, dest; 378 TCGv_i32 tmp, zero; 379 380 zero = tcg_constant_i32(0); 381 382 frn = tcg_temp_new_i32(); 383 frm = tcg_temp_new_i32(); 384 dest = tcg_temp_new_i32(); 385 vfp_load_reg32(frn, rn); 386 vfp_load_reg32(frm, rm); 387 switch (a->cc) { 388 case 0: /* eq: Z */ 389 tcg_gen_movcond_i32(TCG_COND_EQ, dest, cpu_ZF, zero, frn, frm); 390 break; 391 case 1: /* vs: V */ 392 tcg_gen_movcond_i32(TCG_COND_LT, dest, cpu_VF, zero, frn, frm); 393 break; 394 case 2: /* ge: N == V -> N ^ V == 0 */ 395 tmp = tcg_temp_new_i32(); 396 tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); 397 tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero, frn, frm); 398 break; 399 case 3: /* gt: !Z && N == V */ 400 tcg_gen_movcond_i32(TCG_COND_NE, dest, cpu_ZF, zero, frn, frm); 401 tmp = tcg_temp_new_i32(); 402 tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); 403 tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero, dest, frm); 404 break; 405 } 406 /* For fp16 the top half is always zeroes */ 407 if (sz == 1) { 408 tcg_gen_andi_i32(dest, dest, 0xffff); 409 } 410 vfp_store_reg32(dest, rd); 411 } 412 413 return true; 414 } 415 416 /* 417 * Table for converting the most common AArch32 encoding of 418 * rounding mode to arm_fprounding order (which matches the 419 * common AArch64 order); see ARM ARM pseudocode FPDecodeRM(). 420 */ 421 static const uint8_t fp_decode_rm[] = { 422 FPROUNDING_TIEAWAY, 423 FPROUNDING_TIEEVEN, 424 FPROUNDING_POSINF, 425 FPROUNDING_NEGINF, 426 }; 427 428 static bool trans_VRINT(DisasContext *s, arg_VRINT *a) 429 { 430 uint32_t rd, rm; 431 int sz = a->sz; 432 TCGv_ptr fpst; 433 TCGv_i32 tcg_rmode; 434 int rounding = fp_decode_rm[a->rm]; 435 436 if (!dc_isar_feature(aa32_vrint, s)) { 437 return false; 438 } 439 440 if (sz == 3 && !dc_isar_feature(aa32_fpdp_v2, s)) { 441 return false; 442 } 443 444 if (sz == 1 && !dc_isar_feature(aa32_fp16_arith, s)) { 445 return false; 446 } 447 448 /* UNDEF accesses to D16-D31 if they don't exist */ 449 if (sz == 3 && !dc_isar_feature(aa32_simd_r32, s) && 450 ((a->vm | a->vd) & 0x10)) { 451 return false; 452 } 453 454 rd = a->vd; 455 rm = a->vm; 456 457 if (!vfp_access_check(s)) { 458 return true; 459 } 460 461 if (sz == 1) { 462 fpst = fpstatus_ptr(FPST_FPCR_F16); 463 } else { 464 fpst = fpstatus_ptr(FPST_FPCR); 465 } 466 467 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding)); 468 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); 469 470 if (sz == 3) { 471 TCGv_i64 tcg_op; 472 TCGv_i64 tcg_res; 473 tcg_op = tcg_temp_new_i64(); 474 tcg_res = tcg_temp_new_i64(); 475 vfp_load_reg64(tcg_op, rm); 476 gen_helper_rintd(tcg_res, tcg_op, fpst); 477 vfp_store_reg64(tcg_res, rd); 478 } else { 479 TCGv_i32 tcg_op; 480 TCGv_i32 tcg_res; 481 tcg_op = tcg_temp_new_i32(); 482 tcg_res = tcg_temp_new_i32(); 483 vfp_load_reg32(tcg_op, rm); 484 if (sz == 1) { 485 gen_helper_rinth(tcg_res, tcg_op, fpst); 486 } else { 487 gen_helper_rints(tcg_res, tcg_op, fpst); 488 } 489 vfp_store_reg32(tcg_res, rd); 490 } 491 492 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); 493 return true; 494 } 495 496 static bool trans_VCVT(DisasContext *s, arg_VCVT *a) 497 { 498 uint32_t rd, rm; 499 int sz = a->sz; 500 TCGv_ptr fpst; 501 TCGv_i32 tcg_rmode, tcg_shift; 502 int rounding = fp_decode_rm[a->rm]; 503 bool is_signed = a->op; 504 505 if (!dc_isar_feature(aa32_vcvt_dr, s)) { 506 return false; 507 } 508 509 if (sz == 3 && !dc_isar_feature(aa32_fpdp_v2, s)) { 510 return false; 511 } 512 513 if (sz == 1 && !dc_isar_feature(aa32_fp16_arith, s)) { 514 return false; 515 } 516 517 /* UNDEF accesses to D16-D31 if they don't exist */ 518 if (sz == 3 && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { 519 return false; 520 } 521 522 rd = a->vd; 523 rm = a->vm; 524 525 if (!vfp_access_check(s)) { 526 return true; 527 } 528 529 if (sz == 1) { 530 fpst = fpstatus_ptr(FPST_FPCR_F16); 531 } else { 532 fpst = fpstatus_ptr(FPST_FPCR); 533 } 534 535 tcg_shift = tcg_constant_i32(0); 536 537 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding)); 538 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); 539 540 if (sz == 3) { 541 TCGv_i64 tcg_double, tcg_res; 542 TCGv_i32 tcg_tmp; 543 tcg_double = tcg_temp_new_i64(); 544 tcg_res = tcg_temp_new_i64(); 545 tcg_tmp = tcg_temp_new_i32(); 546 vfp_load_reg64(tcg_double, rm); 547 if (is_signed) { 548 gen_helper_vfp_tosld(tcg_res, tcg_double, tcg_shift, fpst); 549 } else { 550 gen_helper_vfp_tould(tcg_res, tcg_double, tcg_shift, fpst); 551 } 552 tcg_gen_extrl_i64_i32(tcg_tmp, tcg_res); 553 vfp_store_reg32(tcg_tmp, rd); 554 } else { 555 TCGv_i32 tcg_single, tcg_res; 556 tcg_single = tcg_temp_new_i32(); 557 tcg_res = tcg_temp_new_i32(); 558 vfp_load_reg32(tcg_single, rm); 559 if (sz == 1) { 560 if (is_signed) { 561 gen_helper_vfp_toslh(tcg_res, tcg_single, tcg_shift, fpst); 562 } else { 563 gen_helper_vfp_toulh(tcg_res, tcg_single, tcg_shift, fpst); 564 } 565 } else { 566 if (is_signed) { 567 gen_helper_vfp_tosls(tcg_res, tcg_single, tcg_shift, fpst); 568 } else { 569 gen_helper_vfp_touls(tcg_res, tcg_single, tcg_shift, fpst); 570 } 571 } 572 vfp_store_reg32(tcg_res, rd); 573 } 574 575 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); 576 return true; 577 } 578 579 bool mve_skip_vmov(DisasContext *s, int vn, int index, int size) 580 { 581 /* 582 * In a CPU with MVE, the VMOV (vector lane to general-purpose register) 583 * and VMOV (general-purpose register to vector lane) insns are not 584 * predicated, but they are subject to beatwise execution if they are 585 * not in an IT block. 586 * 587 * Since our implementation always executes all 4 beats in one tick, 588 * this means only that if PSR.ECI says we should not be executing 589 * the beat corresponding to the lane of the vector register being 590 * accessed then we should skip performing the move, and that we need 591 * to do the usual check for bad ECI state and advance of ECI state. 592 * 593 * Note that if PSR.ECI is non-zero then we cannot be in an IT block. 594 * 595 * Return true if this VMOV scalar <-> gpreg should be skipped because 596 * the MVE PSR.ECI state says we skip the beat where the store happens. 597 */ 598 599 /* Calculate the byte offset into Qn which we're going to access */ 600 int ofs = (index << size) + ((vn & 1) * 8); 601 602 if (!dc_isar_feature(aa32_mve, s)) { 603 return false; 604 } 605 606 switch (s->eci) { 607 case ECI_NONE: 608 return false; 609 case ECI_A0: 610 return ofs < 4; 611 case ECI_A0A1: 612 return ofs < 8; 613 case ECI_A0A1A2: 614 case ECI_A0A1A2B0: 615 return ofs < 12; 616 default: 617 g_assert_not_reached(); 618 } 619 } 620 621 static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a) 622 { 623 /* VMOV scalar to general purpose register */ 624 TCGv_i32 tmp; 625 626 /* 627 * SIZE == MO_32 is a VFP instruction; otherwise NEON. MVE has 628 * all sizes, whether the CPU has fp or not. 629 */ 630 if (!dc_isar_feature(aa32_mve, s)) { 631 if (a->size == MO_32 632 ? !dc_isar_feature(aa32_fpsp_v2, s) 633 : !arm_dc_feature(s, ARM_FEATURE_NEON)) { 634 return false; 635 } 636 } 637 638 /* UNDEF accesses to D16-D31 if they don't exist */ 639 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) { 640 return false; 641 } 642 643 if (dc_isar_feature(aa32_mve, s)) { 644 if (!mve_eci_check(s)) { 645 return true; 646 } 647 } 648 649 if (!vfp_access_check(s)) { 650 return true; 651 } 652 653 if (!mve_skip_vmov(s, a->vn, a->index, a->size)) { 654 tmp = tcg_temp_new_i32(); 655 read_neon_element32(tmp, a->vn, a->index, 656 a->size | (a->u ? 0 : MO_SIGN)); 657 store_reg(s, a->rt, tmp); 658 } 659 660 if (dc_isar_feature(aa32_mve, s)) { 661 mve_update_and_store_eci(s); 662 } 663 return true; 664 } 665 666 static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a) 667 { 668 /* VMOV general purpose register to scalar */ 669 TCGv_i32 tmp; 670 671 /* 672 * SIZE == MO_32 is a VFP instruction; otherwise NEON. MVE has 673 * all sizes, whether the CPU has fp or not. 674 */ 675 if (!dc_isar_feature(aa32_mve, s)) { 676 if (a->size == MO_32 677 ? !dc_isar_feature(aa32_fpsp_v2, s) 678 : !arm_dc_feature(s, ARM_FEATURE_NEON)) { 679 return false; 680 } 681 } 682 683 /* UNDEF accesses to D16-D31 if they don't exist */ 684 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) { 685 return false; 686 } 687 688 if (dc_isar_feature(aa32_mve, s)) { 689 if (!mve_eci_check(s)) { 690 return true; 691 } 692 } 693 694 if (!vfp_access_check(s)) { 695 return true; 696 } 697 698 if (!mve_skip_vmov(s, a->vn, a->index, a->size)) { 699 tmp = load_reg(s, a->rt); 700 write_neon_element32(tmp, a->vn, a->index, a->size); 701 } 702 703 if (dc_isar_feature(aa32_mve, s)) { 704 mve_update_and_store_eci(s); 705 } 706 return true; 707 } 708 709 static bool trans_VDUP(DisasContext *s, arg_VDUP *a) 710 { 711 /* VDUP (general purpose register) */ 712 TCGv_i32 tmp; 713 int size, vec_size; 714 715 if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 716 return false; 717 } 718 719 /* UNDEF accesses to D16-D31 if they don't exist */ 720 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) { 721 return false; 722 } 723 724 if (a->b && a->e) { 725 return false; 726 } 727 728 if (a->q && (a->vn & 1)) { 729 return false; 730 } 731 732 vec_size = a->q ? 16 : 8; 733 if (a->b) { 734 size = 0; 735 } else if (a->e) { 736 size = 1; 737 } else { 738 size = 2; 739 } 740 741 if (!vfp_access_check(s)) { 742 return true; 743 } 744 745 tmp = load_reg(s, a->rt); 746 tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(a->vn), 747 vec_size, vec_size, tmp); 748 return true; 749 } 750 751 static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) 752 { 753 TCGv_i32 tmp; 754 bool ignore_vfp_enabled = false; 755 756 if (arm_dc_feature(s, ARM_FEATURE_M)) { 757 /* M profile version was already handled in m-nocp.decode */ 758 return false; 759 } 760 761 if (!dc_isar_feature(aa32_fpsp_v2, s)) { 762 return false; 763 } 764 765 switch (a->reg) { 766 case ARM_VFP_FPSID: 767 /* 768 * VFPv2 allows access to FPSID from userspace; VFPv3 restricts 769 * all ID registers to privileged access only. 770 */ 771 if (IS_USER(s) && dc_isar_feature(aa32_fpsp_v3, s)) { 772 return false; 773 } 774 ignore_vfp_enabled = true; 775 break; 776 case ARM_VFP_MVFR0: 777 case ARM_VFP_MVFR1: 778 if (IS_USER(s) || !arm_dc_feature(s, ARM_FEATURE_MVFR)) { 779 return false; 780 } 781 ignore_vfp_enabled = true; 782 break; 783 case ARM_VFP_MVFR2: 784 if (IS_USER(s) || !arm_dc_feature(s, ARM_FEATURE_V8)) { 785 return false; 786 } 787 ignore_vfp_enabled = true; 788 break; 789 case ARM_VFP_FPSCR: 790 break; 791 case ARM_VFP_FPEXC: 792 if (IS_USER(s)) { 793 return false; 794 } 795 ignore_vfp_enabled = true; 796 break; 797 case ARM_VFP_FPINST: 798 case ARM_VFP_FPINST2: 799 /* Not present in VFPv3 */ 800 if (IS_USER(s) || dc_isar_feature(aa32_fpsp_v3, s)) { 801 return false; 802 } 803 break; 804 default: 805 return false; 806 } 807 808 /* 809 * Call vfp_access_check_a() directly, because we need to tell 810 * it to ignore FPEXC.EN for some register accesses. 811 */ 812 if (!vfp_access_check_a(s, ignore_vfp_enabled)) { 813 return true; 814 } 815 816 if (a->l) { 817 /* VMRS, move VFP special register to gp register */ 818 switch (a->reg) { 819 case ARM_VFP_MVFR0: 820 case ARM_VFP_MVFR1: 821 case ARM_VFP_MVFR2: 822 case ARM_VFP_FPSID: 823 if (s->current_el == 1) { 824 gen_set_condexec(s); 825 gen_update_pc(s, 0); 826 gen_helper_check_hcr_el2_trap(cpu_env, 827 tcg_constant_i32(a->rt), 828 tcg_constant_i32(a->reg)); 829 } 830 /* fall through */ 831 case ARM_VFP_FPEXC: 832 case ARM_VFP_FPINST: 833 case ARM_VFP_FPINST2: 834 tmp = load_cpu_field(vfp.xregs[a->reg]); 835 break; 836 case ARM_VFP_FPSCR: 837 if (a->rt == 15) { 838 tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); 839 tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK); 840 } else { 841 tmp = tcg_temp_new_i32(); 842 gen_helper_vfp_get_fpscr(tmp, cpu_env); 843 } 844 break; 845 default: 846 g_assert_not_reached(); 847 } 848 849 if (a->rt == 15) { 850 /* Set the 4 flag bits in the CPSR. */ 851 gen_set_nzcv(tmp); 852 } else { 853 store_reg(s, a->rt, tmp); 854 } 855 } else { 856 /* VMSR, move gp register to VFP special register */ 857 switch (a->reg) { 858 case ARM_VFP_FPSID: 859 case ARM_VFP_MVFR0: 860 case ARM_VFP_MVFR1: 861 case ARM_VFP_MVFR2: 862 /* Writes are ignored. */ 863 break; 864 case ARM_VFP_FPSCR: 865 tmp = load_reg(s, a->rt); 866 gen_helper_vfp_set_fpscr(cpu_env, tmp); 867 gen_lookup_tb(s); 868 break; 869 case ARM_VFP_FPEXC: 870 /* 871 * TODO: VFP subarchitecture support. 872 * For now, keep the EN bit only 873 */ 874 tmp = load_reg(s, a->rt); 875 tcg_gen_andi_i32(tmp, tmp, 1 << 30); 876 store_cpu_field(tmp, vfp.xregs[a->reg]); 877 gen_lookup_tb(s); 878 break; 879 case ARM_VFP_FPINST: 880 case ARM_VFP_FPINST2: 881 tmp = load_reg(s, a->rt); 882 store_cpu_field(tmp, vfp.xregs[a->reg]); 883 break; 884 default: 885 g_assert_not_reached(); 886 } 887 } 888 889 return true; 890 } 891 892 893 static bool trans_VMOV_half(DisasContext *s, arg_VMOV_single *a) 894 { 895 TCGv_i32 tmp; 896 897 if (!dc_isar_feature(aa32_fp16_arith, s)) { 898 return false; 899 } 900 901 if (a->rt == 15) { 902 /* UNPREDICTABLE; we choose to UNDEF */ 903 return false; 904 } 905 906 if (!vfp_access_check(s)) { 907 return true; 908 } 909 910 if (a->l) { 911 /* VFP to general purpose register */ 912 tmp = tcg_temp_new_i32(); 913 vfp_load_reg32(tmp, a->vn); 914 tcg_gen_andi_i32(tmp, tmp, 0xffff); 915 store_reg(s, a->rt, tmp); 916 } else { 917 /* general purpose register to VFP */ 918 tmp = load_reg(s, a->rt); 919 tcg_gen_andi_i32(tmp, tmp, 0xffff); 920 vfp_store_reg32(tmp, a->vn); 921 } 922 923 return true; 924 } 925 926 static bool trans_VMOV_single(DisasContext *s, arg_VMOV_single *a) 927 { 928 TCGv_i32 tmp; 929 930 if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 931 return false; 932 } 933 934 if (!vfp_access_check(s)) { 935 return true; 936 } 937 938 if (a->l) { 939 /* VFP to general purpose register */ 940 tmp = tcg_temp_new_i32(); 941 vfp_load_reg32(tmp, a->vn); 942 if (a->rt == 15) { 943 /* Set the 4 flag bits in the CPSR. */ 944 gen_set_nzcv(tmp); 945 } else { 946 store_reg(s, a->rt, tmp); 947 } 948 } else { 949 /* general purpose register to VFP */ 950 tmp = load_reg(s, a->rt); 951 vfp_store_reg32(tmp, a->vn); 952 } 953 954 return true; 955 } 956 957 static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a) 958 { 959 TCGv_i32 tmp; 960 961 if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 962 return false; 963 } 964 965 /* 966 * VMOV between two general-purpose registers and two single precision 967 * floating point registers 968 */ 969 if (!vfp_access_check(s)) { 970 return true; 971 } 972 973 if (a->op) { 974 /* fpreg to gpreg */ 975 tmp = tcg_temp_new_i32(); 976 vfp_load_reg32(tmp, a->vm); 977 store_reg(s, a->rt, tmp); 978 tmp = tcg_temp_new_i32(); 979 vfp_load_reg32(tmp, a->vm + 1); 980 store_reg(s, a->rt2, tmp); 981 } else { 982 /* gpreg to fpreg */ 983 tmp = load_reg(s, a->rt); 984 vfp_store_reg32(tmp, a->vm); 985 tmp = load_reg(s, a->rt2); 986 vfp_store_reg32(tmp, a->vm + 1); 987 } 988 989 return true; 990 } 991 992 static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_dp *a) 993 { 994 TCGv_i32 tmp; 995 996 /* 997 * VMOV between two general-purpose registers and one double precision 998 * floating point register. Note that this does not require support 999 * for double precision arithmetic. 1000 */ 1001 if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 1002 return false; 1003 } 1004 1005 /* UNDEF accesses to D16-D31 if they don't exist */ 1006 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { 1007 return false; 1008 } 1009 1010 if (!vfp_access_check(s)) { 1011 return true; 1012 } 1013 1014 if (a->op) { 1015 /* fpreg to gpreg */ 1016 tmp = tcg_temp_new_i32(); 1017 vfp_load_reg32(tmp, a->vm * 2); 1018 store_reg(s, a->rt, tmp); 1019 tmp = tcg_temp_new_i32(); 1020 vfp_load_reg32(tmp, a->vm * 2 + 1); 1021 store_reg(s, a->rt2, tmp); 1022 } else { 1023 /* gpreg to fpreg */ 1024 tmp = load_reg(s, a->rt); 1025 vfp_store_reg32(tmp, a->vm * 2); 1026 tmp = load_reg(s, a->rt2); 1027 vfp_store_reg32(tmp, a->vm * 2 + 1); 1028 } 1029 1030 return true; 1031 } 1032 1033 static bool trans_VLDR_VSTR_hp(DisasContext *s, arg_VLDR_VSTR_sp *a) 1034 { 1035 uint32_t offset; 1036 TCGv_i32 addr, tmp; 1037 1038 if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 1039 return false; 1040 } 1041 1042 if (!vfp_access_check(s)) { 1043 return true; 1044 } 1045 1046 /* imm8 field is offset/2 for fp16, unlike fp32 and fp64 */ 1047 offset = a->imm << 1; 1048 if (!a->u) { 1049 offset = -offset; 1050 } 1051 1052 /* For thumb, use of PC is UNPREDICTABLE. */ 1053 addr = add_reg_for_lit(s, a->rn, offset); 1054 tmp = tcg_temp_new_i32(); 1055 if (a->l) { 1056 gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), MO_UW | MO_ALIGN); 1057 vfp_store_reg32(tmp, a->vd); 1058 } else { 1059 vfp_load_reg32(tmp, a->vd); 1060 gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), MO_UW | MO_ALIGN); 1061 } 1062 return true; 1063 } 1064 1065 static bool trans_VLDR_VSTR_sp(DisasContext *s, arg_VLDR_VSTR_sp *a) 1066 { 1067 uint32_t offset; 1068 TCGv_i32 addr, tmp; 1069 1070 if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 1071 return false; 1072 } 1073 1074 if (!vfp_access_check(s)) { 1075 return true; 1076 } 1077 1078 offset = a->imm << 2; 1079 if (!a->u) { 1080 offset = -offset; 1081 } 1082 1083 /* For thumb, use of PC is UNPREDICTABLE. */ 1084 addr = add_reg_for_lit(s, a->rn, offset); 1085 tmp = tcg_temp_new_i32(); 1086 if (a->l) { 1087 gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN); 1088 vfp_store_reg32(tmp, a->vd); 1089 } else { 1090 vfp_load_reg32(tmp, a->vd); 1091 gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN); 1092 } 1093 return true; 1094 } 1095 1096 static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a) 1097 { 1098 uint32_t offset; 1099 TCGv_i32 addr; 1100 TCGv_i64 tmp; 1101 1102 /* Note that this does not require support for double arithmetic. */ 1103 if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 1104 return false; 1105 } 1106 1107 /* UNDEF accesses to D16-D31 if they don't exist */ 1108 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 1109 return false; 1110 } 1111 1112 if (!vfp_access_check(s)) { 1113 return true; 1114 } 1115 1116 offset = a->imm << 2; 1117 if (!a->u) { 1118 offset = -offset; 1119 } 1120 1121 /* For thumb, use of PC is UNPREDICTABLE. */ 1122 addr = add_reg_for_lit(s, a->rn, offset); 1123 tmp = tcg_temp_new_i64(); 1124 if (a->l) { 1125 gen_aa32_ld_i64(s, tmp, addr, get_mem_index(s), MO_UQ | MO_ALIGN_4); 1126 vfp_store_reg64(tmp, a->vd); 1127 } else { 1128 vfp_load_reg64(tmp, a->vd); 1129 gen_aa32_st_i64(s, tmp, addr, get_mem_index(s), MO_UQ | MO_ALIGN_4); 1130 } 1131 return true; 1132 } 1133 1134 static bool trans_VLDM_VSTM_sp(DisasContext *s, arg_VLDM_VSTM_sp *a) 1135 { 1136 uint32_t offset; 1137 TCGv_i32 addr, tmp; 1138 int i, n; 1139 1140 if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 1141 return false; 1142 } 1143 1144 n = a->imm; 1145 1146 if (n == 0 || (a->vd + n) > 32) { 1147 /* 1148 * UNPREDICTABLE cases for bad immediates: we choose to 1149 * UNDEF to avoid generating huge numbers of TCG ops 1150 */ 1151 return false; 1152 } 1153 if (a->rn == 15 && a->w) { 1154 /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */ 1155 return false; 1156 } 1157 1158 s->eci_handled = true; 1159 1160 if (!vfp_access_check(s)) { 1161 return true; 1162 } 1163 1164 /* For thumb, use of PC is UNPREDICTABLE. */ 1165 addr = add_reg_for_lit(s, a->rn, 0); 1166 if (a->p) { 1167 /* pre-decrement */ 1168 tcg_gen_addi_i32(addr, addr, -(a->imm << 2)); 1169 } 1170 1171 if (s->v8m_stackcheck && a->rn == 13 && a->w) { 1172 /* 1173 * Here 'addr' is the lowest address we will store to, 1174 * and is either the old SP (if post-increment) or 1175 * the new SP (if pre-decrement). For post-increment 1176 * where the old value is below the limit and the new 1177 * value is above, it is UNKNOWN whether the limit check 1178 * triggers; we choose to trigger. 1179 */ 1180 gen_helper_v8m_stackcheck(cpu_env, addr); 1181 } 1182 1183 offset = 4; 1184 tmp = tcg_temp_new_i32(); 1185 for (i = 0; i < n; i++) { 1186 if (a->l) { 1187 /* load */ 1188 gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN); 1189 vfp_store_reg32(tmp, a->vd + i); 1190 } else { 1191 /* store */ 1192 vfp_load_reg32(tmp, a->vd + i); 1193 gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN); 1194 } 1195 tcg_gen_addi_i32(addr, addr, offset); 1196 } 1197 if (a->w) { 1198 /* writeback */ 1199 if (a->p) { 1200 offset = -offset * n; 1201 tcg_gen_addi_i32(addr, addr, offset); 1202 } 1203 store_reg(s, a->rn, addr); 1204 } 1205 1206 clear_eci_state(s); 1207 return true; 1208 } 1209 1210 static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a) 1211 { 1212 uint32_t offset; 1213 TCGv_i32 addr; 1214 TCGv_i64 tmp; 1215 int i, n; 1216 1217 /* Note that this does not require support for double arithmetic. */ 1218 if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 1219 return false; 1220 } 1221 1222 n = a->imm >> 1; 1223 1224 if (n == 0 || (a->vd + n) > 32 || n > 16) { 1225 /* 1226 * UNPREDICTABLE cases for bad immediates: we choose to 1227 * UNDEF to avoid generating huge numbers of TCG ops 1228 */ 1229 return false; 1230 } 1231 if (a->rn == 15 && a->w) { 1232 /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */ 1233 return false; 1234 } 1235 1236 /* UNDEF accesses to D16-D31 if they don't exist */ 1237 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd + n) > 16) { 1238 return false; 1239 } 1240 1241 s->eci_handled = true; 1242 1243 if (!vfp_access_check(s)) { 1244 return true; 1245 } 1246 1247 /* For thumb, use of PC is UNPREDICTABLE. */ 1248 addr = add_reg_for_lit(s, a->rn, 0); 1249 if (a->p) { 1250 /* pre-decrement */ 1251 tcg_gen_addi_i32(addr, addr, -(a->imm << 2)); 1252 } 1253 1254 if (s->v8m_stackcheck && a->rn == 13 && a->w) { 1255 /* 1256 * Here 'addr' is the lowest address we will store to, 1257 * and is either the old SP (if post-increment) or 1258 * the new SP (if pre-decrement). For post-increment 1259 * where the old value is below the limit and the new 1260 * value is above, it is UNKNOWN whether the limit check 1261 * triggers; we choose to trigger. 1262 */ 1263 gen_helper_v8m_stackcheck(cpu_env, addr); 1264 } 1265 1266 offset = 8; 1267 tmp = tcg_temp_new_i64(); 1268 for (i = 0; i < n; i++) { 1269 if (a->l) { 1270 /* load */ 1271 gen_aa32_ld_i64(s, tmp, addr, get_mem_index(s), MO_UQ | MO_ALIGN_4); 1272 vfp_store_reg64(tmp, a->vd + i); 1273 } else { 1274 /* store */ 1275 vfp_load_reg64(tmp, a->vd + i); 1276 gen_aa32_st_i64(s, tmp, addr, get_mem_index(s), MO_UQ | MO_ALIGN_4); 1277 } 1278 tcg_gen_addi_i32(addr, addr, offset); 1279 } 1280 if (a->w) { 1281 /* writeback */ 1282 if (a->p) { 1283 offset = -offset * n; 1284 } else if (a->imm & 1) { 1285 offset = 4; 1286 } else { 1287 offset = 0; 1288 } 1289 1290 if (offset != 0) { 1291 tcg_gen_addi_i32(addr, addr, offset); 1292 } 1293 store_reg(s, a->rn, addr); 1294 } 1295 1296 clear_eci_state(s); 1297 return true; 1298 } 1299 1300 /* 1301 * Types for callbacks for do_vfp_3op_sp() and do_vfp_3op_dp(). 1302 * The callback should emit code to write a value to vd. If 1303 * do_vfp_3op_{sp,dp}() was passed reads_vd then the TCGv vd 1304 * will contain the old value of the relevant VFP register; 1305 * otherwise it must be written to only. 1306 */ 1307 typedef void VFPGen3OpSPFn(TCGv_i32 vd, 1308 TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst); 1309 typedef void VFPGen3OpDPFn(TCGv_i64 vd, 1310 TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst); 1311 1312 /* 1313 * Types for callbacks for do_vfp_2op_sp() and do_vfp_2op_dp(). 1314 * The callback should emit code to write a value to vd (which 1315 * should be written to only). 1316 */ 1317 typedef void VFPGen2OpSPFn(TCGv_i32 vd, TCGv_i32 vm); 1318 typedef void VFPGen2OpDPFn(TCGv_i64 vd, TCGv_i64 vm); 1319 1320 /* 1321 * Return true if the specified S reg is in a scalar bank 1322 * (ie if it is s0..s7) 1323 */ 1324 static inline bool vfp_sreg_is_scalar(int reg) 1325 { 1326 return (reg & 0x18) == 0; 1327 } 1328 1329 /* 1330 * Return true if the specified D reg is in a scalar bank 1331 * (ie if it is d0..d3 or d16..d19) 1332 */ 1333 static inline bool vfp_dreg_is_scalar(int reg) 1334 { 1335 return (reg & 0xc) == 0; 1336 } 1337 1338 /* 1339 * Advance the S reg number forwards by delta within its bank 1340 * (ie increment the low 3 bits but leave the rest the same) 1341 */ 1342 static inline int vfp_advance_sreg(int reg, int delta) 1343 { 1344 return ((reg + delta) & 0x7) | (reg & ~0x7); 1345 } 1346 1347 /* 1348 * Advance the D reg number forwards by delta within its bank 1349 * (ie increment the low 2 bits but leave the rest the same) 1350 */ 1351 static inline int vfp_advance_dreg(int reg, int delta) 1352 { 1353 return ((reg + delta) & 0x3) | (reg & ~0x3); 1354 } 1355 1356 /* 1357 * Perform a 3-operand VFP data processing instruction. fn is the 1358 * callback to do the actual operation; this function deals with the 1359 * code to handle looping around for VFP vector processing. 1360 */ 1361 static bool do_vfp_3op_sp(DisasContext *s, VFPGen3OpSPFn *fn, 1362 int vd, int vn, int vm, bool reads_vd) 1363 { 1364 uint32_t delta_m = 0; 1365 uint32_t delta_d = 0; 1366 int veclen = s->vec_len; 1367 TCGv_i32 f0, f1, fd; 1368 TCGv_ptr fpst; 1369 1370 if (!dc_isar_feature(aa32_fpsp_v2, s)) { 1371 return false; 1372 } 1373 1374 if (!dc_isar_feature(aa32_fpshvec, s) && 1375 (veclen != 0 || s->vec_stride != 0)) { 1376 return false; 1377 } 1378 1379 if (!vfp_access_check(s)) { 1380 return true; 1381 } 1382 1383 if (veclen > 0) { 1384 /* Figure out what type of vector operation this is. */ 1385 if (vfp_sreg_is_scalar(vd)) { 1386 /* scalar */ 1387 veclen = 0; 1388 } else { 1389 delta_d = s->vec_stride + 1; 1390 1391 if (vfp_sreg_is_scalar(vm)) { 1392 /* mixed scalar/vector */ 1393 delta_m = 0; 1394 } else { 1395 /* vector */ 1396 delta_m = delta_d; 1397 } 1398 } 1399 } 1400 1401 f0 = tcg_temp_new_i32(); 1402 f1 = tcg_temp_new_i32(); 1403 fd = tcg_temp_new_i32(); 1404 fpst = fpstatus_ptr(FPST_FPCR); 1405 1406 vfp_load_reg32(f0, vn); 1407 vfp_load_reg32(f1, vm); 1408 1409 for (;;) { 1410 if (reads_vd) { 1411 vfp_load_reg32(fd, vd); 1412 } 1413 fn(fd, f0, f1, fpst); 1414 vfp_store_reg32(fd, vd); 1415 1416 if (veclen == 0) { 1417 break; 1418 } 1419 1420 /* Set up the operands for the next iteration */ 1421 veclen--; 1422 vd = vfp_advance_sreg(vd, delta_d); 1423 vn = vfp_advance_sreg(vn, delta_d); 1424 vfp_load_reg32(f0, vn); 1425 if (delta_m) { 1426 vm = vfp_advance_sreg(vm, delta_m); 1427 vfp_load_reg32(f1, vm); 1428 } 1429 } 1430 return true; 1431 } 1432 1433 static bool do_vfp_3op_hp(DisasContext *s, VFPGen3OpSPFn *fn, 1434 int vd, int vn, int vm, bool reads_vd) 1435 { 1436 /* 1437 * Do a half-precision operation. Functionally this is 1438 * the same as do_vfp_3op_sp(), except: 1439 * - it uses the FPST_FPCR_F16 1440 * - it doesn't need the VFP vector handling (fp16 is a 1441 * v8 feature, and in v8 VFP vectors don't exist) 1442 * - it does the aa32_fp16_arith feature test 1443 */ 1444 TCGv_i32 f0, f1, fd; 1445 TCGv_ptr fpst; 1446 1447 if (!dc_isar_feature(aa32_fp16_arith, s)) { 1448 return false; 1449 } 1450 1451 if (s->vec_len != 0 || s->vec_stride != 0) { 1452 return false; 1453 } 1454 1455 if (!vfp_access_check(s)) { 1456 return true; 1457 } 1458 1459 f0 = tcg_temp_new_i32(); 1460 f1 = tcg_temp_new_i32(); 1461 fd = tcg_temp_new_i32(); 1462 fpst = fpstatus_ptr(FPST_FPCR_F16); 1463 1464 vfp_load_reg32(f0, vn); 1465 vfp_load_reg32(f1, vm); 1466 1467 if (reads_vd) { 1468 vfp_load_reg32(fd, vd); 1469 } 1470 fn(fd, f0, f1, fpst); 1471 vfp_store_reg32(fd, vd); 1472 return true; 1473 } 1474 1475 static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn, 1476 int vd, int vn, int vm, bool reads_vd) 1477 { 1478 uint32_t delta_m = 0; 1479 uint32_t delta_d = 0; 1480 int veclen = s->vec_len; 1481 TCGv_i64 f0, f1, fd; 1482 TCGv_ptr fpst; 1483 1484 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 1485 return false; 1486 } 1487 1488 /* UNDEF accesses to D16-D31 if they don't exist */ 1489 if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) { 1490 return false; 1491 } 1492 1493 if (!dc_isar_feature(aa32_fpshvec, s) && 1494 (veclen != 0 || s->vec_stride != 0)) { 1495 return false; 1496 } 1497 1498 if (!vfp_access_check(s)) { 1499 return true; 1500 } 1501 1502 if (veclen > 0) { 1503 /* Figure out what type of vector operation this is. */ 1504 if (vfp_dreg_is_scalar(vd)) { 1505 /* scalar */ 1506 veclen = 0; 1507 } else { 1508 delta_d = (s->vec_stride >> 1) + 1; 1509 1510 if (vfp_dreg_is_scalar(vm)) { 1511 /* mixed scalar/vector */ 1512 delta_m = 0; 1513 } else { 1514 /* vector */ 1515 delta_m = delta_d; 1516 } 1517 } 1518 } 1519 1520 f0 = tcg_temp_new_i64(); 1521 f1 = tcg_temp_new_i64(); 1522 fd = tcg_temp_new_i64(); 1523 fpst = fpstatus_ptr(FPST_FPCR); 1524 1525 vfp_load_reg64(f0, vn); 1526 vfp_load_reg64(f1, vm); 1527 1528 for (;;) { 1529 if (reads_vd) { 1530 vfp_load_reg64(fd, vd); 1531 } 1532 fn(fd, f0, f1, fpst); 1533 vfp_store_reg64(fd, vd); 1534 1535 if (veclen == 0) { 1536 break; 1537 } 1538 /* Set up the operands for the next iteration */ 1539 veclen--; 1540 vd = vfp_advance_dreg(vd, delta_d); 1541 vn = vfp_advance_dreg(vn, delta_d); 1542 vfp_load_reg64(f0, vn); 1543 if (delta_m) { 1544 vm = vfp_advance_dreg(vm, delta_m); 1545 vfp_load_reg64(f1, vm); 1546 } 1547 } 1548 return true; 1549 } 1550 1551 static bool do_vfp_2op_sp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm) 1552 { 1553 uint32_t delta_m = 0; 1554 uint32_t delta_d = 0; 1555 int veclen = s->vec_len; 1556 TCGv_i32 f0, fd; 1557 1558 /* Note that the caller must check the aa32_fpsp_v2 feature. */ 1559 1560 if (!dc_isar_feature(aa32_fpshvec, s) && 1561 (veclen != 0 || s->vec_stride != 0)) { 1562 return false; 1563 } 1564 1565 if (!vfp_access_check(s)) { 1566 return true; 1567 } 1568 1569 if (veclen > 0) { 1570 /* Figure out what type of vector operation this is. */ 1571 if (vfp_sreg_is_scalar(vd)) { 1572 /* scalar */ 1573 veclen = 0; 1574 } else { 1575 delta_d = s->vec_stride + 1; 1576 1577 if (vfp_sreg_is_scalar(vm)) { 1578 /* mixed scalar/vector */ 1579 delta_m = 0; 1580 } else { 1581 /* vector */ 1582 delta_m = delta_d; 1583 } 1584 } 1585 } 1586 1587 f0 = tcg_temp_new_i32(); 1588 fd = tcg_temp_new_i32(); 1589 1590 vfp_load_reg32(f0, vm); 1591 1592 for (;;) { 1593 fn(fd, f0); 1594 vfp_store_reg32(fd, vd); 1595 1596 if (veclen == 0) { 1597 break; 1598 } 1599 1600 if (delta_m == 0) { 1601 /* single source one-many */ 1602 while (veclen--) { 1603 vd = vfp_advance_sreg(vd, delta_d); 1604 vfp_store_reg32(fd, vd); 1605 } 1606 break; 1607 } 1608 1609 /* Set up the operands for the next iteration */ 1610 veclen--; 1611 vd = vfp_advance_sreg(vd, delta_d); 1612 vm = vfp_advance_sreg(vm, delta_m); 1613 vfp_load_reg32(f0, vm); 1614 } 1615 return true; 1616 } 1617 1618 static bool do_vfp_2op_hp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm) 1619 { 1620 /* 1621 * Do a half-precision operation. Functionally this is 1622 * the same as do_vfp_2op_sp(), except: 1623 * - it doesn't need the VFP vector handling (fp16 is a 1624 * v8 feature, and in v8 VFP vectors don't exist) 1625 * - it does the aa32_fp16_arith feature test 1626 */ 1627 TCGv_i32 f0; 1628 1629 /* Note that the caller must check the aa32_fp16_arith feature */ 1630 1631 if (!dc_isar_feature(aa32_fp16_arith, s)) { 1632 return false; 1633 } 1634 1635 if (s->vec_len != 0 || s->vec_stride != 0) { 1636 return false; 1637 } 1638 1639 if (!vfp_access_check(s)) { 1640 return true; 1641 } 1642 1643 f0 = tcg_temp_new_i32(); 1644 vfp_load_reg32(f0, vm); 1645 fn(f0, f0); 1646 vfp_store_reg32(f0, vd); 1647 1648 return true; 1649 } 1650 1651 static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm) 1652 { 1653 uint32_t delta_m = 0; 1654 uint32_t delta_d = 0; 1655 int veclen = s->vec_len; 1656 TCGv_i64 f0, fd; 1657 1658 /* Note that the caller must check the aa32_fpdp_v2 feature. */ 1659 1660 /* UNDEF accesses to D16-D31 if they don't exist */ 1661 if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) { 1662 return false; 1663 } 1664 1665 if (!dc_isar_feature(aa32_fpshvec, s) && 1666 (veclen != 0 || s->vec_stride != 0)) { 1667 return false; 1668 } 1669 1670 if (!vfp_access_check(s)) { 1671 return true; 1672 } 1673 1674 if (veclen > 0) { 1675 /* Figure out what type of vector operation this is. */ 1676 if (vfp_dreg_is_scalar(vd)) { 1677 /* scalar */ 1678 veclen = 0; 1679 } else { 1680 delta_d = (s->vec_stride >> 1) + 1; 1681 1682 if (vfp_dreg_is_scalar(vm)) { 1683 /* mixed scalar/vector */ 1684 delta_m = 0; 1685 } else { 1686 /* vector */ 1687 delta_m = delta_d; 1688 } 1689 } 1690 } 1691 1692 f0 = tcg_temp_new_i64(); 1693 fd = tcg_temp_new_i64(); 1694 1695 vfp_load_reg64(f0, vm); 1696 1697 for (;;) { 1698 fn(fd, f0); 1699 vfp_store_reg64(fd, vd); 1700 1701 if (veclen == 0) { 1702 break; 1703 } 1704 1705 if (delta_m == 0) { 1706 /* single source one-many */ 1707 while (veclen--) { 1708 vd = vfp_advance_dreg(vd, delta_d); 1709 vfp_store_reg64(fd, vd); 1710 } 1711 break; 1712 } 1713 1714 /* Set up the operands for the next iteration */ 1715 veclen--; 1716 vd = vfp_advance_dreg(vd, delta_d); 1717 vd = vfp_advance_dreg(vm, delta_m); 1718 vfp_load_reg64(f0, vm); 1719 } 1720 return true; 1721 } 1722 1723 static void gen_VMLA_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst) 1724 { 1725 /* Note that order of inputs to the add matters for NaNs */ 1726 TCGv_i32 tmp = tcg_temp_new_i32(); 1727 1728 gen_helper_vfp_mulh(tmp, vn, vm, fpst); 1729 gen_helper_vfp_addh(vd, vd, tmp, fpst); 1730 } 1731 1732 static bool trans_VMLA_hp(DisasContext *s, arg_VMLA_sp *a) 1733 { 1734 return do_vfp_3op_hp(s, gen_VMLA_hp, a->vd, a->vn, a->vm, true); 1735 } 1736 1737 static void gen_VMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst) 1738 { 1739 /* Note that order of inputs to the add matters for NaNs */ 1740 TCGv_i32 tmp = tcg_temp_new_i32(); 1741 1742 gen_helper_vfp_muls(tmp, vn, vm, fpst); 1743 gen_helper_vfp_adds(vd, vd, tmp, fpst); 1744 } 1745 1746 static bool trans_VMLA_sp(DisasContext *s, arg_VMLA_sp *a) 1747 { 1748 return do_vfp_3op_sp(s, gen_VMLA_sp, a->vd, a->vn, a->vm, true); 1749 } 1750 1751 static void gen_VMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst) 1752 { 1753 /* Note that order of inputs to the add matters for NaNs */ 1754 TCGv_i64 tmp = tcg_temp_new_i64(); 1755 1756 gen_helper_vfp_muld(tmp, vn, vm, fpst); 1757 gen_helper_vfp_addd(vd, vd, tmp, fpst); 1758 } 1759 1760 static bool trans_VMLA_dp(DisasContext *s, arg_VMLA_dp *a) 1761 { 1762 return do_vfp_3op_dp(s, gen_VMLA_dp, a->vd, a->vn, a->vm, true); 1763 } 1764 1765 static void gen_VMLS_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst) 1766 { 1767 /* 1768 * VMLS: vd = vd + -(vn * vm) 1769 * Note that order of inputs to the add matters for NaNs. 1770 */ 1771 TCGv_i32 tmp = tcg_temp_new_i32(); 1772 1773 gen_helper_vfp_mulh(tmp, vn, vm, fpst); 1774 gen_helper_vfp_negh(tmp, tmp); 1775 gen_helper_vfp_addh(vd, vd, tmp, fpst); 1776 } 1777 1778 static bool trans_VMLS_hp(DisasContext *s, arg_VMLS_sp *a) 1779 { 1780 return do_vfp_3op_hp(s, gen_VMLS_hp, a->vd, a->vn, a->vm, true); 1781 } 1782 1783 static void gen_VMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst) 1784 { 1785 /* 1786 * VMLS: vd = vd + -(vn * vm) 1787 * Note that order of inputs to the add matters for NaNs. 1788 */ 1789 TCGv_i32 tmp = tcg_temp_new_i32(); 1790 1791 gen_helper_vfp_muls(tmp, vn, vm, fpst); 1792 gen_helper_vfp_negs(tmp, tmp); 1793 gen_helper_vfp_adds(vd, vd, tmp, fpst); 1794 } 1795 1796 static bool trans_VMLS_sp(DisasContext *s, arg_VMLS_sp *a) 1797 { 1798 return do_vfp_3op_sp(s, gen_VMLS_sp, a->vd, a->vn, a->vm, true); 1799 } 1800 1801 static void gen_VMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst) 1802 { 1803 /* 1804 * VMLS: vd = vd + -(vn * vm) 1805 * Note that order of inputs to the add matters for NaNs. 1806 */ 1807 TCGv_i64 tmp = tcg_temp_new_i64(); 1808 1809 gen_helper_vfp_muld(tmp, vn, vm, fpst); 1810 gen_helper_vfp_negd(tmp, tmp); 1811 gen_helper_vfp_addd(vd, vd, tmp, fpst); 1812 } 1813 1814 static bool trans_VMLS_dp(DisasContext *s, arg_VMLS_dp *a) 1815 { 1816 return do_vfp_3op_dp(s, gen_VMLS_dp, a->vd, a->vn, a->vm, true); 1817 } 1818 1819 static void gen_VNMLS_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst) 1820 { 1821 /* 1822 * VNMLS: -fd + (fn * fm) 1823 * Note that it isn't valid to replace (-A + B) with (B - A) or similar 1824 * plausible looking simplifications because this will give wrong results 1825 * for NaNs. 1826 */ 1827 TCGv_i32 tmp = tcg_temp_new_i32(); 1828 1829 gen_helper_vfp_mulh(tmp, vn, vm, fpst); 1830 gen_helper_vfp_negh(vd, vd); 1831 gen_helper_vfp_addh(vd, vd, tmp, fpst); 1832 } 1833 1834 static bool trans_VNMLS_hp(DisasContext *s, arg_VNMLS_sp *a) 1835 { 1836 return do_vfp_3op_hp(s, gen_VNMLS_hp, a->vd, a->vn, a->vm, true); 1837 } 1838 1839 static void gen_VNMLS_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst) 1840 { 1841 /* 1842 * VNMLS: -fd + (fn * fm) 1843 * Note that it isn't valid to replace (-A + B) with (B - A) or similar 1844 * plausible looking simplifications because this will give wrong results 1845 * for NaNs. 1846 */ 1847 TCGv_i32 tmp = tcg_temp_new_i32(); 1848 1849 gen_helper_vfp_muls(tmp, vn, vm, fpst); 1850 gen_helper_vfp_negs(vd, vd); 1851 gen_helper_vfp_adds(vd, vd, tmp, fpst); 1852 } 1853 1854 static bool trans_VNMLS_sp(DisasContext *s, arg_VNMLS_sp *a) 1855 { 1856 return do_vfp_3op_sp(s, gen_VNMLS_sp, a->vd, a->vn, a->vm, true); 1857 } 1858 1859 static void gen_VNMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst) 1860 { 1861 /* 1862 * VNMLS: -fd + (fn * fm) 1863 * Note that it isn't valid to replace (-A + B) with (B - A) or similar 1864 * plausible looking simplifications because this will give wrong results 1865 * for NaNs. 1866 */ 1867 TCGv_i64 tmp = tcg_temp_new_i64(); 1868 1869 gen_helper_vfp_muld(tmp, vn, vm, fpst); 1870 gen_helper_vfp_negd(vd, vd); 1871 gen_helper_vfp_addd(vd, vd, tmp, fpst); 1872 } 1873 1874 static bool trans_VNMLS_dp(DisasContext *s, arg_VNMLS_dp *a) 1875 { 1876 return do_vfp_3op_dp(s, gen_VNMLS_dp, a->vd, a->vn, a->vm, true); 1877 } 1878 1879 static void gen_VNMLA_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst) 1880 { 1881 /* VNMLA: -fd + -(fn * fm) */ 1882 TCGv_i32 tmp = tcg_temp_new_i32(); 1883 1884 gen_helper_vfp_mulh(tmp, vn, vm, fpst); 1885 gen_helper_vfp_negh(tmp, tmp); 1886 gen_helper_vfp_negh(vd, vd); 1887 gen_helper_vfp_addh(vd, vd, tmp, fpst); 1888 } 1889 1890 static bool trans_VNMLA_hp(DisasContext *s, arg_VNMLA_sp *a) 1891 { 1892 return do_vfp_3op_hp(s, gen_VNMLA_hp, a->vd, a->vn, a->vm, true); 1893 } 1894 1895 static void gen_VNMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst) 1896 { 1897 /* VNMLA: -fd + -(fn * fm) */ 1898 TCGv_i32 tmp = tcg_temp_new_i32(); 1899 1900 gen_helper_vfp_muls(tmp, vn, vm, fpst); 1901 gen_helper_vfp_negs(tmp, tmp); 1902 gen_helper_vfp_negs(vd, vd); 1903 gen_helper_vfp_adds(vd, vd, tmp, fpst); 1904 } 1905 1906 static bool trans_VNMLA_sp(DisasContext *s, arg_VNMLA_sp *a) 1907 { 1908 return do_vfp_3op_sp(s, gen_VNMLA_sp, a->vd, a->vn, a->vm, true); 1909 } 1910 1911 static void gen_VNMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst) 1912 { 1913 /* VNMLA: -fd + (fn * fm) */ 1914 TCGv_i64 tmp = tcg_temp_new_i64(); 1915 1916 gen_helper_vfp_muld(tmp, vn, vm, fpst); 1917 gen_helper_vfp_negd(tmp, tmp); 1918 gen_helper_vfp_negd(vd, vd); 1919 gen_helper_vfp_addd(vd, vd, tmp, fpst); 1920 } 1921 1922 static bool trans_VNMLA_dp(DisasContext *s, arg_VNMLA_dp *a) 1923 { 1924 return do_vfp_3op_dp(s, gen_VNMLA_dp, a->vd, a->vn, a->vm, true); 1925 } 1926 1927 static bool trans_VMUL_hp(DisasContext *s, arg_VMUL_sp *a) 1928 { 1929 return do_vfp_3op_hp(s, gen_helper_vfp_mulh, a->vd, a->vn, a->vm, false); 1930 } 1931 1932 static bool trans_VMUL_sp(DisasContext *s, arg_VMUL_sp *a) 1933 { 1934 return do_vfp_3op_sp(s, gen_helper_vfp_muls, a->vd, a->vn, a->vm, false); 1935 } 1936 1937 static bool trans_VMUL_dp(DisasContext *s, arg_VMUL_dp *a) 1938 { 1939 return do_vfp_3op_dp(s, gen_helper_vfp_muld, a->vd, a->vn, a->vm, false); 1940 } 1941 1942 static void gen_VNMUL_hp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst) 1943 { 1944 /* VNMUL: -(fn * fm) */ 1945 gen_helper_vfp_mulh(vd, vn, vm, fpst); 1946 gen_helper_vfp_negh(vd, vd); 1947 } 1948 1949 static bool trans_VNMUL_hp(DisasContext *s, arg_VNMUL_sp *a) 1950 { 1951 return do_vfp_3op_hp(s, gen_VNMUL_hp, a->vd, a->vn, a->vm, false); 1952 } 1953 1954 static void gen_VNMUL_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst) 1955 { 1956 /* VNMUL: -(fn * fm) */ 1957 gen_helper_vfp_muls(vd, vn, vm, fpst); 1958 gen_helper_vfp_negs(vd, vd); 1959 } 1960 1961 static bool trans_VNMUL_sp(DisasContext *s, arg_VNMUL_sp *a) 1962 { 1963 return do_vfp_3op_sp(s, gen_VNMUL_sp, a->vd, a->vn, a->vm, false); 1964 } 1965 1966 static void gen_VNMUL_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst) 1967 { 1968 /* VNMUL: -(fn * fm) */ 1969 gen_helper_vfp_muld(vd, vn, vm, fpst); 1970 gen_helper_vfp_negd(vd, vd); 1971 } 1972 1973 static bool trans_VNMUL_dp(DisasContext *s, arg_VNMUL_dp *a) 1974 { 1975 return do_vfp_3op_dp(s, gen_VNMUL_dp, a->vd, a->vn, a->vm, false); 1976 } 1977 1978 static bool trans_VADD_hp(DisasContext *s, arg_VADD_sp *a) 1979 { 1980 return do_vfp_3op_hp(s, gen_helper_vfp_addh, a->vd, a->vn, a->vm, false); 1981 } 1982 1983 static bool trans_VADD_sp(DisasContext *s, arg_VADD_sp *a) 1984 { 1985 return do_vfp_3op_sp(s, gen_helper_vfp_adds, a->vd, a->vn, a->vm, false); 1986 } 1987 1988 static bool trans_VADD_dp(DisasContext *s, arg_VADD_dp *a) 1989 { 1990 return do_vfp_3op_dp(s, gen_helper_vfp_addd, a->vd, a->vn, a->vm, false); 1991 } 1992 1993 static bool trans_VSUB_hp(DisasContext *s, arg_VSUB_sp *a) 1994 { 1995 return do_vfp_3op_hp(s, gen_helper_vfp_subh, a->vd, a->vn, a->vm, false); 1996 } 1997 1998 static bool trans_VSUB_sp(DisasContext *s, arg_VSUB_sp *a) 1999 { 2000 return do_vfp_3op_sp(s, gen_helper_vfp_subs, a->vd, a->vn, a->vm, false); 2001 } 2002 2003 static bool trans_VSUB_dp(DisasContext *s, arg_VSUB_dp *a) 2004 { 2005 return do_vfp_3op_dp(s, gen_helper_vfp_subd, a->vd, a->vn, a->vm, false); 2006 } 2007 2008 static bool trans_VDIV_hp(DisasContext *s, arg_VDIV_sp *a) 2009 { 2010 return do_vfp_3op_hp(s, gen_helper_vfp_divh, a->vd, a->vn, a->vm, false); 2011 } 2012 2013 static bool trans_VDIV_sp(DisasContext *s, arg_VDIV_sp *a) 2014 { 2015 return do_vfp_3op_sp(s, gen_helper_vfp_divs, a->vd, a->vn, a->vm, false); 2016 } 2017 2018 static bool trans_VDIV_dp(DisasContext *s, arg_VDIV_dp *a) 2019 { 2020 return do_vfp_3op_dp(s, gen_helper_vfp_divd, a->vd, a->vn, a->vm, false); 2021 } 2022 2023 static bool trans_VMINNM_hp(DisasContext *s, arg_VMINNM_sp *a) 2024 { 2025 if (!dc_isar_feature(aa32_vminmaxnm, s)) { 2026 return false; 2027 } 2028 return do_vfp_3op_hp(s, gen_helper_vfp_minnumh, 2029 a->vd, a->vn, a->vm, false); 2030 } 2031 2032 static bool trans_VMAXNM_hp(DisasContext *s, arg_VMAXNM_sp *a) 2033 { 2034 if (!dc_isar_feature(aa32_vminmaxnm, s)) { 2035 return false; 2036 } 2037 return do_vfp_3op_hp(s, gen_helper_vfp_maxnumh, 2038 a->vd, a->vn, a->vm, false); 2039 } 2040 2041 static bool trans_VMINNM_sp(DisasContext *s, arg_VMINNM_sp *a) 2042 { 2043 if (!dc_isar_feature(aa32_vminmaxnm, s)) { 2044 return false; 2045 } 2046 return do_vfp_3op_sp(s, gen_helper_vfp_minnums, 2047 a->vd, a->vn, a->vm, false); 2048 } 2049 2050 static bool trans_VMAXNM_sp(DisasContext *s, arg_VMAXNM_sp *a) 2051 { 2052 if (!dc_isar_feature(aa32_vminmaxnm, s)) { 2053 return false; 2054 } 2055 return do_vfp_3op_sp(s, gen_helper_vfp_maxnums, 2056 a->vd, a->vn, a->vm, false); 2057 } 2058 2059 static bool trans_VMINNM_dp(DisasContext *s, arg_VMINNM_dp *a) 2060 { 2061 if (!dc_isar_feature(aa32_vminmaxnm, s)) { 2062 return false; 2063 } 2064 return do_vfp_3op_dp(s, gen_helper_vfp_minnumd, 2065 a->vd, a->vn, a->vm, false); 2066 } 2067 2068 static bool trans_VMAXNM_dp(DisasContext *s, arg_VMAXNM_dp *a) 2069 { 2070 if (!dc_isar_feature(aa32_vminmaxnm, s)) { 2071 return false; 2072 } 2073 return do_vfp_3op_dp(s, gen_helper_vfp_maxnumd, 2074 a->vd, a->vn, a->vm, false); 2075 } 2076 2077 static bool do_vfm_hp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d) 2078 { 2079 /* 2080 * VFNMA : fd = muladd(-fd, fn, fm) 2081 * VFNMS : fd = muladd(-fd, -fn, fm) 2082 * VFMA : fd = muladd( fd, fn, fm) 2083 * VFMS : fd = muladd( fd, -fn, fm) 2084 * 2085 * These are fused multiply-add, and must be done as one floating 2086 * point operation with no rounding between the multiplication and 2087 * addition steps. NB that doing the negations here as separate 2088 * steps is correct : an input NaN should come out with its sign 2089 * bit flipped if it is a negated-input. 2090 */ 2091 TCGv_ptr fpst; 2092 TCGv_i32 vn, vm, vd; 2093 2094 /* 2095 * Present in VFPv4 only, and only with the FP16 extension. 2096 * Note that we can't rely on the SIMDFMAC check alone, because 2097 * in a Neon-no-VFP core that ID register field will be non-zero. 2098 */ 2099 if (!dc_isar_feature(aa32_fp16_arith, s) || 2100 !dc_isar_feature(aa32_simdfmac, s) || 2101 !dc_isar_feature(aa32_fpsp_v2, s)) { 2102 return false; 2103 } 2104 2105 if (s->vec_len != 0 || s->vec_stride != 0) { 2106 return false; 2107 } 2108 2109 if (!vfp_access_check(s)) { 2110 return true; 2111 } 2112 2113 vn = tcg_temp_new_i32(); 2114 vm = tcg_temp_new_i32(); 2115 vd = tcg_temp_new_i32(); 2116 2117 vfp_load_reg32(vn, a->vn); 2118 vfp_load_reg32(vm, a->vm); 2119 if (neg_n) { 2120 /* VFNMS, VFMS */ 2121 gen_helper_vfp_negh(vn, vn); 2122 } 2123 vfp_load_reg32(vd, a->vd); 2124 if (neg_d) { 2125 /* VFNMA, VFNMS */ 2126 gen_helper_vfp_negh(vd, vd); 2127 } 2128 fpst = fpstatus_ptr(FPST_FPCR_F16); 2129 gen_helper_vfp_muladdh(vd, vn, vm, vd, fpst); 2130 vfp_store_reg32(vd, a->vd); 2131 return true; 2132 } 2133 2134 static bool do_vfm_sp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d) 2135 { 2136 /* 2137 * VFNMA : fd = muladd(-fd, fn, fm) 2138 * VFNMS : fd = muladd(-fd, -fn, fm) 2139 * VFMA : fd = muladd( fd, fn, fm) 2140 * VFMS : fd = muladd( fd, -fn, fm) 2141 * 2142 * These are fused multiply-add, and must be done as one floating 2143 * point operation with no rounding between the multiplication and 2144 * addition steps. NB that doing the negations here as separate 2145 * steps is correct : an input NaN should come out with its sign 2146 * bit flipped if it is a negated-input. 2147 */ 2148 TCGv_ptr fpst; 2149 TCGv_i32 vn, vm, vd; 2150 2151 /* 2152 * Present in VFPv4 only. 2153 * Note that we can't rely on the SIMDFMAC check alone, because 2154 * in a Neon-no-VFP core that ID register field will be non-zero. 2155 */ 2156 if (!dc_isar_feature(aa32_simdfmac, s) || 2157 !dc_isar_feature(aa32_fpsp_v2, s)) { 2158 return false; 2159 } 2160 /* 2161 * In v7A, UNPREDICTABLE with non-zero vector length/stride; from 2162 * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A. 2163 */ 2164 if (s->vec_len != 0 || s->vec_stride != 0) { 2165 return false; 2166 } 2167 2168 if (!vfp_access_check(s)) { 2169 return true; 2170 } 2171 2172 vn = tcg_temp_new_i32(); 2173 vm = tcg_temp_new_i32(); 2174 vd = tcg_temp_new_i32(); 2175 2176 vfp_load_reg32(vn, a->vn); 2177 vfp_load_reg32(vm, a->vm); 2178 if (neg_n) { 2179 /* VFNMS, VFMS */ 2180 gen_helper_vfp_negs(vn, vn); 2181 } 2182 vfp_load_reg32(vd, a->vd); 2183 if (neg_d) { 2184 /* VFNMA, VFNMS */ 2185 gen_helper_vfp_negs(vd, vd); 2186 } 2187 fpst = fpstatus_ptr(FPST_FPCR); 2188 gen_helper_vfp_muladds(vd, vn, vm, vd, fpst); 2189 vfp_store_reg32(vd, a->vd); 2190 return true; 2191 } 2192 2193 static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d) 2194 { 2195 /* 2196 * VFNMA : fd = muladd(-fd, fn, fm) 2197 * VFNMS : fd = muladd(-fd, -fn, fm) 2198 * VFMA : fd = muladd( fd, fn, fm) 2199 * VFMS : fd = muladd( fd, -fn, fm) 2200 * 2201 * These are fused multiply-add, and must be done as one floating 2202 * point operation with no rounding between the multiplication and 2203 * addition steps. NB that doing the negations here as separate 2204 * steps is correct : an input NaN should come out with its sign 2205 * bit flipped if it is a negated-input. 2206 */ 2207 TCGv_ptr fpst; 2208 TCGv_i64 vn, vm, vd; 2209 2210 /* 2211 * Present in VFPv4 only. 2212 * Note that we can't rely on the SIMDFMAC check alone, because 2213 * in a Neon-no-VFP core that ID register field will be non-zero. 2214 */ 2215 if (!dc_isar_feature(aa32_simdfmac, s) || 2216 !dc_isar_feature(aa32_fpdp_v2, s)) { 2217 return false; 2218 } 2219 /* 2220 * In v7A, UNPREDICTABLE with non-zero vector length/stride; from 2221 * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A. 2222 */ 2223 if (s->vec_len != 0 || s->vec_stride != 0) { 2224 return false; 2225 } 2226 2227 /* UNDEF accesses to D16-D31 if they don't exist. */ 2228 if (!dc_isar_feature(aa32_simd_r32, s) && 2229 ((a->vd | a->vn | a->vm) & 0x10)) { 2230 return false; 2231 } 2232 2233 if (!vfp_access_check(s)) { 2234 return true; 2235 } 2236 2237 vn = tcg_temp_new_i64(); 2238 vm = tcg_temp_new_i64(); 2239 vd = tcg_temp_new_i64(); 2240 2241 vfp_load_reg64(vn, a->vn); 2242 vfp_load_reg64(vm, a->vm); 2243 if (neg_n) { 2244 /* VFNMS, VFMS */ 2245 gen_helper_vfp_negd(vn, vn); 2246 } 2247 vfp_load_reg64(vd, a->vd); 2248 if (neg_d) { 2249 /* VFNMA, VFNMS */ 2250 gen_helper_vfp_negd(vd, vd); 2251 } 2252 fpst = fpstatus_ptr(FPST_FPCR); 2253 gen_helper_vfp_muladdd(vd, vn, vm, vd, fpst); 2254 vfp_store_reg64(vd, a->vd); 2255 return true; 2256 } 2257 2258 #define MAKE_ONE_VFM_TRANS_FN(INSN, PREC, NEGN, NEGD) \ 2259 static bool trans_##INSN##_##PREC(DisasContext *s, \ 2260 arg_##INSN##_##PREC *a) \ 2261 { \ 2262 return do_vfm_##PREC(s, a, NEGN, NEGD); \ 2263 } 2264 2265 #define MAKE_VFM_TRANS_FNS(PREC) \ 2266 MAKE_ONE_VFM_TRANS_FN(VFMA, PREC, false, false) \ 2267 MAKE_ONE_VFM_TRANS_FN(VFMS, PREC, true, false) \ 2268 MAKE_ONE_VFM_TRANS_FN(VFNMA, PREC, false, true) \ 2269 MAKE_ONE_VFM_TRANS_FN(VFNMS, PREC, true, true) 2270 2271 MAKE_VFM_TRANS_FNS(hp) 2272 MAKE_VFM_TRANS_FNS(sp) 2273 MAKE_VFM_TRANS_FNS(dp) 2274 2275 static bool trans_VMOV_imm_hp(DisasContext *s, arg_VMOV_imm_sp *a) 2276 { 2277 if (!dc_isar_feature(aa32_fp16_arith, s)) { 2278 return false; 2279 } 2280 2281 if (s->vec_len != 0 || s->vec_stride != 0) { 2282 return false; 2283 } 2284 2285 if (!vfp_access_check(s)) { 2286 return true; 2287 } 2288 2289 vfp_store_reg32(tcg_constant_i32(vfp_expand_imm(MO_16, a->imm)), a->vd); 2290 return true; 2291 } 2292 2293 static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a) 2294 { 2295 uint32_t delta_d = 0; 2296 int veclen = s->vec_len; 2297 TCGv_i32 fd; 2298 uint32_t vd; 2299 2300 vd = a->vd; 2301 2302 if (!dc_isar_feature(aa32_fpsp_v3, s)) { 2303 return false; 2304 } 2305 2306 if (!dc_isar_feature(aa32_fpshvec, s) && 2307 (veclen != 0 || s->vec_stride != 0)) { 2308 return false; 2309 } 2310 2311 if (!vfp_access_check(s)) { 2312 return true; 2313 } 2314 2315 if (veclen > 0) { 2316 /* Figure out what type of vector operation this is. */ 2317 if (vfp_sreg_is_scalar(vd)) { 2318 /* scalar */ 2319 veclen = 0; 2320 } else { 2321 delta_d = s->vec_stride + 1; 2322 } 2323 } 2324 2325 fd = tcg_constant_i32(vfp_expand_imm(MO_32, a->imm)); 2326 2327 for (;;) { 2328 vfp_store_reg32(fd, vd); 2329 2330 if (veclen == 0) { 2331 break; 2332 } 2333 2334 /* Set up the operands for the next iteration */ 2335 veclen--; 2336 vd = vfp_advance_sreg(vd, delta_d); 2337 } 2338 2339 return true; 2340 } 2341 2342 static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a) 2343 { 2344 uint32_t delta_d = 0; 2345 int veclen = s->vec_len; 2346 TCGv_i64 fd; 2347 uint32_t vd; 2348 2349 vd = a->vd; 2350 2351 if (!dc_isar_feature(aa32_fpdp_v3, s)) { 2352 return false; 2353 } 2354 2355 /* UNDEF accesses to D16-D31 if they don't exist. */ 2356 if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) { 2357 return false; 2358 } 2359 2360 if (!dc_isar_feature(aa32_fpshvec, s) && 2361 (veclen != 0 || s->vec_stride != 0)) { 2362 return false; 2363 } 2364 2365 if (!vfp_access_check(s)) { 2366 return true; 2367 } 2368 2369 if (veclen > 0) { 2370 /* Figure out what type of vector operation this is. */ 2371 if (vfp_dreg_is_scalar(vd)) { 2372 /* scalar */ 2373 veclen = 0; 2374 } else { 2375 delta_d = (s->vec_stride >> 1) + 1; 2376 } 2377 } 2378 2379 fd = tcg_constant_i64(vfp_expand_imm(MO_64, a->imm)); 2380 2381 for (;;) { 2382 vfp_store_reg64(fd, vd); 2383 2384 if (veclen == 0) { 2385 break; 2386 } 2387 2388 /* Set up the operands for the next iteration */ 2389 veclen--; 2390 vd = vfp_advance_dreg(vd, delta_d); 2391 } 2392 2393 return true; 2394 } 2395 2396 #define DO_VFP_2OP(INSN, PREC, FN, CHECK) \ 2397 static bool trans_##INSN##_##PREC(DisasContext *s, \ 2398 arg_##INSN##_##PREC *a) \ 2399 { \ 2400 if (!dc_isar_feature(CHECK, s)) { \ 2401 return false; \ 2402 } \ 2403 return do_vfp_2op_##PREC(s, FN, a->vd, a->vm); \ 2404 } 2405 2406 #define DO_VFP_VMOV(INSN, PREC, FN) \ 2407 static bool trans_##INSN##_##PREC(DisasContext *s, \ 2408 arg_##INSN##_##PREC *a) \ 2409 { \ 2410 if (!dc_isar_feature(aa32_fp##PREC##_v2, s) && \ 2411 !dc_isar_feature(aa32_mve, s)) { \ 2412 return false; \ 2413 } \ 2414 return do_vfp_2op_##PREC(s, FN, a->vd, a->vm); \ 2415 } 2416 2417 DO_VFP_VMOV(VMOV_reg, sp, tcg_gen_mov_i32) 2418 DO_VFP_VMOV(VMOV_reg, dp, tcg_gen_mov_i64) 2419 2420 DO_VFP_2OP(VABS, hp, gen_helper_vfp_absh, aa32_fp16_arith) 2421 DO_VFP_2OP(VABS, sp, gen_helper_vfp_abss, aa32_fpsp_v2) 2422 DO_VFP_2OP(VABS, dp, gen_helper_vfp_absd, aa32_fpdp_v2) 2423 2424 DO_VFP_2OP(VNEG, hp, gen_helper_vfp_negh, aa32_fp16_arith) 2425 DO_VFP_2OP(VNEG, sp, gen_helper_vfp_negs, aa32_fpsp_v2) 2426 DO_VFP_2OP(VNEG, dp, gen_helper_vfp_negd, aa32_fpdp_v2) 2427 2428 static void gen_VSQRT_hp(TCGv_i32 vd, TCGv_i32 vm) 2429 { 2430 gen_helper_vfp_sqrth(vd, vm, cpu_env); 2431 } 2432 2433 static void gen_VSQRT_sp(TCGv_i32 vd, TCGv_i32 vm) 2434 { 2435 gen_helper_vfp_sqrts(vd, vm, cpu_env); 2436 } 2437 2438 static void gen_VSQRT_dp(TCGv_i64 vd, TCGv_i64 vm) 2439 { 2440 gen_helper_vfp_sqrtd(vd, vm, cpu_env); 2441 } 2442 2443 DO_VFP_2OP(VSQRT, hp, gen_VSQRT_hp, aa32_fp16_arith) 2444 DO_VFP_2OP(VSQRT, sp, gen_VSQRT_sp, aa32_fpsp_v2) 2445 DO_VFP_2OP(VSQRT, dp, gen_VSQRT_dp, aa32_fpdp_v2) 2446 2447 static bool trans_VCMP_hp(DisasContext *s, arg_VCMP_sp *a) 2448 { 2449 TCGv_i32 vd, vm; 2450 2451 if (!dc_isar_feature(aa32_fp16_arith, s)) { 2452 return false; 2453 } 2454 2455 /* Vm/M bits must be zero for the Z variant */ 2456 if (a->z && a->vm != 0) { 2457 return false; 2458 } 2459 2460 if (!vfp_access_check(s)) { 2461 return true; 2462 } 2463 2464 vd = tcg_temp_new_i32(); 2465 vm = tcg_temp_new_i32(); 2466 2467 vfp_load_reg32(vd, a->vd); 2468 if (a->z) { 2469 tcg_gen_movi_i32(vm, 0); 2470 } else { 2471 vfp_load_reg32(vm, a->vm); 2472 } 2473 2474 if (a->e) { 2475 gen_helper_vfp_cmpeh(vd, vm, cpu_env); 2476 } else { 2477 gen_helper_vfp_cmph(vd, vm, cpu_env); 2478 } 2479 return true; 2480 } 2481 2482 static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a) 2483 { 2484 TCGv_i32 vd, vm; 2485 2486 if (!dc_isar_feature(aa32_fpsp_v2, s)) { 2487 return false; 2488 } 2489 2490 /* Vm/M bits must be zero for the Z variant */ 2491 if (a->z && a->vm != 0) { 2492 return false; 2493 } 2494 2495 if (!vfp_access_check(s)) { 2496 return true; 2497 } 2498 2499 vd = tcg_temp_new_i32(); 2500 vm = tcg_temp_new_i32(); 2501 2502 vfp_load_reg32(vd, a->vd); 2503 if (a->z) { 2504 tcg_gen_movi_i32(vm, 0); 2505 } else { 2506 vfp_load_reg32(vm, a->vm); 2507 } 2508 2509 if (a->e) { 2510 gen_helper_vfp_cmpes(vd, vm, cpu_env); 2511 } else { 2512 gen_helper_vfp_cmps(vd, vm, cpu_env); 2513 } 2514 return true; 2515 } 2516 2517 static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a) 2518 { 2519 TCGv_i64 vd, vm; 2520 2521 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 2522 return false; 2523 } 2524 2525 /* Vm/M bits must be zero for the Z variant */ 2526 if (a->z && a->vm != 0) { 2527 return false; 2528 } 2529 2530 /* UNDEF accesses to D16-D31 if they don't exist. */ 2531 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) { 2532 return false; 2533 } 2534 2535 if (!vfp_access_check(s)) { 2536 return true; 2537 } 2538 2539 vd = tcg_temp_new_i64(); 2540 vm = tcg_temp_new_i64(); 2541 2542 vfp_load_reg64(vd, a->vd); 2543 if (a->z) { 2544 tcg_gen_movi_i64(vm, 0); 2545 } else { 2546 vfp_load_reg64(vm, a->vm); 2547 } 2548 2549 if (a->e) { 2550 gen_helper_vfp_cmped(vd, vm, cpu_env); 2551 } else { 2552 gen_helper_vfp_cmpd(vd, vm, cpu_env); 2553 } 2554 return true; 2555 } 2556 2557 static bool trans_VCVT_f32_f16(DisasContext *s, arg_VCVT_f32_f16 *a) 2558 { 2559 TCGv_ptr fpst; 2560 TCGv_i32 ahp_mode; 2561 TCGv_i32 tmp; 2562 2563 if (!dc_isar_feature(aa32_fp16_spconv, s)) { 2564 return false; 2565 } 2566 2567 if (!vfp_access_check(s)) { 2568 return true; 2569 } 2570 2571 fpst = fpstatus_ptr(FPST_FPCR); 2572 ahp_mode = get_ahp_flag(); 2573 tmp = tcg_temp_new_i32(); 2574 /* The T bit tells us if we want the low or high 16 bits of Vm */ 2575 tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t)); 2576 gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp_mode); 2577 vfp_store_reg32(tmp, a->vd); 2578 return true; 2579 } 2580 2581 static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a) 2582 { 2583 TCGv_ptr fpst; 2584 TCGv_i32 ahp_mode; 2585 TCGv_i32 tmp; 2586 TCGv_i64 vd; 2587 2588 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 2589 return false; 2590 } 2591 2592 if (!dc_isar_feature(aa32_fp16_dpconv, s)) { 2593 return false; 2594 } 2595 2596 /* UNDEF accesses to D16-D31 if they don't exist. */ 2597 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 2598 return false; 2599 } 2600 2601 if (!vfp_access_check(s)) { 2602 return true; 2603 } 2604 2605 fpst = fpstatus_ptr(FPST_FPCR); 2606 ahp_mode = get_ahp_flag(); 2607 tmp = tcg_temp_new_i32(); 2608 /* The T bit tells us if we want the low or high 16 bits of Vm */ 2609 tcg_gen_ld16u_i32(tmp, cpu_env, vfp_f16_offset(a->vm, a->t)); 2610 vd = tcg_temp_new_i64(); 2611 gen_helper_vfp_fcvt_f16_to_f64(vd, tmp, fpst, ahp_mode); 2612 vfp_store_reg64(vd, a->vd); 2613 return true; 2614 } 2615 2616 static bool trans_VCVT_b16_f32(DisasContext *s, arg_VCVT_b16_f32 *a) 2617 { 2618 TCGv_ptr fpst; 2619 TCGv_i32 tmp; 2620 2621 if (!dc_isar_feature(aa32_bf16, s)) { 2622 return false; 2623 } 2624 2625 if (!vfp_access_check(s)) { 2626 return true; 2627 } 2628 2629 fpst = fpstatus_ptr(FPST_FPCR); 2630 tmp = tcg_temp_new_i32(); 2631 2632 vfp_load_reg32(tmp, a->vm); 2633 gen_helper_bfcvt(tmp, tmp, fpst); 2634 tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t)); 2635 return true; 2636 } 2637 2638 static bool trans_VCVT_f16_f32(DisasContext *s, arg_VCVT_f16_f32 *a) 2639 { 2640 TCGv_ptr fpst; 2641 TCGv_i32 ahp_mode; 2642 TCGv_i32 tmp; 2643 2644 if (!dc_isar_feature(aa32_fp16_spconv, s)) { 2645 return false; 2646 } 2647 2648 if (!vfp_access_check(s)) { 2649 return true; 2650 } 2651 2652 fpst = fpstatus_ptr(FPST_FPCR); 2653 ahp_mode = get_ahp_flag(); 2654 tmp = tcg_temp_new_i32(); 2655 2656 vfp_load_reg32(tmp, a->vm); 2657 gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp_mode); 2658 tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t)); 2659 return true; 2660 } 2661 2662 static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a) 2663 { 2664 TCGv_ptr fpst; 2665 TCGv_i32 ahp_mode; 2666 TCGv_i32 tmp; 2667 TCGv_i64 vm; 2668 2669 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 2670 return false; 2671 } 2672 2673 if (!dc_isar_feature(aa32_fp16_dpconv, s)) { 2674 return false; 2675 } 2676 2677 /* UNDEF accesses to D16-D31 if they don't exist. */ 2678 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { 2679 return false; 2680 } 2681 2682 if (!vfp_access_check(s)) { 2683 return true; 2684 } 2685 2686 fpst = fpstatus_ptr(FPST_FPCR); 2687 ahp_mode = get_ahp_flag(); 2688 tmp = tcg_temp_new_i32(); 2689 vm = tcg_temp_new_i64(); 2690 2691 vfp_load_reg64(vm, a->vm); 2692 gen_helper_vfp_fcvt_f64_to_f16(tmp, vm, fpst, ahp_mode); 2693 tcg_gen_st16_i32(tmp, cpu_env, vfp_f16_offset(a->vd, a->t)); 2694 return true; 2695 } 2696 2697 static bool trans_VRINTR_hp(DisasContext *s, arg_VRINTR_sp *a) 2698 { 2699 TCGv_ptr fpst; 2700 TCGv_i32 tmp; 2701 2702 if (!dc_isar_feature(aa32_fp16_arith, s)) { 2703 return false; 2704 } 2705 2706 if (!vfp_access_check(s)) { 2707 return true; 2708 } 2709 2710 tmp = tcg_temp_new_i32(); 2711 vfp_load_reg32(tmp, a->vm); 2712 fpst = fpstatus_ptr(FPST_FPCR_F16); 2713 gen_helper_rinth(tmp, tmp, fpst); 2714 vfp_store_reg32(tmp, a->vd); 2715 return true; 2716 } 2717 2718 static bool trans_VRINTR_sp(DisasContext *s, arg_VRINTR_sp *a) 2719 { 2720 TCGv_ptr fpst; 2721 TCGv_i32 tmp; 2722 2723 if (!dc_isar_feature(aa32_vrint, s)) { 2724 return false; 2725 } 2726 2727 if (!vfp_access_check(s)) { 2728 return true; 2729 } 2730 2731 tmp = tcg_temp_new_i32(); 2732 vfp_load_reg32(tmp, a->vm); 2733 fpst = fpstatus_ptr(FPST_FPCR); 2734 gen_helper_rints(tmp, tmp, fpst); 2735 vfp_store_reg32(tmp, a->vd); 2736 return true; 2737 } 2738 2739 static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a) 2740 { 2741 TCGv_ptr fpst; 2742 TCGv_i64 tmp; 2743 2744 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 2745 return false; 2746 } 2747 2748 if (!dc_isar_feature(aa32_vrint, s)) { 2749 return false; 2750 } 2751 2752 /* UNDEF accesses to D16-D31 if they don't exist. */ 2753 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) { 2754 return false; 2755 } 2756 2757 if (!vfp_access_check(s)) { 2758 return true; 2759 } 2760 2761 tmp = tcg_temp_new_i64(); 2762 vfp_load_reg64(tmp, a->vm); 2763 fpst = fpstatus_ptr(FPST_FPCR); 2764 gen_helper_rintd(tmp, tmp, fpst); 2765 vfp_store_reg64(tmp, a->vd); 2766 return true; 2767 } 2768 2769 static bool trans_VRINTZ_hp(DisasContext *s, arg_VRINTZ_sp *a) 2770 { 2771 TCGv_ptr fpst; 2772 TCGv_i32 tmp; 2773 TCGv_i32 tcg_rmode; 2774 2775 if (!dc_isar_feature(aa32_fp16_arith, s)) { 2776 return false; 2777 } 2778 2779 if (!vfp_access_check(s)) { 2780 return true; 2781 } 2782 2783 tmp = tcg_temp_new_i32(); 2784 vfp_load_reg32(tmp, a->vm); 2785 fpst = fpstatus_ptr(FPST_FPCR_F16); 2786 tcg_rmode = tcg_const_i32(float_round_to_zero); 2787 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); 2788 gen_helper_rinth(tmp, tmp, fpst); 2789 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); 2790 vfp_store_reg32(tmp, a->vd); 2791 return true; 2792 } 2793 2794 static bool trans_VRINTZ_sp(DisasContext *s, arg_VRINTZ_sp *a) 2795 { 2796 TCGv_ptr fpst; 2797 TCGv_i32 tmp; 2798 TCGv_i32 tcg_rmode; 2799 2800 if (!dc_isar_feature(aa32_vrint, s)) { 2801 return false; 2802 } 2803 2804 if (!vfp_access_check(s)) { 2805 return true; 2806 } 2807 2808 tmp = tcg_temp_new_i32(); 2809 vfp_load_reg32(tmp, a->vm); 2810 fpst = fpstatus_ptr(FPST_FPCR); 2811 tcg_rmode = tcg_const_i32(float_round_to_zero); 2812 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); 2813 gen_helper_rints(tmp, tmp, fpst); 2814 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); 2815 vfp_store_reg32(tmp, a->vd); 2816 return true; 2817 } 2818 2819 static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a) 2820 { 2821 TCGv_ptr fpst; 2822 TCGv_i64 tmp; 2823 TCGv_i32 tcg_rmode; 2824 2825 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 2826 return false; 2827 } 2828 2829 if (!dc_isar_feature(aa32_vrint, s)) { 2830 return false; 2831 } 2832 2833 /* UNDEF accesses to D16-D31 if they don't exist. */ 2834 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) { 2835 return false; 2836 } 2837 2838 if (!vfp_access_check(s)) { 2839 return true; 2840 } 2841 2842 tmp = tcg_temp_new_i64(); 2843 vfp_load_reg64(tmp, a->vm); 2844 fpst = fpstatus_ptr(FPST_FPCR); 2845 tcg_rmode = tcg_const_i32(float_round_to_zero); 2846 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); 2847 gen_helper_rintd(tmp, tmp, fpst); 2848 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst); 2849 vfp_store_reg64(tmp, a->vd); 2850 return true; 2851 } 2852 2853 static bool trans_VRINTX_hp(DisasContext *s, arg_VRINTX_sp *a) 2854 { 2855 TCGv_ptr fpst; 2856 TCGv_i32 tmp; 2857 2858 if (!dc_isar_feature(aa32_fp16_arith, s)) { 2859 return false; 2860 } 2861 2862 if (!vfp_access_check(s)) { 2863 return true; 2864 } 2865 2866 tmp = tcg_temp_new_i32(); 2867 vfp_load_reg32(tmp, a->vm); 2868 fpst = fpstatus_ptr(FPST_FPCR_F16); 2869 gen_helper_rinth_exact(tmp, tmp, fpst); 2870 vfp_store_reg32(tmp, a->vd); 2871 return true; 2872 } 2873 2874 static bool trans_VRINTX_sp(DisasContext *s, arg_VRINTX_sp *a) 2875 { 2876 TCGv_ptr fpst; 2877 TCGv_i32 tmp; 2878 2879 if (!dc_isar_feature(aa32_vrint, s)) { 2880 return false; 2881 } 2882 2883 if (!vfp_access_check(s)) { 2884 return true; 2885 } 2886 2887 tmp = tcg_temp_new_i32(); 2888 vfp_load_reg32(tmp, a->vm); 2889 fpst = fpstatus_ptr(FPST_FPCR); 2890 gen_helper_rints_exact(tmp, tmp, fpst); 2891 vfp_store_reg32(tmp, a->vd); 2892 return true; 2893 } 2894 2895 static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a) 2896 { 2897 TCGv_ptr fpst; 2898 TCGv_i64 tmp; 2899 2900 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 2901 return false; 2902 } 2903 2904 if (!dc_isar_feature(aa32_vrint, s)) { 2905 return false; 2906 } 2907 2908 /* UNDEF accesses to D16-D31 if they don't exist. */ 2909 if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) { 2910 return false; 2911 } 2912 2913 if (!vfp_access_check(s)) { 2914 return true; 2915 } 2916 2917 tmp = tcg_temp_new_i64(); 2918 vfp_load_reg64(tmp, a->vm); 2919 fpst = fpstatus_ptr(FPST_FPCR); 2920 gen_helper_rintd_exact(tmp, tmp, fpst); 2921 vfp_store_reg64(tmp, a->vd); 2922 return true; 2923 } 2924 2925 static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a) 2926 { 2927 TCGv_i64 vd; 2928 TCGv_i32 vm; 2929 2930 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 2931 return false; 2932 } 2933 2934 /* UNDEF accesses to D16-D31 if they don't exist. */ 2935 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 2936 return false; 2937 } 2938 2939 if (!vfp_access_check(s)) { 2940 return true; 2941 } 2942 2943 vm = tcg_temp_new_i32(); 2944 vd = tcg_temp_new_i64(); 2945 vfp_load_reg32(vm, a->vm); 2946 gen_helper_vfp_fcvtds(vd, vm, cpu_env); 2947 vfp_store_reg64(vd, a->vd); 2948 return true; 2949 } 2950 2951 static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a) 2952 { 2953 TCGv_i64 vm; 2954 TCGv_i32 vd; 2955 2956 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 2957 return false; 2958 } 2959 2960 /* UNDEF accesses to D16-D31 if they don't exist. */ 2961 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { 2962 return false; 2963 } 2964 2965 if (!vfp_access_check(s)) { 2966 return true; 2967 } 2968 2969 vd = tcg_temp_new_i32(); 2970 vm = tcg_temp_new_i64(); 2971 vfp_load_reg64(vm, a->vm); 2972 gen_helper_vfp_fcvtsd(vd, vm, cpu_env); 2973 vfp_store_reg32(vd, a->vd); 2974 return true; 2975 } 2976 2977 static bool trans_VCVT_int_hp(DisasContext *s, arg_VCVT_int_sp *a) 2978 { 2979 TCGv_i32 vm; 2980 TCGv_ptr fpst; 2981 2982 if (!dc_isar_feature(aa32_fp16_arith, s)) { 2983 return false; 2984 } 2985 2986 if (!vfp_access_check(s)) { 2987 return true; 2988 } 2989 2990 vm = tcg_temp_new_i32(); 2991 vfp_load_reg32(vm, a->vm); 2992 fpst = fpstatus_ptr(FPST_FPCR_F16); 2993 if (a->s) { 2994 /* i32 -> f16 */ 2995 gen_helper_vfp_sitoh(vm, vm, fpst); 2996 } else { 2997 /* u32 -> f16 */ 2998 gen_helper_vfp_uitoh(vm, vm, fpst); 2999 } 3000 vfp_store_reg32(vm, a->vd); 3001 return true; 3002 } 3003 3004 static bool trans_VCVT_int_sp(DisasContext *s, arg_VCVT_int_sp *a) 3005 { 3006 TCGv_i32 vm; 3007 TCGv_ptr fpst; 3008 3009 if (!dc_isar_feature(aa32_fpsp_v2, s)) { 3010 return false; 3011 } 3012 3013 if (!vfp_access_check(s)) { 3014 return true; 3015 } 3016 3017 vm = tcg_temp_new_i32(); 3018 vfp_load_reg32(vm, a->vm); 3019 fpst = fpstatus_ptr(FPST_FPCR); 3020 if (a->s) { 3021 /* i32 -> f32 */ 3022 gen_helper_vfp_sitos(vm, vm, fpst); 3023 } else { 3024 /* u32 -> f32 */ 3025 gen_helper_vfp_uitos(vm, vm, fpst); 3026 } 3027 vfp_store_reg32(vm, a->vd); 3028 return true; 3029 } 3030 3031 static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a) 3032 { 3033 TCGv_i32 vm; 3034 TCGv_i64 vd; 3035 TCGv_ptr fpst; 3036 3037 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 3038 return false; 3039 } 3040 3041 /* UNDEF accesses to D16-D31 if they don't exist. */ 3042 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 3043 return false; 3044 } 3045 3046 if (!vfp_access_check(s)) { 3047 return true; 3048 } 3049 3050 vm = tcg_temp_new_i32(); 3051 vd = tcg_temp_new_i64(); 3052 vfp_load_reg32(vm, a->vm); 3053 fpst = fpstatus_ptr(FPST_FPCR); 3054 if (a->s) { 3055 /* i32 -> f64 */ 3056 gen_helper_vfp_sitod(vd, vm, fpst); 3057 } else { 3058 /* u32 -> f64 */ 3059 gen_helper_vfp_uitod(vd, vm, fpst); 3060 } 3061 vfp_store_reg64(vd, a->vd); 3062 return true; 3063 } 3064 3065 static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a) 3066 { 3067 TCGv_i32 vd; 3068 TCGv_i64 vm; 3069 3070 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 3071 return false; 3072 } 3073 3074 if (!dc_isar_feature(aa32_jscvt, s)) { 3075 return false; 3076 } 3077 3078 /* UNDEF accesses to D16-D31 if they don't exist. */ 3079 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { 3080 return false; 3081 } 3082 3083 if (!vfp_access_check(s)) { 3084 return true; 3085 } 3086 3087 vm = tcg_temp_new_i64(); 3088 vd = tcg_temp_new_i32(); 3089 vfp_load_reg64(vm, a->vm); 3090 gen_helper_vjcvt(vd, vm, cpu_env); 3091 vfp_store_reg32(vd, a->vd); 3092 return true; 3093 } 3094 3095 static bool trans_VCVT_fix_hp(DisasContext *s, arg_VCVT_fix_sp *a) 3096 { 3097 TCGv_i32 vd, shift; 3098 TCGv_ptr fpst; 3099 int frac_bits; 3100 3101 if (!dc_isar_feature(aa32_fp16_arith, s)) { 3102 return false; 3103 } 3104 3105 if (!vfp_access_check(s)) { 3106 return true; 3107 } 3108 3109 frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm); 3110 3111 vd = tcg_temp_new_i32(); 3112 vfp_load_reg32(vd, a->vd); 3113 3114 fpst = fpstatus_ptr(FPST_FPCR_F16); 3115 shift = tcg_constant_i32(frac_bits); 3116 3117 /* Switch on op:U:sx bits */ 3118 switch (a->opc) { 3119 case 0: 3120 gen_helper_vfp_shtoh_round_to_nearest(vd, vd, shift, fpst); 3121 break; 3122 case 1: 3123 gen_helper_vfp_sltoh_round_to_nearest(vd, vd, shift, fpst); 3124 break; 3125 case 2: 3126 gen_helper_vfp_uhtoh_round_to_nearest(vd, vd, shift, fpst); 3127 break; 3128 case 3: 3129 gen_helper_vfp_ultoh_round_to_nearest(vd, vd, shift, fpst); 3130 break; 3131 case 4: 3132 gen_helper_vfp_toshh_round_to_zero(vd, vd, shift, fpst); 3133 break; 3134 case 5: 3135 gen_helper_vfp_toslh_round_to_zero(vd, vd, shift, fpst); 3136 break; 3137 case 6: 3138 gen_helper_vfp_touhh_round_to_zero(vd, vd, shift, fpst); 3139 break; 3140 case 7: 3141 gen_helper_vfp_toulh_round_to_zero(vd, vd, shift, fpst); 3142 break; 3143 default: 3144 g_assert_not_reached(); 3145 } 3146 3147 vfp_store_reg32(vd, a->vd); 3148 return true; 3149 } 3150 3151 static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a) 3152 { 3153 TCGv_i32 vd, shift; 3154 TCGv_ptr fpst; 3155 int frac_bits; 3156 3157 if (!dc_isar_feature(aa32_fpsp_v3, s)) { 3158 return false; 3159 } 3160 3161 if (!vfp_access_check(s)) { 3162 return true; 3163 } 3164 3165 frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm); 3166 3167 vd = tcg_temp_new_i32(); 3168 vfp_load_reg32(vd, a->vd); 3169 3170 fpst = fpstatus_ptr(FPST_FPCR); 3171 shift = tcg_constant_i32(frac_bits); 3172 3173 /* Switch on op:U:sx bits */ 3174 switch (a->opc) { 3175 case 0: 3176 gen_helper_vfp_shtos_round_to_nearest(vd, vd, shift, fpst); 3177 break; 3178 case 1: 3179 gen_helper_vfp_sltos_round_to_nearest(vd, vd, shift, fpst); 3180 break; 3181 case 2: 3182 gen_helper_vfp_uhtos_round_to_nearest(vd, vd, shift, fpst); 3183 break; 3184 case 3: 3185 gen_helper_vfp_ultos_round_to_nearest(vd, vd, shift, fpst); 3186 break; 3187 case 4: 3188 gen_helper_vfp_toshs_round_to_zero(vd, vd, shift, fpst); 3189 break; 3190 case 5: 3191 gen_helper_vfp_tosls_round_to_zero(vd, vd, shift, fpst); 3192 break; 3193 case 6: 3194 gen_helper_vfp_touhs_round_to_zero(vd, vd, shift, fpst); 3195 break; 3196 case 7: 3197 gen_helper_vfp_touls_round_to_zero(vd, vd, shift, fpst); 3198 break; 3199 default: 3200 g_assert_not_reached(); 3201 } 3202 3203 vfp_store_reg32(vd, a->vd); 3204 return true; 3205 } 3206 3207 static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a) 3208 { 3209 TCGv_i64 vd; 3210 TCGv_i32 shift; 3211 TCGv_ptr fpst; 3212 int frac_bits; 3213 3214 if (!dc_isar_feature(aa32_fpdp_v3, s)) { 3215 return false; 3216 } 3217 3218 /* UNDEF accesses to D16-D31 if they don't exist. */ 3219 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 3220 return false; 3221 } 3222 3223 if (!vfp_access_check(s)) { 3224 return true; 3225 } 3226 3227 frac_bits = (a->opc & 1) ? (32 - a->imm) : (16 - a->imm); 3228 3229 vd = tcg_temp_new_i64(); 3230 vfp_load_reg64(vd, a->vd); 3231 3232 fpst = fpstatus_ptr(FPST_FPCR); 3233 shift = tcg_constant_i32(frac_bits); 3234 3235 /* Switch on op:U:sx bits */ 3236 switch (a->opc) { 3237 case 0: 3238 gen_helper_vfp_shtod_round_to_nearest(vd, vd, shift, fpst); 3239 break; 3240 case 1: 3241 gen_helper_vfp_sltod_round_to_nearest(vd, vd, shift, fpst); 3242 break; 3243 case 2: 3244 gen_helper_vfp_uhtod_round_to_nearest(vd, vd, shift, fpst); 3245 break; 3246 case 3: 3247 gen_helper_vfp_ultod_round_to_nearest(vd, vd, shift, fpst); 3248 break; 3249 case 4: 3250 gen_helper_vfp_toshd_round_to_zero(vd, vd, shift, fpst); 3251 break; 3252 case 5: 3253 gen_helper_vfp_tosld_round_to_zero(vd, vd, shift, fpst); 3254 break; 3255 case 6: 3256 gen_helper_vfp_touhd_round_to_zero(vd, vd, shift, fpst); 3257 break; 3258 case 7: 3259 gen_helper_vfp_tould_round_to_zero(vd, vd, shift, fpst); 3260 break; 3261 default: 3262 g_assert_not_reached(); 3263 } 3264 3265 vfp_store_reg64(vd, a->vd); 3266 return true; 3267 } 3268 3269 static bool trans_VCVT_hp_int(DisasContext *s, arg_VCVT_sp_int *a) 3270 { 3271 TCGv_i32 vm; 3272 TCGv_ptr fpst; 3273 3274 if (!dc_isar_feature(aa32_fp16_arith, s)) { 3275 return false; 3276 } 3277 3278 if (!vfp_access_check(s)) { 3279 return true; 3280 } 3281 3282 fpst = fpstatus_ptr(FPST_FPCR_F16); 3283 vm = tcg_temp_new_i32(); 3284 vfp_load_reg32(vm, a->vm); 3285 3286 if (a->s) { 3287 if (a->rz) { 3288 gen_helper_vfp_tosizh(vm, vm, fpst); 3289 } else { 3290 gen_helper_vfp_tosih(vm, vm, fpst); 3291 } 3292 } else { 3293 if (a->rz) { 3294 gen_helper_vfp_touizh(vm, vm, fpst); 3295 } else { 3296 gen_helper_vfp_touih(vm, vm, fpst); 3297 } 3298 } 3299 vfp_store_reg32(vm, a->vd); 3300 return true; 3301 } 3302 3303 static bool trans_VCVT_sp_int(DisasContext *s, arg_VCVT_sp_int *a) 3304 { 3305 TCGv_i32 vm; 3306 TCGv_ptr fpst; 3307 3308 if (!dc_isar_feature(aa32_fpsp_v2, s)) { 3309 return false; 3310 } 3311 3312 if (!vfp_access_check(s)) { 3313 return true; 3314 } 3315 3316 fpst = fpstatus_ptr(FPST_FPCR); 3317 vm = tcg_temp_new_i32(); 3318 vfp_load_reg32(vm, a->vm); 3319 3320 if (a->s) { 3321 if (a->rz) { 3322 gen_helper_vfp_tosizs(vm, vm, fpst); 3323 } else { 3324 gen_helper_vfp_tosis(vm, vm, fpst); 3325 } 3326 } else { 3327 if (a->rz) { 3328 gen_helper_vfp_touizs(vm, vm, fpst); 3329 } else { 3330 gen_helper_vfp_touis(vm, vm, fpst); 3331 } 3332 } 3333 vfp_store_reg32(vm, a->vd); 3334 return true; 3335 } 3336 3337 static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a) 3338 { 3339 TCGv_i32 vd; 3340 TCGv_i64 vm; 3341 TCGv_ptr fpst; 3342 3343 if (!dc_isar_feature(aa32_fpdp_v2, s)) { 3344 return false; 3345 } 3346 3347 /* UNDEF accesses to D16-D31 if they don't exist. */ 3348 if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { 3349 return false; 3350 } 3351 3352 if (!vfp_access_check(s)) { 3353 return true; 3354 } 3355 3356 fpst = fpstatus_ptr(FPST_FPCR); 3357 vm = tcg_temp_new_i64(); 3358 vd = tcg_temp_new_i32(); 3359 vfp_load_reg64(vm, a->vm); 3360 3361 if (a->s) { 3362 if (a->rz) { 3363 gen_helper_vfp_tosizd(vd, vm, fpst); 3364 } else { 3365 gen_helper_vfp_tosid(vd, vm, fpst); 3366 } 3367 } else { 3368 if (a->rz) { 3369 gen_helper_vfp_touizd(vd, vm, fpst); 3370 } else { 3371 gen_helper_vfp_touid(vd, vm, fpst); 3372 } 3373 } 3374 vfp_store_reg32(vd, a->vd); 3375 return true; 3376 } 3377 3378 static bool trans_VINS(DisasContext *s, arg_VINS *a) 3379 { 3380 TCGv_i32 rd, rm; 3381 3382 if (!dc_isar_feature(aa32_fp16_arith, s)) { 3383 return false; 3384 } 3385 3386 if (s->vec_len != 0 || s->vec_stride != 0) { 3387 return false; 3388 } 3389 3390 if (!vfp_access_check(s)) { 3391 return true; 3392 } 3393 3394 /* Insert low half of Vm into high half of Vd */ 3395 rm = tcg_temp_new_i32(); 3396 rd = tcg_temp_new_i32(); 3397 vfp_load_reg32(rm, a->vm); 3398 vfp_load_reg32(rd, a->vd); 3399 tcg_gen_deposit_i32(rd, rd, rm, 16, 16); 3400 vfp_store_reg32(rd, a->vd); 3401 return true; 3402 } 3403 3404 static bool trans_VMOVX(DisasContext *s, arg_VINS *a) 3405 { 3406 TCGv_i32 rm; 3407 3408 if (!dc_isar_feature(aa32_fp16_arith, s)) { 3409 return false; 3410 } 3411 3412 if (s->vec_len != 0 || s->vec_stride != 0) { 3413 return false; 3414 } 3415 3416 if (!vfp_access_check(s)) { 3417 return true; 3418 } 3419 3420 /* Set Vd to high half of Vm */ 3421 rm = tcg_temp_new_i32(); 3422 vfp_load_reg32(rm, a->vm); 3423 tcg_gen_shri_i32(rm, rm, 16); 3424 vfp_store_reg32(rm, a->vd); 3425 return true; 3426 } 3427