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