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" 22*fa856736SPeter 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 195*fa856736SPeter Maydell /* 196*fa856736SPeter Maydell * M-profile provides two different sets of instructions that can 197*fa856736SPeter Maydell * access floating point system registers: VMSR/VMRS (which move 198*fa856736SPeter Maydell * to/from a general purpose register) and VLDR/VSTR sysreg (which 199*fa856736SPeter Maydell * move directly to/from memory). In some cases there are also side 200*fa856736SPeter Maydell * effects which must happen after any write to memory (which could 201*fa856736SPeter Maydell * cause an exception). So we implement the common logic for the 202*fa856736SPeter Maydell * sysreg access in gen_M_fp_sysreg_write() and gen_M_fp_sysreg_read(), 203*fa856736SPeter Maydell * which take pointers to callback functions which will perform the 204*fa856736SPeter Maydell * actual "read/write general purpose register" and "read/write 205*fa856736SPeter Maydell * memory" operations. 206*fa856736SPeter Maydell */ 207*fa856736SPeter Maydell 208*fa856736SPeter Maydell /* 209*fa856736SPeter Maydell * Emit code to store the sysreg to its final destination; frees the 210*fa856736SPeter Maydell * TCG temp 'value' it is passed. 211*fa856736SPeter Maydell */ 212*fa856736SPeter Maydell typedef void fp_sysreg_storefn(DisasContext *s, void *opaque, TCGv_i32 value); 213*fa856736SPeter Maydell /* 214*fa856736SPeter Maydell * Emit code to load the value to be copied to the sysreg; returns 215*fa856736SPeter Maydell * a new TCG temporary 216*fa856736SPeter Maydell */ 217*fa856736SPeter Maydell typedef TCGv_i32 fp_sysreg_loadfn(DisasContext *s, void *opaque); 218*fa856736SPeter Maydell 219*fa856736SPeter Maydell /* Common decode/access checks for fp sysreg read/write */ 220*fa856736SPeter Maydell typedef enum FPSysRegCheckResult { 221*fa856736SPeter Maydell FPSysRegCheckFailed, /* caller should return false */ 222*fa856736SPeter Maydell FPSysRegCheckDone, /* caller should return true */ 223*fa856736SPeter Maydell FPSysRegCheckContinue, /* caller should continue generating code */ 224*fa856736SPeter Maydell } FPSysRegCheckResult; 225*fa856736SPeter Maydell 226*fa856736SPeter Maydell static FPSysRegCheckResult fp_sysreg_checks(DisasContext *s, int regno) 227*fa856736SPeter Maydell { 228*fa856736SPeter Maydell if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 229*fa856736SPeter Maydell return FPSysRegCheckFailed; 230*fa856736SPeter Maydell } 231*fa856736SPeter Maydell 232*fa856736SPeter Maydell switch (regno) { 233*fa856736SPeter Maydell case ARM_VFP_FPSCR: 234*fa856736SPeter Maydell case QEMU_VFP_FPSCR_NZCV: 235*fa856736SPeter Maydell break; 236*fa856736SPeter Maydell case ARM_VFP_FPSCR_NZCVQC: 237*fa856736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 238*fa856736SPeter Maydell return FPSysRegCheckFailed; 239*fa856736SPeter Maydell } 240*fa856736SPeter Maydell break; 241*fa856736SPeter Maydell case ARM_VFP_FPCXT_S: 242*fa856736SPeter Maydell case ARM_VFP_FPCXT_NS: 243*fa856736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 244*fa856736SPeter Maydell return FPSysRegCheckFailed; 245*fa856736SPeter Maydell } 246*fa856736SPeter Maydell if (!s->v8m_secure) { 247*fa856736SPeter Maydell return FPSysRegCheckFailed; 248*fa856736SPeter Maydell } 249*fa856736SPeter Maydell break; 250*fa856736SPeter Maydell case ARM_VFP_VPR: 251*fa856736SPeter Maydell case ARM_VFP_P0: 252*fa856736SPeter Maydell if (!dc_isar_feature(aa32_mve, s)) { 253*fa856736SPeter Maydell return FPSysRegCheckFailed; 254*fa856736SPeter Maydell } 255*fa856736SPeter Maydell break; 256*fa856736SPeter Maydell default: 257*fa856736SPeter Maydell return FPSysRegCheckFailed; 258*fa856736SPeter Maydell } 259*fa856736SPeter Maydell 260*fa856736SPeter Maydell /* 261*fa856736SPeter Maydell * FPCXT_NS is a special case: it has specific handling for 262*fa856736SPeter Maydell * "current FP state is inactive", and must do the PreserveFPState() 263*fa856736SPeter Maydell * but not the usual full set of actions done by ExecuteFPCheck(). 264*fa856736SPeter Maydell * So we don't call vfp_access_check() and the callers must handle this. 265*fa856736SPeter Maydell */ 266*fa856736SPeter Maydell if (regno != ARM_VFP_FPCXT_NS && !vfp_access_check(s)) { 267*fa856736SPeter Maydell return FPSysRegCheckDone; 268*fa856736SPeter Maydell } 269*fa856736SPeter Maydell return FPSysRegCheckContinue; 270*fa856736SPeter Maydell } 271*fa856736SPeter Maydell 272*fa856736SPeter Maydell static void gen_branch_fpInactive(DisasContext *s, TCGCond cond, 273*fa856736SPeter Maydell TCGLabel *label) 274*fa856736SPeter Maydell { 275*fa856736SPeter Maydell /* 276*fa856736SPeter Maydell * FPCXT_NS is a special case: it has specific handling for 277*fa856736SPeter Maydell * "current FP state is inactive", and must do the PreserveFPState() 278*fa856736SPeter Maydell * but not the usual full set of actions done by ExecuteFPCheck(). 279*fa856736SPeter Maydell * We don't have a TB flag that matches the fpInactive check, so we 280*fa856736SPeter Maydell * do it at runtime as we don't expect FPCXT_NS accesses to be frequent. 281*fa856736SPeter Maydell * 282*fa856736SPeter Maydell * Emit code that checks fpInactive and does a conditional 283*fa856736SPeter Maydell * branch to label based on it: 284*fa856736SPeter Maydell * if cond is TCG_COND_NE then branch if fpInactive != 0 (ie if inactive) 285*fa856736SPeter Maydell * if cond is TCG_COND_EQ then branch if fpInactive == 0 (ie if active) 286*fa856736SPeter Maydell */ 287*fa856736SPeter Maydell assert(cond == TCG_COND_EQ || cond == TCG_COND_NE); 288*fa856736SPeter Maydell 289*fa856736SPeter Maydell /* fpInactive = FPCCR_NS.ASPEN == 1 && CONTROL.FPCA == 0 */ 290*fa856736SPeter Maydell TCGv_i32 aspen, fpca; 291*fa856736SPeter Maydell aspen = load_cpu_field(v7m.fpccr[M_REG_NS]); 292*fa856736SPeter Maydell fpca = load_cpu_field(v7m.control[M_REG_S]); 293*fa856736SPeter Maydell tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); 294*fa856736SPeter Maydell tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); 295*fa856736SPeter Maydell tcg_gen_andi_i32(fpca, fpca, R_V7M_CONTROL_FPCA_MASK); 296*fa856736SPeter Maydell tcg_gen_or_i32(fpca, fpca, aspen); 297*fa856736SPeter Maydell tcg_gen_brcondi_i32(tcg_invert_cond(cond), fpca, 0, label); 298*fa856736SPeter Maydell tcg_temp_free_i32(aspen); 299*fa856736SPeter Maydell tcg_temp_free_i32(fpca); 300*fa856736SPeter Maydell } 301*fa856736SPeter Maydell 302*fa856736SPeter Maydell static bool gen_M_fp_sysreg_write(DisasContext *s, int regno, 303*fa856736SPeter Maydell fp_sysreg_loadfn *loadfn, 304*fa856736SPeter Maydell void *opaque) 305*fa856736SPeter Maydell { 306*fa856736SPeter Maydell /* Do a write to an M-profile floating point system register */ 307*fa856736SPeter Maydell TCGv_i32 tmp; 308*fa856736SPeter Maydell TCGLabel *lab_end = NULL; 309*fa856736SPeter Maydell 310*fa856736SPeter Maydell switch (fp_sysreg_checks(s, regno)) { 311*fa856736SPeter Maydell case FPSysRegCheckFailed: 312*fa856736SPeter Maydell return false; 313*fa856736SPeter Maydell case FPSysRegCheckDone: 314*fa856736SPeter Maydell return true; 315*fa856736SPeter Maydell case FPSysRegCheckContinue: 316*fa856736SPeter Maydell break; 317*fa856736SPeter Maydell } 318*fa856736SPeter Maydell 319*fa856736SPeter Maydell switch (regno) { 320*fa856736SPeter Maydell case ARM_VFP_FPSCR: 321*fa856736SPeter Maydell tmp = loadfn(s, opaque); 322*fa856736SPeter Maydell gen_helper_vfp_set_fpscr(cpu_env, tmp); 323*fa856736SPeter Maydell tcg_temp_free_i32(tmp); 324*fa856736SPeter Maydell gen_lookup_tb(s); 325*fa856736SPeter Maydell break; 326*fa856736SPeter Maydell case ARM_VFP_FPSCR_NZCVQC: 327*fa856736SPeter Maydell { 328*fa856736SPeter Maydell TCGv_i32 fpscr; 329*fa856736SPeter Maydell tmp = loadfn(s, opaque); 330*fa856736SPeter Maydell if (dc_isar_feature(aa32_mve, s)) { 331*fa856736SPeter Maydell /* QC is only present for MVE; otherwise RES0 */ 332*fa856736SPeter Maydell TCGv_i32 qc = tcg_temp_new_i32(); 333*fa856736SPeter Maydell tcg_gen_andi_i32(qc, tmp, FPCR_QC); 334*fa856736SPeter Maydell /* 335*fa856736SPeter Maydell * The 4 vfp.qc[] fields need only be "zero" vs "non-zero"; 336*fa856736SPeter Maydell * here writing the same value into all elements is simplest. 337*fa856736SPeter Maydell */ 338*fa856736SPeter Maydell tcg_gen_gvec_dup_i32(MO_32, offsetof(CPUARMState, vfp.qc), 339*fa856736SPeter Maydell 16, 16, qc); 340*fa856736SPeter Maydell } 341*fa856736SPeter Maydell tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK); 342*fa856736SPeter Maydell fpscr = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); 343*fa856736SPeter Maydell tcg_gen_andi_i32(fpscr, fpscr, ~FPCR_NZCV_MASK); 344*fa856736SPeter Maydell tcg_gen_or_i32(fpscr, fpscr, tmp); 345*fa856736SPeter Maydell store_cpu_field(fpscr, vfp.xregs[ARM_VFP_FPSCR]); 346*fa856736SPeter Maydell tcg_temp_free_i32(tmp); 347*fa856736SPeter Maydell break; 348*fa856736SPeter Maydell } 349*fa856736SPeter Maydell case ARM_VFP_FPCXT_NS: 350*fa856736SPeter Maydell lab_end = gen_new_label(); 351*fa856736SPeter Maydell /* fpInactive case: write is a NOP, so branch to end */ 352*fa856736SPeter Maydell gen_branch_fpInactive(s, TCG_COND_NE, lab_end); 353*fa856736SPeter Maydell /* 354*fa856736SPeter Maydell * !fpInactive: if FPU disabled, take NOCP exception; 355*fa856736SPeter Maydell * otherwise PreserveFPState(), and then FPCXT_NS writes 356*fa856736SPeter Maydell * behave the same as FPCXT_S writes. 357*fa856736SPeter Maydell */ 358*fa856736SPeter Maydell if (s->fp_excp_el) { 359*fa856736SPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_NOCP, 360*fa856736SPeter Maydell syn_uncategorized(), s->fp_excp_el); 361*fa856736SPeter Maydell /* 362*fa856736SPeter Maydell * This was only a conditional exception, so override 363*fa856736SPeter Maydell * gen_exception_insn()'s default to DISAS_NORETURN 364*fa856736SPeter Maydell */ 365*fa856736SPeter Maydell s->base.is_jmp = DISAS_NEXT; 366*fa856736SPeter Maydell break; 367*fa856736SPeter Maydell } 368*fa856736SPeter Maydell gen_preserve_fp_state(s); 369*fa856736SPeter Maydell /* fall through */ 370*fa856736SPeter Maydell case ARM_VFP_FPCXT_S: 371*fa856736SPeter Maydell { 372*fa856736SPeter Maydell TCGv_i32 sfpa, control; 373*fa856736SPeter Maydell /* 374*fa856736SPeter Maydell * Set FPSCR and CONTROL.SFPA from value; the new FPSCR takes 375*fa856736SPeter Maydell * bits [27:0] from value and zeroes bits [31:28]. 376*fa856736SPeter Maydell */ 377*fa856736SPeter Maydell tmp = loadfn(s, opaque); 378*fa856736SPeter Maydell sfpa = tcg_temp_new_i32(); 379*fa856736SPeter Maydell tcg_gen_shri_i32(sfpa, tmp, 31); 380*fa856736SPeter Maydell control = load_cpu_field(v7m.control[M_REG_S]); 381*fa856736SPeter Maydell tcg_gen_deposit_i32(control, control, sfpa, 382*fa856736SPeter Maydell R_V7M_CONTROL_SFPA_SHIFT, 1); 383*fa856736SPeter Maydell store_cpu_field(control, v7m.control[M_REG_S]); 384*fa856736SPeter Maydell tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK); 385*fa856736SPeter Maydell gen_helper_vfp_set_fpscr(cpu_env, tmp); 386*fa856736SPeter Maydell tcg_temp_free_i32(tmp); 387*fa856736SPeter Maydell tcg_temp_free_i32(sfpa); 388*fa856736SPeter Maydell break; 389*fa856736SPeter Maydell } 390*fa856736SPeter Maydell case ARM_VFP_VPR: 391*fa856736SPeter Maydell /* Behaves as NOP if not privileged */ 392*fa856736SPeter Maydell if (IS_USER(s)) { 393*fa856736SPeter Maydell break; 394*fa856736SPeter Maydell } 395*fa856736SPeter Maydell tmp = loadfn(s, opaque); 396*fa856736SPeter Maydell store_cpu_field(tmp, v7m.vpr); 397*fa856736SPeter Maydell break; 398*fa856736SPeter Maydell case ARM_VFP_P0: 399*fa856736SPeter Maydell { 400*fa856736SPeter Maydell TCGv_i32 vpr; 401*fa856736SPeter Maydell tmp = loadfn(s, opaque); 402*fa856736SPeter Maydell vpr = load_cpu_field(v7m.vpr); 403*fa856736SPeter Maydell tcg_gen_deposit_i32(vpr, vpr, tmp, 404*fa856736SPeter Maydell R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH); 405*fa856736SPeter Maydell store_cpu_field(vpr, v7m.vpr); 406*fa856736SPeter Maydell tcg_temp_free_i32(tmp); 407*fa856736SPeter Maydell break; 408*fa856736SPeter Maydell } 409*fa856736SPeter Maydell default: 410*fa856736SPeter Maydell g_assert_not_reached(); 411*fa856736SPeter Maydell } 412*fa856736SPeter Maydell if (lab_end) { 413*fa856736SPeter Maydell gen_set_label(lab_end); 414*fa856736SPeter Maydell } 415*fa856736SPeter Maydell return true; 416*fa856736SPeter Maydell } 417*fa856736SPeter Maydell 418*fa856736SPeter Maydell static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, 419*fa856736SPeter Maydell fp_sysreg_storefn *storefn, 420*fa856736SPeter Maydell void *opaque) 421*fa856736SPeter Maydell { 422*fa856736SPeter Maydell /* Do a read from an M-profile floating point system register */ 423*fa856736SPeter Maydell TCGv_i32 tmp; 424*fa856736SPeter Maydell TCGLabel *lab_end = NULL; 425*fa856736SPeter Maydell bool lookup_tb = false; 426*fa856736SPeter Maydell 427*fa856736SPeter Maydell switch (fp_sysreg_checks(s, regno)) { 428*fa856736SPeter Maydell case FPSysRegCheckFailed: 429*fa856736SPeter Maydell return false; 430*fa856736SPeter Maydell case FPSysRegCheckDone: 431*fa856736SPeter Maydell return true; 432*fa856736SPeter Maydell case FPSysRegCheckContinue: 433*fa856736SPeter Maydell break; 434*fa856736SPeter Maydell } 435*fa856736SPeter Maydell 436*fa856736SPeter Maydell if (regno == ARM_VFP_FPSCR_NZCVQC && !dc_isar_feature(aa32_mve, s)) { 437*fa856736SPeter Maydell /* QC is RES0 without MVE, so NZCVQC simplifies to NZCV */ 438*fa856736SPeter Maydell regno = QEMU_VFP_FPSCR_NZCV; 439*fa856736SPeter Maydell } 440*fa856736SPeter Maydell 441*fa856736SPeter Maydell switch (regno) { 442*fa856736SPeter Maydell case ARM_VFP_FPSCR: 443*fa856736SPeter Maydell tmp = tcg_temp_new_i32(); 444*fa856736SPeter Maydell gen_helper_vfp_get_fpscr(tmp, cpu_env); 445*fa856736SPeter Maydell storefn(s, opaque, tmp); 446*fa856736SPeter Maydell break; 447*fa856736SPeter Maydell case ARM_VFP_FPSCR_NZCVQC: 448*fa856736SPeter Maydell tmp = tcg_temp_new_i32(); 449*fa856736SPeter Maydell gen_helper_vfp_get_fpscr(tmp, cpu_env); 450*fa856736SPeter Maydell tcg_gen_andi_i32(tmp, tmp, FPCR_NZCVQC_MASK); 451*fa856736SPeter Maydell storefn(s, opaque, tmp); 452*fa856736SPeter Maydell break; 453*fa856736SPeter Maydell case QEMU_VFP_FPSCR_NZCV: 454*fa856736SPeter Maydell /* 455*fa856736SPeter Maydell * Read just NZCV; this is a special case to avoid the 456*fa856736SPeter Maydell * helper call for the "VMRS to CPSR.NZCV" insn. 457*fa856736SPeter Maydell */ 458*fa856736SPeter Maydell tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); 459*fa856736SPeter Maydell tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK); 460*fa856736SPeter Maydell storefn(s, opaque, tmp); 461*fa856736SPeter Maydell break; 462*fa856736SPeter Maydell case ARM_VFP_FPCXT_S: 463*fa856736SPeter Maydell { 464*fa856736SPeter Maydell TCGv_i32 control, sfpa, fpscr; 465*fa856736SPeter Maydell /* Bits [27:0] from FPSCR, bit [31] from CONTROL.SFPA */ 466*fa856736SPeter Maydell tmp = tcg_temp_new_i32(); 467*fa856736SPeter Maydell sfpa = tcg_temp_new_i32(); 468*fa856736SPeter Maydell gen_helper_vfp_get_fpscr(tmp, cpu_env); 469*fa856736SPeter Maydell tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK); 470*fa856736SPeter Maydell control = load_cpu_field(v7m.control[M_REG_S]); 471*fa856736SPeter Maydell tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK); 472*fa856736SPeter Maydell tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT); 473*fa856736SPeter Maydell tcg_gen_or_i32(tmp, tmp, sfpa); 474*fa856736SPeter Maydell tcg_temp_free_i32(sfpa); 475*fa856736SPeter Maydell /* 476*fa856736SPeter Maydell * Store result before updating FPSCR etc, in case 477*fa856736SPeter Maydell * it is a memory write which causes an exception. 478*fa856736SPeter Maydell */ 479*fa856736SPeter Maydell storefn(s, opaque, tmp); 480*fa856736SPeter Maydell /* 481*fa856736SPeter Maydell * Now we must reset FPSCR from FPDSCR_NS, and clear 482*fa856736SPeter Maydell * CONTROL.SFPA; so we'll end the TB here. 483*fa856736SPeter Maydell */ 484*fa856736SPeter Maydell tcg_gen_andi_i32(control, control, ~R_V7M_CONTROL_SFPA_MASK); 485*fa856736SPeter Maydell store_cpu_field(control, v7m.control[M_REG_S]); 486*fa856736SPeter Maydell fpscr = load_cpu_field(v7m.fpdscr[M_REG_NS]); 487*fa856736SPeter Maydell gen_helper_vfp_set_fpscr(cpu_env, fpscr); 488*fa856736SPeter Maydell tcg_temp_free_i32(fpscr); 489*fa856736SPeter Maydell lookup_tb = true; 490*fa856736SPeter Maydell break; 491*fa856736SPeter Maydell } 492*fa856736SPeter Maydell case ARM_VFP_FPCXT_NS: 493*fa856736SPeter Maydell { 494*fa856736SPeter Maydell TCGv_i32 control, sfpa, fpscr, fpdscr, zero; 495*fa856736SPeter Maydell TCGLabel *lab_active = gen_new_label(); 496*fa856736SPeter Maydell 497*fa856736SPeter Maydell lookup_tb = true; 498*fa856736SPeter Maydell 499*fa856736SPeter Maydell gen_branch_fpInactive(s, TCG_COND_EQ, lab_active); 500*fa856736SPeter Maydell /* fpInactive case: reads as FPDSCR_NS */ 501*fa856736SPeter Maydell TCGv_i32 tmp = load_cpu_field(v7m.fpdscr[M_REG_NS]); 502*fa856736SPeter Maydell storefn(s, opaque, tmp); 503*fa856736SPeter Maydell lab_end = gen_new_label(); 504*fa856736SPeter Maydell tcg_gen_br(lab_end); 505*fa856736SPeter Maydell 506*fa856736SPeter Maydell gen_set_label(lab_active); 507*fa856736SPeter Maydell /* 508*fa856736SPeter Maydell * !fpInactive: if FPU disabled, take NOCP exception; 509*fa856736SPeter Maydell * otherwise PreserveFPState(), and then FPCXT_NS 510*fa856736SPeter Maydell * reads the same as FPCXT_S. 511*fa856736SPeter Maydell */ 512*fa856736SPeter Maydell if (s->fp_excp_el) { 513*fa856736SPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_NOCP, 514*fa856736SPeter Maydell syn_uncategorized(), s->fp_excp_el); 515*fa856736SPeter Maydell /* 516*fa856736SPeter Maydell * This was only a conditional exception, so override 517*fa856736SPeter Maydell * gen_exception_insn()'s default to DISAS_NORETURN 518*fa856736SPeter Maydell */ 519*fa856736SPeter Maydell s->base.is_jmp = DISAS_NEXT; 520*fa856736SPeter Maydell break; 521*fa856736SPeter Maydell } 522*fa856736SPeter Maydell gen_preserve_fp_state(s); 523*fa856736SPeter Maydell tmp = tcg_temp_new_i32(); 524*fa856736SPeter Maydell sfpa = tcg_temp_new_i32(); 525*fa856736SPeter Maydell fpscr = tcg_temp_new_i32(); 526*fa856736SPeter Maydell gen_helper_vfp_get_fpscr(fpscr, cpu_env); 527*fa856736SPeter Maydell tcg_gen_andi_i32(tmp, fpscr, ~FPCR_NZCV_MASK); 528*fa856736SPeter Maydell control = load_cpu_field(v7m.control[M_REG_S]); 529*fa856736SPeter Maydell tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK); 530*fa856736SPeter Maydell tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT); 531*fa856736SPeter Maydell tcg_gen_or_i32(tmp, tmp, sfpa); 532*fa856736SPeter Maydell tcg_temp_free_i32(control); 533*fa856736SPeter Maydell /* Store result before updating FPSCR, in case it faults */ 534*fa856736SPeter Maydell storefn(s, opaque, tmp); 535*fa856736SPeter Maydell /* If SFPA is zero then set FPSCR from FPDSCR_NS */ 536*fa856736SPeter Maydell fpdscr = load_cpu_field(v7m.fpdscr[M_REG_NS]); 537*fa856736SPeter Maydell zero = tcg_const_i32(0); 538*fa856736SPeter Maydell tcg_gen_movcond_i32(TCG_COND_EQ, fpscr, sfpa, zero, fpdscr, fpscr); 539*fa856736SPeter Maydell gen_helper_vfp_set_fpscr(cpu_env, fpscr); 540*fa856736SPeter Maydell tcg_temp_free_i32(zero); 541*fa856736SPeter Maydell tcg_temp_free_i32(sfpa); 542*fa856736SPeter Maydell tcg_temp_free_i32(fpdscr); 543*fa856736SPeter Maydell tcg_temp_free_i32(fpscr); 544*fa856736SPeter Maydell break; 545*fa856736SPeter Maydell } 546*fa856736SPeter Maydell case ARM_VFP_VPR: 547*fa856736SPeter Maydell /* Behaves as NOP if not privileged */ 548*fa856736SPeter Maydell if (IS_USER(s)) { 549*fa856736SPeter Maydell break; 550*fa856736SPeter Maydell } 551*fa856736SPeter Maydell tmp = load_cpu_field(v7m.vpr); 552*fa856736SPeter Maydell storefn(s, opaque, tmp); 553*fa856736SPeter Maydell break; 554*fa856736SPeter Maydell case ARM_VFP_P0: 555*fa856736SPeter Maydell tmp = load_cpu_field(v7m.vpr); 556*fa856736SPeter Maydell tcg_gen_extract_i32(tmp, tmp, R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH); 557*fa856736SPeter Maydell storefn(s, opaque, tmp); 558*fa856736SPeter Maydell break; 559*fa856736SPeter Maydell default: 560*fa856736SPeter Maydell g_assert_not_reached(); 561*fa856736SPeter Maydell } 562*fa856736SPeter Maydell 563*fa856736SPeter Maydell if (lab_end) { 564*fa856736SPeter Maydell gen_set_label(lab_end); 565*fa856736SPeter Maydell } 566*fa856736SPeter Maydell if (lookup_tb) { 567*fa856736SPeter Maydell gen_lookup_tb(s); 568*fa856736SPeter Maydell } 569*fa856736SPeter Maydell return true; 570*fa856736SPeter Maydell } 571*fa856736SPeter Maydell 572*fa856736SPeter Maydell static void fp_sysreg_to_gpr(DisasContext *s, void *opaque, TCGv_i32 value) 573*fa856736SPeter Maydell { 574*fa856736SPeter Maydell arg_VMSR_VMRS *a = opaque; 575*fa856736SPeter Maydell 576*fa856736SPeter Maydell if (a->rt == 15) { 577*fa856736SPeter Maydell /* Set the 4 flag bits in the CPSR */ 578*fa856736SPeter Maydell gen_set_nzcv(value); 579*fa856736SPeter Maydell tcg_temp_free_i32(value); 580*fa856736SPeter Maydell } else { 581*fa856736SPeter Maydell store_reg(s, a->rt, value); 582*fa856736SPeter Maydell } 583*fa856736SPeter Maydell } 584*fa856736SPeter Maydell 585*fa856736SPeter Maydell static TCGv_i32 gpr_to_fp_sysreg(DisasContext *s, void *opaque) 586*fa856736SPeter Maydell { 587*fa856736SPeter Maydell arg_VMSR_VMRS *a = opaque; 588*fa856736SPeter Maydell 589*fa856736SPeter Maydell return load_reg(s, a->rt); 590*fa856736SPeter Maydell } 591*fa856736SPeter Maydell 592*fa856736SPeter Maydell static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) 593*fa856736SPeter Maydell { 594*fa856736SPeter Maydell /* 595*fa856736SPeter Maydell * Accesses to R15 are UNPREDICTABLE; we choose to undef. 596*fa856736SPeter Maydell * FPSCR -> r15 is a special case which writes to the PSR flags; 597*fa856736SPeter Maydell * set a->reg to a special value to tell gen_M_fp_sysreg_read() 598*fa856736SPeter Maydell * we only care about the top 4 bits of FPSCR there. 599*fa856736SPeter Maydell */ 600*fa856736SPeter Maydell if (a->rt == 15) { 601*fa856736SPeter Maydell if (a->l && a->reg == ARM_VFP_FPSCR) { 602*fa856736SPeter Maydell a->reg = QEMU_VFP_FPSCR_NZCV; 603*fa856736SPeter Maydell } else { 604*fa856736SPeter Maydell return false; 605*fa856736SPeter Maydell } 606*fa856736SPeter Maydell } 607*fa856736SPeter Maydell 608*fa856736SPeter Maydell if (a->l) { 609*fa856736SPeter Maydell /* VMRS, move FP system register to gp register */ 610*fa856736SPeter Maydell return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_gpr, a); 611*fa856736SPeter Maydell } else { 612*fa856736SPeter Maydell /* VMSR, move gp register to FP system register */ 613*fa856736SPeter Maydell return gen_M_fp_sysreg_write(s, a->reg, gpr_to_fp_sysreg, a); 614*fa856736SPeter Maydell } 615*fa856736SPeter Maydell } 616*fa856736SPeter Maydell 617*fa856736SPeter Maydell static void fp_sysreg_to_memory(DisasContext *s, void *opaque, TCGv_i32 value) 618*fa856736SPeter Maydell { 619*fa856736SPeter Maydell arg_vldr_sysreg *a = opaque; 620*fa856736SPeter Maydell uint32_t offset = a->imm; 621*fa856736SPeter Maydell TCGv_i32 addr; 622*fa856736SPeter Maydell 623*fa856736SPeter Maydell if (!a->a) { 624*fa856736SPeter Maydell offset = -offset; 625*fa856736SPeter Maydell } 626*fa856736SPeter Maydell 627*fa856736SPeter Maydell addr = load_reg(s, a->rn); 628*fa856736SPeter Maydell if (a->p) { 629*fa856736SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 630*fa856736SPeter Maydell } 631*fa856736SPeter Maydell 632*fa856736SPeter Maydell if (s->v8m_stackcheck && a->rn == 13 && a->w) { 633*fa856736SPeter Maydell gen_helper_v8m_stackcheck(cpu_env, addr); 634*fa856736SPeter Maydell } 635*fa856736SPeter Maydell 636*fa856736SPeter Maydell gen_aa32_st_i32(s, value, addr, get_mem_index(s), 637*fa856736SPeter Maydell MO_UL | MO_ALIGN | s->be_data); 638*fa856736SPeter Maydell tcg_temp_free_i32(value); 639*fa856736SPeter Maydell 640*fa856736SPeter Maydell if (a->w) { 641*fa856736SPeter Maydell /* writeback */ 642*fa856736SPeter Maydell if (!a->p) { 643*fa856736SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 644*fa856736SPeter Maydell } 645*fa856736SPeter Maydell store_reg(s, a->rn, addr); 646*fa856736SPeter Maydell } else { 647*fa856736SPeter Maydell tcg_temp_free_i32(addr); 648*fa856736SPeter Maydell } 649*fa856736SPeter Maydell } 650*fa856736SPeter Maydell 651*fa856736SPeter Maydell static TCGv_i32 memory_to_fp_sysreg(DisasContext *s, void *opaque) 652*fa856736SPeter Maydell { 653*fa856736SPeter Maydell arg_vldr_sysreg *a = opaque; 654*fa856736SPeter Maydell uint32_t offset = a->imm; 655*fa856736SPeter Maydell TCGv_i32 addr; 656*fa856736SPeter Maydell TCGv_i32 value = tcg_temp_new_i32(); 657*fa856736SPeter Maydell 658*fa856736SPeter Maydell if (!a->a) { 659*fa856736SPeter Maydell offset = -offset; 660*fa856736SPeter Maydell } 661*fa856736SPeter Maydell 662*fa856736SPeter Maydell addr = load_reg(s, a->rn); 663*fa856736SPeter Maydell if (a->p) { 664*fa856736SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 665*fa856736SPeter Maydell } 666*fa856736SPeter Maydell 667*fa856736SPeter Maydell if (s->v8m_stackcheck && a->rn == 13 && a->w) { 668*fa856736SPeter Maydell gen_helper_v8m_stackcheck(cpu_env, addr); 669*fa856736SPeter Maydell } 670*fa856736SPeter Maydell 671*fa856736SPeter Maydell gen_aa32_ld_i32(s, value, addr, get_mem_index(s), 672*fa856736SPeter Maydell MO_UL | MO_ALIGN | s->be_data); 673*fa856736SPeter Maydell 674*fa856736SPeter Maydell if (a->w) { 675*fa856736SPeter Maydell /* writeback */ 676*fa856736SPeter Maydell if (!a->p) { 677*fa856736SPeter Maydell tcg_gen_addi_i32(addr, addr, offset); 678*fa856736SPeter Maydell } 679*fa856736SPeter Maydell store_reg(s, a->rn, addr); 680*fa856736SPeter Maydell } else { 681*fa856736SPeter Maydell tcg_temp_free_i32(addr); 682*fa856736SPeter Maydell } 683*fa856736SPeter Maydell return value; 684*fa856736SPeter Maydell } 685*fa856736SPeter Maydell 686*fa856736SPeter Maydell static bool trans_VLDR_sysreg(DisasContext *s, arg_vldr_sysreg *a) 687*fa856736SPeter Maydell { 688*fa856736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 689*fa856736SPeter Maydell return false; 690*fa856736SPeter Maydell } 691*fa856736SPeter Maydell if (a->rn == 15) { 692*fa856736SPeter Maydell return false; 693*fa856736SPeter Maydell } 694*fa856736SPeter Maydell return gen_M_fp_sysreg_write(s, a->reg, memory_to_fp_sysreg, a); 695*fa856736SPeter Maydell } 696*fa856736SPeter Maydell 697*fa856736SPeter Maydell static bool trans_VSTR_sysreg(DisasContext *s, arg_vldr_sysreg *a) 698*fa856736SPeter Maydell { 699*fa856736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 700*fa856736SPeter Maydell return false; 701*fa856736SPeter Maydell } 702*fa856736SPeter Maydell if (a->rn == 15) { 703*fa856736SPeter Maydell return false; 704*fa856736SPeter Maydell } 705*fa856736SPeter Maydell return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_memory, a); 706*fa856736SPeter Maydell } 707*fa856736SPeter Maydell 7089a5071abSPeter Maydell static bool trans_NOCP(DisasContext *s, arg_nocp *a) 7099a5071abSPeter Maydell { 7109a5071abSPeter Maydell /* 7119a5071abSPeter Maydell * Handle M-profile early check for disabled coprocessor: 7129a5071abSPeter Maydell * all we need to do here is emit the NOCP exception if 7139a5071abSPeter Maydell * the coprocessor is disabled. Otherwise we return false 7149a5071abSPeter Maydell * and the real VFP/etc decode will handle the insn. 7159a5071abSPeter Maydell */ 7169a5071abSPeter Maydell assert(arm_dc_feature(s, ARM_FEATURE_M)); 7179a5071abSPeter Maydell 7189a5071abSPeter Maydell if (a->cp == 11) { 7199a5071abSPeter Maydell a->cp = 10; 7209a5071abSPeter Maydell } 7219a5071abSPeter Maydell if (arm_dc_feature(s, ARM_FEATURE_V8_1M) && 7229a5071abSPeter Maydell (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) { 7239a5071abSPeter Maydell /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */ 7249a5071abSPeter Maydell a->cp = 10; 7259a5071abSPeter Maydell } 7269a5071abSPeter Maydell 7279a5071abSPeter Maydell if (a->cp != 10) { 7289a5071abSPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_NOCP, 7299a5071abSPeter Maydell syn_uncategorized(), default_exception_el(s)); 7309a5071abSPeter Maydell return true; 7319a5071abSPeter Maydell } 7329a5071abSPeter Maydell 7339a5071abSPeter Maydell if (s->fp_excp_el != 0) { 7349a5071abSPeter Maydell gen_exception_insn(s, s->pc_curr, EXCP_NOCP, 7359a5071abSPeter Maydell syn_uncategorized(), s->fp_excp_el); 7369a5071abSPeter Maydell return true; 7379a5071abSPeter Maydell } 7389a5071abSPeter Maydell 7399a5071abSPeter Maydell return false; 7409a5071abSPeter Maydell } 7419a5071abSPeter Maydell 7429a5071abSPeter Maydell static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a) 7439a5071abSPeter Maydell { 7449a5071abSPeter Maydell /* This range needs a coprocessor check for v8.1M and later only */ 7459a5071abSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 7469a5071abSPeter Maydell return false; 7479a5071abSPeter Maydell } 7489a5071abSPeter Maydell return trans_NOCP(s, a); 7499a5071abSPeter Maydell } 750