19a5071abSPeter Maydell /* 29a5071abSPeter Maydell * ARM translation: M-profile NOCP special-case instructions 39a5071abSPeter Maydell * 49a5071abSPeter Maydell * Copyright (c) 2020 Linaro, Ltd. 59a5071abSPeter Maydell * 69a5071abSPeter Maydell * This library is free software; you can redistribute it and/or 79a5071abSPeter Maydell * modify it under the terms of the GNU Lesser General Public 89a5071abSPeter Maydell * License as published by the Free Software Foundation; either 99a5071abSPeter Maydell * version 2.1 of the License, or (at your option) any later version. 109a5071abSPeter Maydell * 119a5071abSPeter Maydell * This library is distributed in the hope that it will be useful, 129a5071abSPeter Maydell * but WITHOUT ANY WARRANTY; without even the implied warranty of 139a5071abSPeter Maydell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 149a5071abSPeter Maydell * Lesser General Public License for more details. 159a5071abSPeter Maydell * 169a5071abSPeter Maydell * You should have received a copy of the GNU Lesser General Public 179a5071abSPeter Maydell * License along with this library; if not, see <http://www.gnu.org/licenses/>. 189a5071abSPeter Maydell */ 199a5071abSPeter Maydell 209a5071abSPeter Maydell #include "qemu/osdep.h" 219a5071abSPeter Maydell #include "tcg/tcg-op.h" 22fa856736SPeter Maydell #include "tcg/tcg-op-gvec.h" 239a5071abSPeter Maydell #include "translate.h" 249a5071abSPeter Maydell #include "translate-a32.h" 259a5071abSPeter Maydell 269a5071abSPeter Maydell #include "decode-m-nocp.c.inc" 279a5071abSPeter Maydell 289a5071abSPeter Maydell /* 299a5071abSPeter Maydell * Decode VLLDM and VLSTM are nonstandard because: 309a5071abSPeter Maydell * * if there is no FPU then these insns must NOP in 319a5071abSPeter Maydell * Secure state and UNDEF in Nonsecure state 329a5071abSPeter Maydell * * if there is an FPU then these insns do not have 339a5071abSPeter Maydell * the usual behaviour that vfp_access_check() provides of 349a5071abSPeter Maydell * being controlled by CPACR/NSACR enable bits or the 359a5071abSPeter Maydell * lazy-stacking logic. 369a5071abSPeter Maydell */ 379a5071abSPeter Maydell static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a) 389a5071abSPeter Maydell { 399a5071abSPeter Maydell TCGv_i32 fptr; 409a5071abSPeter Maydell 419a5071abSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_M) || 429a5071abSPeter Maydell !arm_dc_feature(s, ARM_FEATURE_V8)) { 439a5071abSPeter Maydell return false; 449a5071abSPeter Maydell } 459a5071abSPeter Maydell 469a5071abSPeter Maydell if (a->op) { 479a5071abSPeter Maydell /* 489a5071abSPeter Maydell * T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not 499a5071abSPeter Maydell * to take the IMPDEF option to make memory accesses to the stack 509a5071abSPeter Maydell * slots that correspond to the D16-D31 registers (discarding 519a5071abSPeter Maydell * read data and writing UNKNOWN values), so for us the T2 529a5071abSPeter Maydell * encoding behaves identically to the T1 encoding. 539a5071abSPeter Maydell */ 549a5071abSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 559a5071abSPeter Maydell return false; 569a5071abSPeter Maydell } 579a5071abSPeter Maydell } else { 589a5071abSPeter Maydell /* 599a5071abSPeter Maydell * T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs. 609a5071abSPeter Maydell * This is currently architecturally impossible, but we add the 619a5071abSPeter Maydell * check to stay in line with the pseudocode. Note that we must 629a5071abSPeter Maydell * emit code for the UNDEF so it takes precedence over the NOCP. 639a5071abSPeter Maydell */ 649a5071abSPeter Maydell if (dc_isar_feature(aa32_simd_r32, s)) { 659a5071abSPeter Maydell unallocated_encoding(s); 669a5071abSPeter Maydell return true; 679a5071abSPeter Maydell } 689a5071abSPeter Maydell } 699a5071abSPeter Maydell 709a5071abSPeter Maydell /* 719a5071abSPeter Maydell * If not secure, UNDEF. We must emit code for this 729a5071abSPeter Maydell * rather than returning false so that this takes 739a5071abSPeter Maydell * precedence over the m-nocp.decode NOCP fallback. 749a5071abSPeter Maydell */ 759a5071abSPeter Maydell if (!s->v8m_secure) { 769a5071abSPeter Maydell unallocated_encoding(s); 779a5071abSPeter Maydell return true; 789a5071abSPeter Maydell } 795138bd01SPeter Maydell 805138bd01SPeter Maydell s->eci_handled = true; 815138bd01SPeter Maydell 829a5071abSPeter Maydell /* If no fpu, NOP. */ 839a5071abSPeter Maydell if (!dc_isar_feature(aa32_vfp, s)) { 845138bd01SPeter Maydell clear_eci_state(s); 859a5071abSPeter Maydell return true; 869a5071abSPeter Maydell } 879a5071abSPeter Maydell 889a5071abSPeter Maydell fptr = load_reg(s, a->rn); 899a5071abSPeter Maydell if (a->l) { 909a5071abSPeter Maydell gen_helper_v7m_vlldm(cpu_env, fptr); 919a5071abSPeter Maydell } else { 929a5071abSPeter Maydell gen_helper_v7m_vlstm(cpu_env, fptr); 939a5071abSPeter Maydell } 949a5071abSPeter Maydell tcg_temp_free_i32(fptr); 959a5071abSPeter Maydell 965138bd01SPeter Maydell clear_eci_state(s); 975138bd01SPeter Maydell 989a5071abSPeter Maydell /* End the TB, because we have updated FP control bits */ 999a5071abSPeter Maydell s->base.is_jmp = DISAS_UPDATE_EXIT; 1009a5071abSPeter Maydell return true; 1019a5071abSPeter Maydell } 1029a5071abSPeter Maydell 1039a5071abSPeter Maydell static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a) 1049a5071abSPeter Maydell { 1059a5071abSPeter Maydell int btmreg, topreg; 1069a5071abSPeter Maydell TCGv_i64 zero; 1079a5071abSPeter Maydell TCGv_i32 aspen, sfpa; 1089a5071abSPeter Maydell 1099a5071abSPeter Maydell if (!dc_isar_feature(aa32_m_sec_state, s)) { 1109a5071abSPeter Maydell /* Before v8.1M, fall through in decode to NOCP check */ 1119a5071abSPeter Maydell return false; 1129a5071abSPeter Maydell } 1139a5071abSPeter Maydell 1149a5071abSPeter Maydell /* Explicitly UNDEF because this takes precedence over NOCP */ 1159a5071abSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) { 1169a5071abSPeter Maydell unallocated_encoding(s); 1179a5071abSPeter Maydell return true; 1189a5071abSPeter Maydell } 1199a5071abSPeter Maydell 1205138bd01SPeter Maydell s->eci_handled = true; 1215138bd01SPeter Maydell 1229a5071abSPeter Maydell if (!dc_isar_feature(aa32_vfp_simd, s)) { 1239a5071abSPeter Maydell /* NOP if we have neither FP nor MVE */ 1245138bd01SPeter Maydell clear_eci_state(s); 1259a5071abSPeter Maydell return true; 1269a5071abSPeter Maydell } 1279a5071abSPeter Maydell 1289a5071abSPeter Maydell /* 1299a5071abSPeter Maydell * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no 1309a5071abSPeter Maydell * active floating point context so we must NOP (without doing 1319a5071abSPeter Maydell * any lazy state preservation or the NOCP check). 1329a5071abSPeter Maydell */ 1339a5071abSPeter Maydell aspen = load_cpu_field(v7m.fpccr[M_REG_S]); 1349a5071abSPeter Maydell sfpa = load_cpu_field(v7m.control[M_REG_S]); 1359a5071abSPeter Maydell tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); 1369a5071abSPeter Maydell tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); 1379a5071abSPeter Maydell tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK); 1389a5071abSPeter Maydell tcg_gen_or_i32(sfpa, sfpa, aspen); 1399a5071abSPeter Maydell arm_gen_condlabel(s); 1409a5071abSPeter Maydell tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel); 1419a5071abSPeter Maydell 1429a5071abSPeter Maydell if (s->fp_excp_el != 0) { 1439a5071abSPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_NOCP, 1449a5071abSPeter Maydell syn_uncategorized(), s->fp_excp_el); 1459a5071abSPeter Maydell return true; 1469a5071abSPeter Maydell } 1479a5071abSPeter Maydell 1489a5071abSPeter Maydell topreg = a->vd + a->imm - 1; 1499a5071abSPeter Maydell btmreg = a->vd; 1509a5071abSPeter Maydell 1519a5071abSPeter Maydell /* Convert to Sreg numbers if the insn specified in Dregs */ 1529a5071abSPeter Maydell if (a->size == 3) { 1539a5071abSPeter Maydell topreg = topreg * 2 + 1; 1549a5071abSPeter Maydell btmreg *= 2; 1559a5071abSPeter Maydell } 1569a5071abSPeter Maydell 1579a5071abSPeter Maydell if (topreg > 63 || (topreg > 31 && !(topreg & 1))) { 1589a5071abSPeter Maydell /* UNPREDICTABLE: we choose to undef */ 1599a5071abSPeter Maydell unallocated_encoding(s); 1609a5071abSPeter Maydell return true; 1619a5071abSPeter Maydell } 1629a5071abSPeter Maydell 1639a5071abSPeter Maydell /* Silently ignore requests to clear D16-D31 if they don't exist */ 1649a5071abSPeter Maydell if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) { 1659a5071abSPeter Maydell topreg = 31; 1669a5071abSPeter Maydell } 1679a5071abSPeter Maydell 1689a5071abSPeter Maydell if (!vfp_access_check(s)) { 1699a5071abSPeter Maydell return true; 1709a5071abSPeter Maydell } 1719a5071abSPeter Maydell 1729a5071abSPeter Maydell /* Zero the Sregs from btmreg to topreg inclusive. */ 1739a5071abSPeter Maydell zero = tcg_const_i64(0); 1749a5071abSPeter Maydell if (btmreg & 1) { 1759a5071abSPeter Maydell write_neon_element64(zero, btmreg >> 1, 1, MO_32); 1769a5071abSPeter Maydell btmreg++; 1779a5071abSPeter Maydell } 1789a5071abSPeter Maydell for (; btmreg + 1 <= topreg; btmreg += 2) { 1799a5071abSPeter Maydell write_neon_element64(zero, btmreg >> 1, 0, MO_64); 1809a5071abSPeter Maydell } 1819a5071abSPeter Maydell if (btmreg == topreg) { 1829a5071abSPeter Maydell write_neon_element64(zero, btmreg >> 1, 0, MO_32); 1839a5071abSPeter Maydell btmreg++; 1849a5071abSPeter Maydell } 1859a5071abSPeter Maydell assert(btmreg == topreg + 1); 186375256a8SPeter Maydell if (dc_isar_feature(aa32_mve, s)) { 187375256a8SPeter Maydell TCGv_i32 z32 = tcg_const_i32(0); 188375256a8SPeter Maydell store_cpu_field(z32, v7m.vpr); 189375256a8SPeter Maydell } 1905138bd01SPeter Maydell 1915138bd01SPeter Maydell clear_eci_state(s); 1929a5071abSPeter Maydell return true; 1939a5071abSPeter Maydell } 1949a5071abSPeter Maydell 195fa856736SPeter Maydell /* 196fa856736SPeter Maydell * M-profile provides two different sets of instructions that can 197fa856736SPeter Maydell * access floating point system registers: VMSR/VMRS (which move 198fa856736SPeter Maydell * to/from a general purpose register) and VLDR/VSTR sysreg (which 199fa856736SPeter Maydell * move directly to/from memory). In some cases there are also side 200fa856736SPeter Maydell * effects which must happen after any write to memory (which could 201fa856736SPeter Maydell * cause an exception). So we implement the common logic for the 202fa856736SPeter Maydell * sysreg access in gen_M_fp_sysreg_write() and gen_M_fp_sysreg_read(), 203fa856736SPeter Maydell * which take pointers to callback functions which will perform the 204fa856736SPeter Maydell * actual "read/write general purpose register" and "read/write 205fa856736SPeter Maydell * memory" operations. 206fa856736SPeter Maydell */ 207fa856736SPeter Maydell 208fa856736SPeter Maydell /* 209fa856736SPeter Maydell * Emit code to store the sysreg to its final destination; frees the 210e494cd0aSPeter Maydell * TCG temp 'value' it is passed. do_access is true to do the store, 211e494cd0aSPeter Maydell * and false to skip it and only perform side-effects like base 212e494cd0aSPeter Maydell * register writeback. 213fa856736SPeter Maydell */ 214e494cd0aSPeter Maydell typedef void fp_sysreg_storefn(DisasContext *s, void *opaque, TCGv_i32 value, 215e494cd0aSPeter Maydell bool do_access); 216fa856736SPeter Maydell /* 217fa856736SPeter Maydell * Emit code to load the value to be copied to the sysreg; returns 218e494cd0aSPeter Maydell * a new TCG temporary. do_access is true to do the store, 219e494cd0aSPeter Maydell * and false to skip it and only perform side-effects like base 220e494cd0aSPeter Maydell * register writeback. 221fa856736SPeter Maydell */ 222e494cd0aSPeter Maydell typedef TCGv_i32 fp_sysreg_loadfn(DisasContext *s, void *opaque, 223e494cd0aSPeter Maydell bool do_access); 224fa856736SPeter Maydell 225fa856736SPeter Maydell /* Common decode/access checks for fp sysreg read/write */ 226fa856736SPeter Maydell typedef enum FPSysRegCheckResult { 227fa856736SPeter Maydell FPSysRegCheckFailed, /* caller should return false */ 228fa856736SPeter Maydell FPSysRegCheckDone, /* caller should return true */ 229fa856736SPeter Maydell FPSysRegCheckContinue, /* caller should continue generating code */ 230fa856736SPeter Maydell } FPSysRegCheckResult; 231fa856736SPeter Maydell 232fa856736SPeter Maydell static FPSysRegCheckResult fp_sysreg_checks(DisasContext *s, int regno) 233fa856736SPeter Maydell { 234fa856736SPeter Maydell if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 235fa856736SPeter Maydell return FPSysRegCheckFailed; 236fa856736SPeter Maydell } 237fa856736SPeter Maydell 238fa856736SPeter Maydell switch (regno) { 239fa856736SPeter Maydell case ARM_VFP_FPSCR: 240fa856736SPeter Maydell case QEMU_VFP_FPSCR_NZCV: 241fa856736SPeter Maydell break; 242fa856736SPeter Maydell case ARM_VFP_FPSCR_NZCVQC: 243fa856736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 244fa856736SPeter Maydell return FPSysRegCheckFailed; 245fa856736SPeter Maydell } 246fa856736SPeter Maydell break; 247fa856736SPeter Maydell case ARM_VFP_FPCXT_S: 248fa856736SPeter Maydell case ARM_VFP_FPCXT_NS: 249fa856736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 250fa856736SPeter Maydell return FPSysRegCheckFailed; 251fa856736SPeter Maydell } 252fa856736SPeter Maydell if (!s->v8m_secure) { 253fa856736SPeter Maydell return FPSysRegCheckFailed; 254fa856736SPeter Maydell } 255fa856736SPeter Maydell break; 256fa856736SPeter Maydell case ARM_VFP_VPR: 257fa856736SPeter Maydell case ARM_VFP_P0: 258fa856736SPeter Maydell if (!dc_isar_feature(aa32_mve, s)) { 259fa856736SPeter Maydell return FPSysRegCheckFailed; 260fa856736SPeter Maydell } 261fa856736SPeter Maydell break; 262fa856736SPeter Maydell default: 263fa856736SPeter Maydell return FPSysRegCheckFailed; 264fa856736SPeter Maydell } 265fa856736SPeter Maydell 266fa856736SPeter Maydell /* 267fa856736SPeter Maydell * FPCXT_NS is a special case: it has specific handling for 268fa856736SPeter Maydell * "current FP state is inactive", and must do the PreserveFPState() 269fa856736SPeter Maydell * but not the usual full set of actions done by ExecuteFPCheck(). 270fa856736SPeter Maydell * So we don't call vfp_access_check() and the callers must handle this. 271fa856736SPeter Maydell */ 272fa856736SPeter Maydell if (regno != ARM_VFP_FPCXT_NS && !vfp_access_check(s)) { 273fa856736SPeter Maydell return FPSysRegCheckDone; 274fa856736SPeter Maydell } 275fa856736SPeter Maydell return FPSysRegCheckContinue; 276fa856736SPeter Maydell } 277fa856736SPeter Maydell 278fa856736SPeter Maydell static void gen_branch_fpInactive(DisasContext *s, TCGCond cond, 279fa856736SPeter Maydell TCGLabel *label) 280fa856736SPeter Maydell { 281fa856736SPeter Maydell /* 282fa856736SPeter Maydell * FPCXT_NS is a special case: it has specific handling for 283fa856736SPeter Maydell * "current FP state is inactive", and must do the PreserveFPState() 284fa856736SPeter Maydell * but not the usual full set of actions done by ExecuteFPCheck(). 285fa856736SPeter Maydell * We don't have a TB flag that matches the fpInactive check, so we 286fa856736SPeter Maydell * do it at runtime as we don't expect FPCXT_NS accesses to be frequent. 287fa856736SPeter Maydell * 288fa856736SPeter Maydell * Emit code that checks fpInactive and does a conditional 289fa856736SPeter Maydell * branch to label based on it: 290fa856736SPeter Maydell * if cond is TCG_COND_NE then branch if fpInactive != 0 (ie if inactive) 291fa856736SPeter Maydell * if cond is TCG_COND_EQ then branch if fpInactive == 0 (ie if active) 292fa856736SPeter Maydell */ 293fa856736SPeter Maydell assert(cond == TCG_COND_EQ || cond == TCG_COND_NE); 294fa856736SPeter Maydell 295fa856736SPeter Maydell /* fpInactive = FPCCR_NS.ASPEN == 1 && CONTROL.FPCA == 0 */ 296fa856736SPeter Maydell TCGv_i32 aspen, fpca; 297fa856736SPeter Maydell aspen = load_cpu_field(v7m.fpccr[M_REG_NS]); 298fa856736SPeter Maydell fpca = load_cpu_field(v7m.control[M_REG_S]); 299fa856736SPeter Maydell tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); 300fa856736SPeter Maydell tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); 301fa856736SPeter Maydell tcg_gen_andi_i32(fpca, fpca, R_V7M_CONTROL_FPCA_MASK); 302fa856736SPeter Maydell tcg_gen_or_i32(fpca, fpca, aspen); 303fa856736SPeter Maydell tcg_gen_brcondi_i32(tcg_invert_cond(cond), fpca, 0, label); 304fa856736SPeter Maydell tcg_temp_free_i32(aspen); 305fa856736SPeter Maydell tcg_temp_free_i32(fpca); 306fa856736SPeter Maydell } 307fa856736SPeter Maydell 308fa856736SPeter Maydell static bool gen_M_fp_sysreg_write(DisasContext *s, int regno, 309fa856736SPeter Maydell fp_sysreg_loadfn *loadfn, 310fa856736SPeter Maydell void *opaque) 311fa856736SPeter Maydell { 312fa856736SPeter Maydell /* Do a write to an M-profile floating point system register */ 313fa856736SPeter Maydell TCGv_i32 tmp; 314fa856736SPeter Maydell TCGLabel *lab_end = NULL; 315fa856736SPeter Maydell 316fa856736SPeter Maydell switch (fp_sysreg_checks(s, regno)) { 317fa856736SPeter Maydell case FPSysRegCheckFailed: 318fa856736SPeter Maydell return false; 319fa856736SPeter Maydell case FPSysRegCheckDone: 320fa856736SPeter Maydell return true; 321fa856736SPeter Maydell case FPSysRegCheckContinue: 322fa856736SPeter Maydell break; 323fa856736SPeter Maydell } 324fa856736SPeter Maydell 325fa856736SPeter Maydell switch (regno) { 326fa856736SPeter Maydell case ARM_VFP_FPSCR: 327e494cd0aSPeter Maydell tmp = loadfn(s, opaque, true); 328fa856736SPeter Maydell gen_helper_vfp_set_fpscr(cpu_env, tmp); 329fa856736SPeter Maydell tcg_temp_free_i32(tmp); 330fa856736SPeter Maydell gen_lookup_tb(s); 331fa856736SPeter Maydell break; 332fa856736SPeter Maydell case ARM_VFP_FPSCR_NZCVQC: 333fa856736SPeter Maydell { 334fa856736SPeter Maydell TCGv_i32 fpscr; 335e494cd0aSPeter Maydell tmp = loadfn(s, opaque, true); 336fa856736SPeter Maydell if (dc_isar_feature(aa32_mve, s)) { 337fa856736SPeter Maydell /* QC is only present for MVE; otherwise RES0 */ 338fa856736SPeter Maydell TCGv_i32 qc = tcg_temp_new_i32(); 339fa856736SPeter Maydell tcg_gen_andi_i32(qc, tmp, FPCR_QC); 340fa856736SPeter Maydell /* 341fa856736SPeter Maydell * The 4 vfp.qc[] fields need only be "zero" vs "non-zero"; 342fa856736SPeter Maydell * here writing the same value into all elements is simplest. 343fa856736SPeter Maydell */ 344fa856736SPeter Maydell tcg_gen_gvec_dup_i32(MO_32, offsetof(CPUARMState, vfp.qc), 345fa856736SPeter Maydell 16, 16, qc); 346fa856736SPeter Maydell } 347fa856736SPeter Maydell tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK); 348fa856736SPeter Maydell fpscr = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); 349fa856736SPeter Maydell tcg_gen_andi_i32(fpscr, fpscr, ~FPCR_NZCV_MASK); 350fa856736SPeter Maydell tcg_gen_or_i32(fpscr, fpscr, tmp); 351fa856736SPeter Maydell store_cpu_field(fpscr, vfp.xregs[ARM_VFP_FPSCR]); 352fa856736SPeter Maydell tcg_temp_free_i32(tmp); 353fa856736SPeter Maydell break; 354fa856736SPeter Maydell } 355fa856736SPeter Maydell case ARM_VFP_FPCXT_NS: 356e494cd0aSPeter Maydell { 357e494cd0aSPeter Maydell TCGLabel *lab_active = gen_new_label(); 358e494cd0aSPeter Maydell 359fa856736SPeter Maydell lab_end = gen_new_label(); 360e494cd0aSPeter Maydell gen_branch_fpInactive(s, TCG_COND_EQ, lab_active); 361e494cd0aSPeter Maydell /* 362e494cd0aSPeter Maydell * fpInactive case: write is a NOP, so only do side effects 363e494cd0aSPeter Maydell * like register writeback before we branch to end 364e494cd0aSPeter Maydell */ 365e494cd0aSPeter Maydell loadfn(s, opaque, false); 366e494cd0aSPeter Maydell tcg_gen_br(lab_end); 367e494cd0aSPeter Maydell 368e494cd0aSPeter Maydell gen_set_label(lab_active); 369fa856736SPeter Maydell /* 370fa856736SPeter Maydell * !fpInactive: if FPU disabled, take NOCP exception; 371fa856736SPeter Maydell * otherwise PreserveFPState(), and then FPCXT_NS writes 372fa856736SPeter Maydell * behave the same as FPCXT_S writes. 373fa856736SPeter Maydell */ 374*88137f78SPeter Maydell if (!vfp_access_check_m(s, true)) { 375fa856736SPeter Maydell /* 376fa856736SPeter Maydell * This was only a conditional exception, so override 377fa856736SPeter Maydell * gen_exception_insn()'s default to DISAS_NORETURN 378fa856736SPeter Maydell */ 379fa856736SPeter Maydell s->base.is_jmp = DISAS_NEXT; 380fa856736SPeter Maydell break; 381fa856736SPeter Maydell } 382e494cd0aSPeter Maydell } 383fa856736SPeter Maydell /* fall through */ 384fa856736SPeter Maydell case ARM_VFP_FPCXT_S: 385fa856736SPeter Maydell { 386fa856736SPeter Maydell TCGv_i32 sfpa, control; 387fa856736SPeter Maydell /* 388fa856736SPeter Maydell * Set FPSCR and CONTROL.SFPA from value; the new FPSCR takes 389fa856736SPeter Maydell * bits [27:0] from value and zeroes bits [31:28]. 390fa856736SPeter Maydell */ 391e494cd0aSPeter Maydell tmp = loadfn(s, opaque, true); 392fa856736SPeter Maydell sfpa = tcg_temp_new_i32(); 393fa856736SPeter Maydell tcg_gen_shri_i32(sfpa, tmp, 31); 394fa856736SPeter Maydell control = load_cpu_field(v7m.control[M_REG_S]); 395fa856736SPeter Maydell tcg_gen_deposit_i32(control, control, sfpa, 396fa856736SPeter Maydell R_V7M_CONTROL_SFPA_SHIFT, 1); 397fa856736SPeter Maydell store_cpu_field(control, v7m.control[M_REG_S]); 398fa856736SPeter Maydell tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK); 399fa856736SPeter Maydell gen_helper_vfp_set_fpscr(cpu_env, tmp); 400fa856736SPeter Maydell tcg_temp_free_i32(tmp); 401fa856736SPeter Maydell tcg_temp_free_i32(sfpa); 402fa856736SPeter Maydell break; 403fa856736SPeter Maydell } 404fa856736SPeter Maydell case ARM_VFP_VPR: 405fa856736SPeter Maydell /* Behaves as NOP if not privileged */ 406fa856736SPeter Maydell if (IS_USER(s)) { 407e494cd0aSPeter Maydell loadfn(s, opaque, false); 408fa856736SPeter Maydell break; 409fa856736SPeter Maydell } 410e494cd0aSPeter Maydell tmp = loadfn(s, opaque, true); 411fa856736SPeter Maydell store_cpu_field(tmp, v7m.vpr); 412fa856736SPeter Maydell break; 413fa856736SPeter Maydell case ARM_VFP_P0: 414fa856736SPeter Maydell { 415fa856736SPeter Maydell TCGv_i32 vpr; 416e494cd0aSPeter Maydell tmp = loadfn(s, opaque, true); 417fa856736SPeter Maydell vpr = load_cpu_field(v7m.vpr); 418fa856736SPeter Maydell tcg_gen_deposit_i32(vpr, vpr, tmp, 419fa856736SPeter Maydell R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH); 420fa856736SPeter Maydell store_cpu_field(vpr, v7m.vpr); 421fa856736SPeter Maydell tcg_temp_free_i32(tmp); 422fa856736SPeter Maydell break; 423fa856736SPeter Maydell } 424fa856736SPeter Maydell default: 425fa856736SPeter Maydell g_assert_not_reached(); 426fa856736SPeter Maydell } 427fa856736SPeter Maydell if (lab_end) { 428fa856736SPeter Maydell gen_set_label(lab_end); 429fa856736SPeter Maydell } 430fa856736SPeter Maydell return true; 431fa856736SPeter Maydell } 432fa856736SPeter Maydell 433fa856736SPeter Maydell static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, 434fa856736SPeter Maydell fp_sysreg_storefn *storefn, 435fa856736SPeter Maydell void *opaque) 436fa856736SPeter Maydell { 437fa856736SPeter Maydell /* Do a read from an M-profile floating point system register */ 438fa856736SPeter Maydell TCGv_i32 tmp; 439fa856736SPeter Maydell TCGLabel *lab_end = NULL; 440fa856736SPeter Maydell bool lookup_tb = false; 441fa856736SPeter Maydell 442fa856736SPeter Maydell switch (fp_sysreg_checks(s, regno)) { 443fa856736SPeter Maydell case FPSysRegCheckFailed: 444fa856736SPeter Maydell return false; 445fa856736SPeter Maydell case FPSysRegCheckDone: 446fa856736SPeter Maydell return true; 447fa856736SPeter Maydell case FPSysRegCheckContinue: 448fa856736SPeter Maydell break; 449fa856736SPeter Maydell } 450fa856736SPeter Maydell 451fa856736SPeter Maydell if (regno == ARM_VFP_FPSCR_NZCVQC && !dc_isar_feature(aa32_mve, s)) { 452fa856736SPeter Maydell /* QC is RES0 without MVE, so NZCVQC simplifies to NZCV */ 453fa856736SPeter Maydell regno = QEMU_VFP_FPSCR_NZCV; 454fa856736SPeter Maydell } 455fa856736SPeter Maydell 456fa856736SPeter Maydell switch (regno) { 457fa856736SPeter Maydell case ARM_VFP_FPSCR: 458fa856736SPeter Maydell tmp = tcg_temp_new_i32(); 459fa856736SPeter Maydell gen_helper_vfp_get_fpscr(tmp, cpu_env); 460e494cd0aSPeter Maydell storefn(s, opaque, tmp, true); 461fa856736SPeter Maydell break; 462fa856736SPeter Maydell case ARM_VFP_FPSCR_NZCVQC: 463fa856736SPeter Maydell tmp = tcg_temp_new_i32(); 464fa856736SPeter Maydell gen_helper_vfp_get_fpscr(tmp, cpu_env); 465fa856736SPeter Maydell tcg_gen_andi_i32(tmp, tmp, FPCR_NZCVQC_MASK); 466e494cd0aSPeter Maydell storefn(s, opaque, tmp, true); 467fa856736SPeter Maydell break; 468fa856736SPeter Maydell case QEMU_VFP_FPSCR_NZCV: 469fa856736SPeter Maydell /* 470fa856736SPeter Maydell * Read just NZCV; this is a special case to avoid the 471fa856736SPeter Maydell * helper call for the "VMRS to CPSR.NZCV" insn. 472fa856736SPeter Maydell */ 473fa856736SPeter Maydell tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); 474fa856736SPeter Maydell tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK); 475e494cd0aSPeter Maydell storefn(s, opaque, tmp, true); 476fa856736SPeter Maydell break; 477fa856736SPeter Maydell case ARM_VFP_FPCXT_S: 478fa856736SPeter Maydell { 479fa856736SPeter Maydell TCGv_i32 control, sfpa, fpscr; 480fa856736SPeter Maydell /* Bits [27:0] from FPSCR, bit [31] from CONTROL.SFPA */ 481fa856736SPeter Maydell tmp = tcg_temp_new_i32(); 482fa856736SPeter Maydell sfpa = tcg_temp_new_i32(); 483fa856736SPeter Maydell gen_helper_vfp_get_fpscr(tmp, cpu_env); 484fa856736SPeter Maydell tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK); 485fa856736SPeter Maydell control = load_cpu_field(v7m.control[M_REG_S]); 486fa856736SPeter Maydell tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK); 487fa856736SPeter Maydell tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT); 488fa856736SPeter Maydell tcg_gen_or_i32(tmp, tmp, sfpa); 489fa856736SPeter Maydell tcg_temp_free_i32(sfpa); 490fa856736SPeter Maydell /* 491fa856736SPeter Maydell * Store result before updating FPSCR etc, in case 492fa856736SPeter Maydell * it is a memory write which causes an exception. 493fa856736SPeter Maydell */ 494e494cd0aSPeter Maydell storefn(s, opaque, tmp, true); 495fa856736SPeter Maydell /* 496fa856736SPeter Maydell * Now we must reset FPSCR from FPDSCR_NS, and clear 497fa856736SPeter Maydell * CONTROL.SFPA; so we'll end the TB here. 498fa856736SPeter Maydell */ 499fa856736SPeter Maydell tcg_gen_andi_i32(control, control, ~R_V7M_CONTROL_SFPA_MASK); 500fa856736SPeter Maydell store_cpu_field(control, v7m.control[M_REG_S]); 501fa856736SPeter Maydell fpscr = load_cpu_field(v7m.fpdscr[M_REG_NS]); 502fa856736SPeter Maydell gen_helper_vfp_set_fpscr(cpu_env, fpscr); 503fa856736SPeter Maydell tcg_temp_free_i32(fpscr); 504fa856736SPeter Maydell lookup_tb = true; 505fa856736SPeter Maydell break; 506fa856736SPeter Maydell } 507fa856736SPeter Maydell case ARM_VFP_FPCXT_NS: 508fa856736SPeter Maydell { 509fa856736SPeter Maydell TCGv_i32 control, sfpa, fpscr, fpdscr, zero; 510fa856736SPeter Maydell TCGLabel *lab_active = gen_new_label(); 511fa856736SPeter Maydell 512fa856736SPeter Maydell lookup_tb = true; 513fa856736SPeter Maydell 514fa856736SPeter Maydell gen_branch_fpInactive(s, TCG_COND_EQ, lab_active); 515fa856736SPeter Maydell /* fpInactive case: reads as FPDSCR_NS */ 516fa856736SPeter Maydell TCGv_i32 tmp = load_cpu_field(v7m.fpdscr[M_REG_NS]); 517e494cd0aSPeter Maydell storefn(s, opaque, tmp, true); 518fa856736SPeter Maydell lab_end = gen_new_label(); 519fa856736SPeter Maydell tcg_gen_br(lab_end); 520fa856736SPeter Maydell 521fa856736SPeter Maydell gen_set_label(lab_active); 522fa856736SPeter Maydell /* 523fa856736SPeter Maydell * !fpInactive: if FPU disabled, take NOCP exception; 524fa856736SPeter Maydell * otherwise PreserveFPState(), and then FPCXT_NS 525fa856736SPeter Maydell * reads the same as FPCXT_S. 526fa856736SPeter Maydell */ 527*88137f78SPeter Maydell if (!vfp_access_check_m(s, true)) { 528fa856736SPeter Maydell /* 529fa856736SPeter Maydell * This was only a conditional exception, so override 530fa856736SPeter Maydell * gen_exception_insn()'s default to DISAS_NORETURN 531fa856736SPeter Maydell */ 532fa856736SPeter Maydell s->base.is_jmp = DISAS_NEXT; 533fa856736SPeter Maydell break; 534fa856736SPeter Maydell } 535fa856736SPeter Maydell tmp = tcg_temp_new_i32(); 536fa856736SPeter Maydell sfpa = tcg_temp_new_i32(); 537fa856736SPeter Maydell fpscr = tcg_temp_new_i32(); 538fa856736SPeter Maydell gen_helper_vfp_get_fpscr(fpscr, cpu_env); 539fa856736SPeter Maydell tcg_gen_andi_i32(tmp, fpscr, ~FPCR_NZCV_MASK); 540fa856736SPeter Maydell control = load_cpu_field(v7m.control[M_REG_S]); 541fa856736SPeter Maydell tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK); 542fa856736SPeter Maydell tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT); 543fa856736SPeter Maydell tcg_gen_or_i32(tmp, tmp, sfpa); 544fa856736SPeter Maydell tcg_temp_free_i32(control); 545fa856736SPeter Maydell /* Store result before updating FPSCR, in case it faults */ 546e494cd0aSPeter Maydell storefn(s, opaque, tmp, true); 547fa856736SPeter Maydell /* If SFPA is zero then set FPSCR from FPDSCR_NS */ 548fa856736SPeter Maydell fpdscr = load_cpu_field(v7m.fpdscr[M_REG_NS]); 549fa856736SPeter Maydell zero = tcg_const_i32(0); 550fa856736SPeter Maydell tcg_gen_movcond_i32(TCG_COND_EQ, fpscr, sfpa, zero, fpdscr, fpscr); 551fa856736SPeter Maydell gen_helper_vfp_set_fpscr(cpu_env, fpscr); 552fa856736SPeter Maydell tcg_temp_free_i32(zero); 553fa856736SPeter Maydell tcg_temp_free_i32(sfpa); 554fa856736SPeter Maydell tcg_temp_free_i32(fpdscr); 555fa856736SPeter Maydell tcg_temp_free_i32(fpscr); 556fa856736SPeter Maydell break; 557fa856736SPeter Maydell } 558fa856736SPeter Maydell case ARM_VFP_VPR: 559fa856736SPeter Maydell /* Behaves as NOP if not privileged */ 560fa856736SPeter Maydell if (IS_USER(s)) { 561e494cd0aSPeter Maydell storefn(s, opaque, NULL, false); 562fa856736SPeter Maydell break; 563fa856736SPeter Maydell } 564fa856736SPeter Maydell tmp = load_cpu_field(v7m.vpr); 565e494cd0aSPeter Maydell storefn(s, opaque, tmp, true); 566fa856736SPeter Maydell break; 567fa856736SPeter Maydell case ARM_VFP_P0: 568fa856736SPeter Maydell tmp = load_cpu_field(v7m.vpr); 569fa856736SPeter Maydell tcg_gen_extract_i32(tmp, tmp, R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH); 570e494cd0aSPeter Maydell storefn(s, opaque, tmp, true); 571fa856736SPeter Maydell break; 572fa856736SPeter Maydell default: 573fa856736SPeter Maydell g_assert_not_reached(); 574fa856736SPeter Maydell } 575fa856736SPeter Maydell 576fa856736SPeter Maydell if (lab_end) { 577fa856736SPeter Maydell gen_set_label(lab_end); 578fa856736SPeter Maydell } 579fa856736SPeter Maydell if (lookup_tb) { 580fa856736SPeter Maydell gen_lookup_tb(s); 581fa856736SPeter Maydell } 582fa856736SPeter Maydell return true; 583fa856736SPeter Maydell } 584fa856736SPeter Maydell 585e494cd0aSPeter Maydell static void fp_sysreg_to_gpr(DisasContext *s, void *opaque, TCGv_i32 value, 586e494cd0aSPeter Maydell bool do_access) 587fa856736SPeter Maydell { 588fa856736SPeter Maydell arg_VMSR_VMRS *a = opaque; 589fa856736SPeter Maydell 590e494cd0aSPeter Maydell if (!do_access) { 591e494cd0aSPeter Maydell return; 592e494cd0aSPeter Maydell } 593e494cd0aSPeter Maydell 594fa856736SPeter Maydell if (a->rt == 15) { 595fa856736SPeter Maydell /* Set the 4 flag bits in the CPSR */ 596fa856736SPeter Maydell gen_set_nzcv(value); 597fa856736SPeter Maydell tcg_temp_free_i32(value); 598fa856736SPeter Maydell } else { 599fa856736SPeter Maydell store_reg(s, a->rt, value); 600fa856736SPeter Maydell } 601fa856736SPeter Maydell } 602fa856736SPeter Maydell 603e494cd0aSPeter Maydell static TCGv_i32 gpr_to_fp_sysreg(DisasContext *s, void *opaque, bool do_access) 604fa856736SPeter Maydell { 605fa856736SPeter Maydell arg_VMSR_VMRS *a = opaque; 606fa856736SPeter Maydell 607e494cd0aSPeter Maydell if (!do_access) { 608e494cd0aSPeter Maydell return NULL; 609e494cd0aSPeter Maydell } 610fa856736SPeter Maydell return load_reg(s, a->rt); 611fa856736SPeter Maydell } 612fa856736SPeter Maydell 613fa856736SPeter Maydell static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) 614fa856736SPeter Maydell { 615fa856736SPeter Maydell /* 616fa856736SPeter Maydell * Accesses to R15 are UNPREDICTABLE; we choose to undef. 617fa856736SPeter Maydell * FPSCR -> r15 is a special case which writes to the PSR flags; 618fa856736SPeter Maydell * set a->reg to a special value to tell gen_M_fp_sysreg_read() 619fa856736SPeter Maydell * we only care about the top 4 bits of FPSCR there. 620fa856736SPeter Maydell */ 621fa856736SPeter Maydell if (a->rt == 15) { 622fa856736SPeter Maydell if (a->l && a->reg == ARM_VFP_FPSCR) { 623fa856736SPeter Maydell a->reg = QEMU_VFP_FPSCR_NZCV; 624fa856736SPeter Maydell } else { 625fa856736SPeter Maydell return false; 626fa856736SPeter Maydell } 627fa856736SPeter Maydell } 628fa856736SPeter Maydell 629fa856736SPeter Maydell if (a->l) { 630fa856736SPeter Maydell /* VMRS, move FP system register to gp register */ 631fa856736SPeter Maydell return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_gpr, a); 632fa856736SPeter Maydell } else { 633fa856736SPeter Maydell /* VMSR, move gp register to FP system register */ 634fa856736SPeter Maydell return gen_M_fp_sysreg_write(s, a->reg, gpr_to_fp_sysreg, a); 635fa856736SPeter Maydell } 636fa856736SPeter Maydell } 637fa856736SPeter Maydell 638e494cd0aSPeter Maydell static void fp_sysreg_to_memory(DisasContext *s, void *opaque, TCGv_i32 value, 639e494cd0aSPeter Maydell bool do_access) 640fa856736SPeter Maydell { 641fa856736SPeter Maydell arg_vldr_sysreg *a = opaque; 642fa856736SPeter Maydell uint32_t offset = a->imm; 643fa856736SPeter Maydell TCGv_i32 addr; 644fa856736SPeter Maydell 645fa856736SPeter Maydell if (!a->a) { 646fa856736SPeter Maydell offset = -offset; 647fa856736SPeter Maydell } 648fa856736SPeter Maydell 649e494cd0aSPeter Maydell if (!do_access && !a->w) { 650e494cd0aSPeter Maydell return; 651e494cd0aSPeter Maydell } 652e494cd0aSPeter Maydell 653fa856736SPeter Maydell addr = load_reg(s, a->rn); 654fa856736SPeter Maydell if (a->p) { 655fa856736SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 656fa856736SPeter Maydell } 657fa856736SPeter Maydell 658fa856736SPeter Maydell if (s->v8m_stackcheck && a->rn == 13 && a->w) { 659fa856736SPeter Maydell gen_helper_v8m_stackcheck(cpu_env, addr); 660fa856736SPeter Maydell } 661fa856736SPeter Maydell 662e494cd0aSPeter Maydell if (do_access) { 663fa856736SPeter Maydell gen_aa32_st_i32(s, value, addr, get_mem_index(s), 664fa856736SPeter Maydell MO_UL | MO_ALIGN | s->be_data); 665fa856736SPeter Maydell tcg_temp_free_i32(value); 666e494cd0aSPeter Maydell } 667fa856736SPeter Maydell 668fa856736SPeter Maydell if (a->w) { 669fa856736SPeter Maydell /* writeback */ 670fa856736SPeter Maydell if (!a->p) { 671fa856736SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 672fa856736SPeter Maydell } 673fa856736SPeter Maydell store_reg(s, a->rn, addr); 674fa856736SPeter Maydell } else { 675fa856736SPeter Maydell tcg_temp_free_i32(addr); 676fa856736SPeter Maydell } 677fa856736SPeter Maydell } 678fa856736SPeter Maydell 679e494cd0aSPeter Maydell static TCGv_i32 memory_to_fp_sysreg(DisasContext *s, void *opaque, 680e494cd0aSPeter Maydell bool do_access) 681fa856736SPeter Maydell { 682fa856736SPeter Maydell arg_vldr_sysreg *a = opaque; 683fa856736SPeter Maydell uint32_t offset = a->imm; 684fa856736SPeter Maydell TCGv_i32 addr; 685e494cd0aSPeter Maydell TCGv_i32 value = NULL; 686fa856736SPeter Maydell 687fa856736SPeter Maydell if (!a->a) { 688fa856736SPeter Maydell offset = -offset; 689fa856736SPeter Maydell } 690fa856736SPeter Maydell 691e494cd0aSPeter Maydell if (!do_access && !a->w) { 692e494cd0aSPeter Maydell return NULL; 693e494cd0aSPeter Maydell } 694e494cd0aSPeter Maydell 695fa856736SPeter Maydell addr = load_reg(s, a->rn); 696fa856736SPeter Maydell if (a->p) { 697fa856736SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 698fa856736SPeter Maydell } 699fa856736SPeter Maydell 700fa856736SPeter Maydell if (s->v8m_stackcheck && a->rn == 13 && a->w) { 701fa856736SPeter Maydell gen_helper_v8m_stackcheck(cpu_env, addr); 702fa856736SPeter Maydell } 703fa856736SPeter Maydell 704e494cd0aSPeter Maydell if (do_access) { 705e494cd0aSPeter Maydell value = tcg_temp_new_i32(); 706fa856736SPeter Maydell gen_aa32_ld_i32(s, value, addr, get_mem_index(s), 707fa856736SPeter Maydell MO_UL | MO_ALIGN | s->be_data); 708e494cd0aSPeter Maydell } 709fa856736SPeter Maydell 710fa856736SPeter Maydell if (a->w) { 711fa856736SPeter Maydell /* writeback */ 712fa856736SPeter Maydell if (!a->p) { 713fa856736SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 714fa856736SPeter Maydell } 715fa856736SPeter Maydell store_reg(s, a->rn, addr); 716fa856736SPeter Maydell } else { 717fa856736SPeter Maydell tcg_temp_free_i32(addr); 718fa856736SPeter Maydell } 719fa856736SPeter Maydell return value; 720fa856736SPeter Maydell } 721fa856736SPeter Maydell 722fa856736SPeter Maydell static bool trans_VLDR_sysreg(DisasContext *s, arg_vldr_sysreg *a) 723fa856736SPeter Maydell { 724fa856736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 725fa856736SPeter Maydell return false; 726fa856736SPeter Maydell } 727fa856736SPeter Maydell if (a->rn == 15) { 728fa856736SPeter Maydell return false; 729fa856736SPeter Maydell } 730fa856736SPeter Maydell return gen_M_fp_sysreg_write(s, a->reg, memory_to_fp_sysreg, a); 731fa856736SPeter Maydell } 732fa856736SPeter Maydell 733fa856736SPeter Maydell static bool trans_VSTR_sysreg(DisasContext *s, arg_vldr_sysreg *a) 734fa856736SPeter Maydell { 735fa856736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 736fa856736SPeter Maydell return false; 737fa856736SPeter Maydell } 738fa856736SPeter Maydell if (a->rn == 15) { 739fa856736SPeter Maydell return false; 740fa856736SPeter Maydell } 741fa856736SPeter Maydell return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_memory, a); 742fa856736SPeter Maydell } 743fa856736SPeter Maydell 7449a5071abSPeter Maydell static bool trans_NOCP(DisasContext *s, arg_nocp *a) 7459a5071abSPeter Maydell { 7469a5071abSPeter Maydell /* 7479a5071abSPeter Maydell * Handle M-profile early check for disabled coprocessor: 7489a5071abSPeter Maydell * all we need to do here is emit the NOCP exception if 7499a5071abSPeter Maydell * the coprocessor is disabled. Otherwise we return false 7509a5071abSPeter Maydell * and the real VFP/etc decode will handle the insn. 7519a5071abSPeter Maydell */ 7529a5071abSPeter Maydell assert(arm_dc_feature(s, ARM_FEATURE_M)); 7539a5071abSPeter Maydell 7549a5071abSPeter Maydell if (a->cp == 11) { 7559a5071abSPeter Maydell a->cp = 10; 7569a5071abSPeter Maydell } 7579a5071abSPeter Maydell if (arm_dc_feature(s, ARM_FEATURE_V8_1M) && 7589a5071abSPeter Maydell (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) { 7599a5071abSPeter Maydell /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */ 7609a5071abSPeter Maydell a->cp = 10; 7619a5071abSPeter Maydell } 7629a5071abSPeter Maydell 7639a5071abSPeter Maydell if (a->cp != 10) { 7649a5071abSPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_NOCP, 7659a5071abSPeter Maydell syn_uncategorized(), default_exception_el(s)); 7669a5071abSPeter Maydell return true; 7679a5071abSPeter Maydell } 7689a5071abSPeter Maydell 7699a5071abSPeter Maydell if (s->fp_excp_el != 0) { 7709a5071abSPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_NOCP, 7719a5071abSPeter Maydell syn_uncategorized(), s->fp_excp_el); 7729a5071abSPeter Maydell return true; 7739a5071abSPeter Maydell } 7749a5071abSPeter Maydell 7759a5071abSPeter Maydell return false; 7769a5071abSPeter Maydell } 7779a5071abSPeter Maydell 7789a5071abSPeter Maydell static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a) 7799a5071abSPeter Maydell { 7809a5071abSPeter Maydell /* This range needs a coprocessor check for v8.1M and later only */ 7819a5071abSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 7829a5071abSPeter Maydell return false; 7839a5071abSPeter Maydell } 7849a5071abSPeter Maydell return trans_NOCP(s, a); 7859a5071abSPeter Maydell } 786