1f0984d40SFabiano Rosas /* 2f0984d40SFabiano Rosas * ARM translation: M-profile NOCP special-case instructions 3f0984d40SFabiano Rosas * 4f0984d40SFabiano Rosas * Copyright (c) 2020 Linaro, Ltd. 5f0984d40SFabiano Rosas * 6f0984d40SFabiano Rosas * This library is free software; you can redistribute it and/or 7f0984d40SFabiano Rosas * modify it under the terms of the GNU Lesser General Public 8f0984d40SFabiano Rosas * License as published by the Free Software Foundation; either 9f0984d40SFabiano Rosas * version 2.1 of the License, or (at your option) any later version. 10f0984d40SFabiano Rosas * 11f0984d40SFabiano Rosas * This library is distributed in the hope that it will be useful, 12f0984d40SFabiano Rosas * but WITHOUT ANY WARRANTY; without even the implied warranty of 13f0984d40SFabiano Rosas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14f0984d40SFabiano Rosas * Lesser General Public License for more details. 15f0984d40SFabiano Rosas * 16f0984d40SFabiano Rosas * You should have received a copy of the GNU Lesser General Public 17f0984d40SFabiano Rosas * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18f0984d40SFabiano Rosas */ 19f0984d40SFabiano Rosas 20f0984d40SFabiano Rosas #include "qemu/osdep.h" 21f0984d40SFabiano Rosas #include "translate.h" 22f0984d40SFabiano Rosas #include "translate-a32.h" 23f0984d40SFabiano Rosas 24f0984d40SFabiano Rosas #include "decode-m-nocp.c.inc" 25f0984d40SFabiano Rosas 26f0984d40SFabiano Rosas /* 27f0984d40SFabiano Rosas * Decode VLLDM and VLSTM are nonstandard because: 28f0984d40SFabiano Rosas * * if there is no FPU then these insns must NOP in 29f0984d40SFabiano Rosas * Secure state and UNDEF in Nonsecure state 30f0984d40SFabiano Rosas * * if there is an FPU then these insns do not have 31f0984d40SFabiano Rosas * the usual behaviour that vfp_access_check() provides of 32f0984d40SFabiano Rosas * being controlled by CPACR/NSACR enable bits or the 33f0984d40SFabiano Rosas * lazy-stacking logic. 34f0984d40SFabiano Rosas */ 35f0984d40SFabiano Rosas static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a) 36f0984d40SFabiano Rosas { 37f0984d40SFabiano Rosas TCGv_i32 fptr; 38f0984d40SFabiano Rosas 39f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_M) || 40f0984d40SFabiano Rosas !arm_dc_feature(s, ARM_FEATURE_V8)) { 41f0984d40SFabiano Rosas return false; 42f0984d40SFabiano Rosas } 43f0984d40SFabiano Rosas 44f0984d40SFabiano Rosas if (a->op) { 45f0984d40SFabiano Rosas /* 46f0984d40SFabiano Rosas * T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not 47f0984d40SFabiano Rosas * to take the IMPDEF option to make memory accesses to the stack 48f0984d40SFabiano Rosas * slots that correspond to the D16-D31 registers (discarding 49f0984d40SFabiano Rosas * read data and writing UNKNOWN values), so for us the T2 50f0984d40SFabiano Rosas * encoding behaves identically to the T1 encoding. 51f0984d40SFabiano Rosas */ 52f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 53f0984d40SFabiano Rosas return false; 54f0984d40SFabiano Rosas } 55f0984d40SFabiano Rosas } else { 56f0984d40SFabiano Rosas /* 57f0984d40SFabiano Rosas * T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs. 58f0984d40SFabiano Rosas * This is currently architecturally impossible, but we add the 59f0984d40SFabiano Rosas * check to stay in line with the pseudocode. Note that we must 60f0984d40SFabiano Rosas * emit code for the UNDEF so it takes precedence over the NOCP. 61f0984d40SFabiano Rosas */ 62f0984d40SFabiano Rosas if (dc_isar_feature(aa32_simd_r32, s)) { 63f0984d40SFabiano Rosas unallocated_encoding(s); 64f0984d40SFabiano Rosas return true; 65f0984d40SFabiano Rosas } 66f0984d40SFabiano Rosas } 67f0984d40SFabiano Rosas 68f0984d40SFabiano Rosas /* 69f0984d40SFabiano Rosas * If not secure, UNDEF. We must emit code for this 70f0984d40SFabiano Rosas * rather than returning false so that this takes 71f0984d40SFabiano Rosas * precedence over the m-nocp.decode NOCP fallback. 72f0984d40SFabiano Rosas */ 73f0984d40SFabiano Rosas if (!s->v8m_secure) { 74f0984d40SFabiano Rosas unallocated_encoding(s); 75f0984d40SFabiano Rosas return true; 76f0984d40SFabiano Rosas } 77f0984d40SFabiano Rosas 78f0984d40SFabiano Rosas s->eci_handled = true; 79f0984d40SFabiano Rosas 80f0984d40SFabiano Rosas /* If no fpu, NOP. */ 81f0984d40SFabiano Rosas if (!dc_isar_feature(aa32_vfp, s)) { 82f0984d40SFabiano Rosas clear_eci_state(s); 83f0984d40SFabiano Rosas return true; 84f0984d40SFabiano Rosas } 85f0984d40SFabiano Rosas 86f0984d40SFabiano Rosas fptr = load_reg(s, a->rn); 87f0984d40SFabiano Rosas if (a->l) { 88ad75a51eSRichard Henderson gen_helper_v7m_vlldm(tcg_env, fptr); 89f0984d40SFabiano Rosas } else { 90ad75a51eSRichard Henderson gen_helper_v7m_vlstm(tcg_env, fptr); 91f0984d40SFabiano Rosas } 92f0984d40SFabiano Rosas 93f0984d40SFabiano Rosas clear_eci_state(s); 94f0984d40SFabiano Rosas 95f0984d40SFabiano Rosas /* 96f0984d40SFabiano Rosas * End the TB, because we have updated FP control bits, 97f0984d40SFabiano Rosas * and possibly VPR or LTPSIZE. 98f0984d40SFabiano Rosas */ 99f0984d40SFabiano Rosas s->base.is_jmp = DISAS_UPDATE_EXIT; 100f0984d40SFabiano Rosas return true; 101f0984d40SFabiano Rosas } 102f0984d40SFabiano Rosas 103f0984d40SFabiano Rosas static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a) 104f0984d40SFabiano Rosas { 105f0984d40SFabiano Rosas int btmreg, topreg; 106f0984d40SFabiano Rosas TCGv_i64 zero; 107f0984d40SFabiano Rosas TCGv_i32 aspen, sfpa; 108f0984d40SFabiano Rosas 109f0984d40SFabiano Rosas if (!dc_isar_feature(aa32_m_sec_state, s)) { 110f0984d40SFabiano Rosas /* Before v8.1M, fall through in decode to NOCP check */ 111f0984d40SFabiano Rosas return false; 112f0984d40SFabiano Rosas } 113f0984d40SFabiano Rosas 114f0984d40SFabiano Rosas /* Explicitly UNDEF because this takes precedence over NOCP */ 115f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) { 116f0984d40SFabiano Rosas unallocated_encoding(s); 117f0984d40SFabiano Rosas return true; 118f0984d40SFabiano Rosas } 119f0984d40SFabiano Rosas 120f0984d40SFabiano Rosas s->eci_handled = true; 121f0984d40SFabiano Rosas 122f0984d40SFabiano Rosas if (!dc_isar_feature(aa32_vfp_simd, s)) { 123f0984d40SFabiano Rosas /* NOP if we have neither FP nor MVE */ 124f0984d40SFabiano Rosas clear_eci_state(s); 125f0984d40SFabiano Rosas return true; 126f0984d40SFabiano Rosas } 127f0984d40SFabiano Rosas 128f0984d40SFabiano Rosas /* 129f0984d40SFabiano Rosas * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no 130f0984d40SFabiano Rosas * active floating point context so we must NOP (without doing 131f0984d40SFabiano Rosas * any lazy state preservation or the NOCP check). 132f0984d40SFabiano Rosas */ 133f0984d40SFabiano Rosas aspen = load_cpu_field(v7m.fpccr[M_REG_S]); 134f0984d40SFabiano Rosas sfpa = load_cpu_field(v7m.control[M_REG_S]); 135f0984d40SFabiano Rosas tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); 136f0984d40SFabiano Rosas tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); 137f0984d40SFabiano Rosas tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK); 138f0984d40SFabiano Rosas tcg_gen_or_i32(sfpa, sfpa, aspen); 139f0984d40SFabiano Rosas arm_gen_condlabel(s); 140f0984d40SFabiano Rosas tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel.label); 141f0984d40SFabiano Rosas 142f0984d40SFabiano Rosas if (s->fp_excp_el != 0) { 143f0984d40SFabiano Rosas gen_exception_insn_el(s, 0, EXCP_NOCP, 144f0984d40SFabiano Rosas syn_uncategorized(), s->fp_excp_el); 145f0984d40SFabiano Rosas return true; 146f0984d40SFabiano Rosas } 147f0984d40SFabiano Rosas 148f0984d40SFabiano Rosas topreg = a->vd + a->imm - 1; 149f0984d40SFabiano Rosas btmreg = a->vd; 150f0984d40SFabiano Rosas 151f0984d40SFabiano Rosas /* Convert to Sreg numbers if the insn specified in Dregs */ 152f0984d40SFabiano Rosas if (a->size == 3) { 153f0984d40SFabiano Rosas topreg = topreg * 2 + 1; 154f0984d40SFabiano Rosas btmreg *= 2; 155f0984d40SFabiano Rosas } 156f0984d40SFabiano Rosas 157f0984d40SFabiano Rosas if (topreg > 63 || (topreg > 31 && !(topreg & 1))) { 158f0984d40SFabiano Rosas /* UNPREDICTABLE: we choose to undef */ 159f0984d40SFabiano Rosas unallocated_encoding(s); 160f0984d40SFabiano Rosas return true; 161f0984d40SFabiano Rosas } 162f0984d40SFabiano Rosas 163f0984d40SFabiano Rosas /* Silently ignore requests to clear D16-D31 if they don't exist */ 164f0984d40SFabiano Rosas if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) { 165f0984d40SFabiano Rosas topreg = 31; 166f0984d40SFabiano Rosas } 167f0984d40SFabiano Rosas 168f0984d40SFabiano Rosas if (!vfp_access_check(s)) { 169f0984d40SFabiano Rosas return true; 170f0984d40SFabiano Rosas } 171f0984d40SFabiano Rosas 172f0984d40SFabiano Rosas /* Zero the Sregs from btmreg to topreg inclusive. */ 173f0984d40SFabiano Rosas zero = tcg_constant_i64(0); 174f0984d40SFabiano Rosas if (btmreg & 1) { 175f0984d40SFabiano Rosas write_neon_element64(zero, btmreg >> 1, 1, MO_32); 176f0984d40SFabiano Rosas btmreg++; 177f0984d40SFabiano Rosas } 178f0984d40SFabiano Rosas for (; btmreg + 1 <= topreg; btmreg += 2) { 179f0984d40SFabiano Rosas write_neon_element64(zero, btmreg >> 1, 0, MO_64); 180f0984d40SFabiano Rosas } 181f0984d40SFabiano Rosas if (btmreg == topreg) { 182f0984d40SFabiano Rosas write_neon_element64(zero, btmreg >> 1, 0, MO_32); 183f0984d40SFabiano Rosas btmreg++; 184f0984d40SFabiano Rosas } 185f0984d40SFabiano Rosas assert(btmreg == topreg + 1); 186f0984d40SFabiano Rosas if (dc_isar_feature(aa32_mve, s)) { 187f0984d40SFabiano Rosas store_cpu_field(tcg_constant_i32(0), v7m.vpr); 188f0984d40SFabiano Rosas } 189f0984d40SFabiano Rosas 190f0984d40SFabiano Rosas clear_eci_state(s); 191f0984d40SFabiano Rosas return true; 192f0984d40SFabiano Rosas } 193f0984d40SFabiano Rosas 194f0984d40SFabiano Rosas /* 195f0984d40SFabiano Rosas * M-profile provides two different sets of instructions that can 196f0984d40SFabiano Rosas * access floating point system registers: VMSR/VMRS (which move 197f0984d40SFabiano Rosas * to/from a general purpose register) and VLDR/VSTR sysreg (which 198f0984d40SFabiano Rosas * move directly to/from memory). In some cases there are also side 199f0984d40SFabiano Rosas * effects which must happen after any write to memory (which could 200f0984d40SFabiano Rosas * cause an exception). So we implement the common logic for the 201f0984d40SFabiano Rosas * sysreg access in gen_M_fp_sysreg_write() and gen_M_fp_sysreg_read(), 202f0984d40SFabiano Rosas * which take pointers to callback functions which will perform the 203f0984d40SFabiano Rosas * actual "read/write general purpose register" and "read/write 204f0984d40SFabiano Rosas * memory" operations. 205f0984d40SFabiano Rosas */ 206f0984d40SFabiano Rosas 207f0984d40SFabiano Rosas /* 208f0984d40SFabiano Rosas * Emit code to store the sysreg to its final destination; frees the 209f0984d40SFabiano Rosas * TCG temp 'value' it is passed. do_access is true to do the store, 210f0984d40SFabiano Rosas * and false to skip it and only perform side-effects like base 211f0984d40SFabiano Rosas * register writeback. 212f0984d40SFabiano Rosas */ 213f0984d40SFabiano Rosas typedef void fp_sysreg_storefn(DisasContext *s, void *opaque, TCGv_i32 value, 214f0984d40SFabiano Rosas bool do_access); 215f0984d40SFabiano Rosas /* 216f0984d40SFabiano Rosas * Emit code to load the value to be copied to the sysreg; returns 217f0984d40SFabiano Rosas * a new TCG temporary. do_access is true to do the store, 218f0984d40SFabiano Rosas * and false to skip it and only perform side-effects like base 219f0984d40SFabiano Rosas * register writeback. 220f0984d40SFabiano Rosas */ 221f0984d40SFabiano Rosas typedef TCGv_i32 fp_sysreg_loadfn(DisasContext *s, void *opaque, 222f0984d40SFabiano Rosas bool do_access); 223f0984d40SFabiano Rosas 224f0984d40SFabiano Rosas /* Common decode/access checks for fp sysreg read/write */ 225f0984d40SFabiano Rosas typedef enum FPSysRegCheckResult { 226f0984d40SFabiano Rosas FPSysRegCheckFailed, /* caller should return false */ 227f0984d40SFabiano Rosas FPSysRegCheckDone, /* caller should return true */ 228f0984d40SFabiano Rosas FPSysRegCheckContinue, /* caller should continue generating code */ 229f0984d40SFabiano Rosas } FPSysRegCheckResult; 230f0984d40SFabiano Rosas 231f0984d40SFabiano Rosas static FPSysRegCheckResult fp_sysreg_checks(DisasContext *s, int regno) 232f0984d40SFabiano Rosas { 233f0984d40SFabiano Rosas if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) { 234f0984d40SFabiano Rosas return FPSysRegCheckFailed; 235f0984d40SFabiano Rosas } 236f0984d40SFabiano Rosas 237f0984d40SFabiano Rosas switch (regno) { 238f0984d40SFabiano Rosas case ARM_VFP_FPSCR: 239f0984d40SFabiano Rosas case QEMU_VFP_FPSCR_NZCV: 240f0984d40SFabiano Rosas break; 241f0984d40SFabiano Rosas case ARM_VFP_FPSCR_NZCVQC: 242f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 243f0984d40SFabiano Rosas return FPSysRegCheckFailed; 244f0984d40SFabiano Rosas } 245f0984d40SFabiano Rosas break; 246f0984d40SFabiano Rosas case ARM_VFP_FPCXT_S: 247f0984d40SFabiano Rosas case ARM_VFP_FPCXT_NS: 248f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 249f0984d40SFabiano Rosas return FPSysRegCheckFailed; 250f0984d40SFabiano Rosas } 251f0984d40SFabiano Rosas if (!s->v8m_secure) { 252f0984d40SFabiano Rosas return FPSysRegCheckFailed; 253f0984d40SFabiano Rosas } 254f0984d40SFabiano Rosas break; 255f0984d40SFabiano Rosas case ARM_VFP_VPR: 256f0984d40SFabiano Rosas case ARM_VFP_P0: 257f0984d40SFabiano Rosas if (!dc_isar_feature(aa32_mve, s)) { 258f0984d40SFabiano Rosas return FPSysRegCheckFailed; 259f0984d40SFabiano Rosas } 260f0984d40SFabiano Rosas break; 261f0984d40SFabiano Rosas default: 262f0984d40SFabiano Rosas return FPSysRegCheckFailed; 263f0984d40SFabiano Rosas } 264f0984d40SFabiano Rosas 265f0984d40SFabiano Rosas /* 266f0984d40SFabiano Rosas * FPCXT_NS is a special case: it has specific handling for 267f0984d40SFabiano Rosas * "current FP state is inactive", and must do the PreserveFPState() 268f0984d40SFabiano Rosas * but not the usual full set of actions done by ExecuteFPCheck(). 269f0984d40SFabiano Rosas * So we don't call vfp_access_check() and the callers must handle this. 270f0984d40SFabiano Rosas */ 271f0984d40SFabiano Rosas if (regno != ARM_VFP_FPCXT_NS && !vfp_access_check(s)) { 272f0984d40SFabiano Rosas return FPSysRegCheckDone; 273f0984d40SFabiano Rosas } 274f0984d40SFabiano Rosas return FPSysRegCheckContinue; 275f0984d40SFabiano Rosas } 276f0984d40SFabiano Rosas 277f0984d40SFabiano Rosas static void gen_branch_fpInactive(DisasContext *s, TCGCond cond, 278f0984d40SFabiano Rosas TCGLabel *label) 279f0984d40SFabiano Rosas { 280f0984d40SFabiano Rosas /* 281f0984d40SFabiano Rosas * FPCXT_NS is a special case: it has specific handling for 282f0984d40SFabiano Rosas * "current FP state is inactive", and must do the PreserveFPState() 283f0984d40SFabiano Rosas * but not the usual full set of actions done by ExecuteFPCheck(). 284f0984d40SFabiano Rosas * We don't have a TB flag that matches the fpInactive check, so we 285f0984d40SFabiano Rosas * do it at runtime as we don't expect FPCXT_NS accesses to be frequent. 286f0984d40SFabiano Rosas * 287f0984d40SFabiano Rosas * Emit code that checks fpInactive and does a conditional 288f0984d40SFabiano Rosas * branch to label based on it: 289f0984d40SFabiano Rosas * if cond is TCG_COND_NE then branch if fpInactive != 0 (ie if inactive) 290f0984d40SFabiano Rosas * if cond is TCG_COND_EQ then branch if fpInactive == 0 (ie if active) 291f0984d40SFabiano Rosas */ 292f0984d40SFabiano Rosas assert(cond == TCG_COND_EQ || cond == TCG_COND_NE); 293f0984d40SFabiano Rosas 294f0984d40SFabiano Rosas /* fpInactive = FPCCR_NS.ASPEN == 1 && CONTROL.FPCA == 0 */ 295f0984d40SFabiano Rosas TCGv_i32 aspen, fpca; 296f0984d40SFabiano Rosas aspen = load_cpu_field(v7m.fpccr[M_REG_NS]); 297f0984d40SFabiano Rosas fpca = load_cpu_field(v7m.control[M_REG_S]); 298f0984d40SFabiano Rosas tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); 299f0984d40SFabiano Rosas tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); 300f0984d40SFabiano Rosas tcg_gen_andi_i32(fpca, fpca, R_V7M_CONTROL_FPCA_MASK); 301f0984d40SFabiano Rosas tcg_gen_or_i32(fpca, fpca, aspen); 302f0984d40SFabiano Rosas tcg_gen_brcondi_i32(tcg_invert_cond(cond), fpca, 0, label); 303f0984d40SFabiano Rosas } 304f0984d40SFabiano Rosas 305f0984d40SFabiano Rosas static bool gen_M_fp_sysreg_write(DisasContext *s, int regno, 306f0984d40SFabiano Rosas fp_sysreg_loadfn *loadfn, 307f0984d40SFabiano Rosas void *opaque) 308f0984d40SFabiano Rosas { 309f0984d40SFabiano Rosas /* Do a write to an M-profile floating point system register */ 310f0984d40SFabiano Rosas TCGv_i32 tmp; 311f0984d40SFabiano Rosas TCGLabel *lab_end = NULL; 312f0984d40SFabiano Rosas 313f0984d40SFabiano Rosas switch (fp_sysreg_checks(s, regno)) { 314f0984d40SFabiano Rosas case FPSysRegCheckFailed: 315f0984d40SFabiano Rosas return false; 316f0984d40SFabiano Rosas case FPSysRegCheckDone: 317f0984d40SFabiano Rosas return true; 318f0984d40SFabiano Rosas case FPSysRegCheckContinue: 319f0984d40SFabiano Rosas break; 320f0984d40SFabiano Rosas } 321f0984d40SFabiano Rosas 322f0984d40SFabiano Rosas switch (regno) { 323f0984d40SFabiano Rosas case ARM_VFP_FPSCR: 324f0984d40SFabiano Rosas tmp = loadfn(s, opaque, true); 325ad75a51eSRichard Henderson gen_helper_vfp_set_fpscr(tcg_env, tmp); 326f0984d40SFabiano Rosas gen_lookup_tb(s); 327f0984d40SFabiano Rosas break; 328f0984d40SFabiano Rosas case ARM_VFP_FPSCR_NZCVQC: 329f0984d40SFabiano Rosas { 330f0984d40SFabiano Rosas TCGv_i32 fpscr; 331f0984d40SFabiano Rosas tmp = loadfn(s, opaque, true); 332f0984d40SFabiano Rosas if (dc_isar_feature(aa32_mve, s)) { 333f0984d40SFabiano Rosas /* QC is only present for MVE; otherwise RES0 */ 334f0984d40SFabiano Rosas TCGv_i32 qc = tcg_temp_new_i32(); 335f0984d40SFabiano Rosas tcg_gen_andi_i32(qc, tmp, FPCR_QC); 336f0984d40SFabiano Rosas /* 337f0984d40SFabiano Rosas * The 4 vfp.qc[] fields need only be "zero" vs "non-zero"; 338f0984d40SFabiano Rosas * here writing the same value into all elements is simplest. 339f0984d40SFabiano Rosas */ 340f0984d40SFabiano Rosas tcg_gen_gvec_dup_i32(MO_32, offsetof(CPUARMState, vfp.qc), 341f0984d40SFabiano Rosas 16, 16, qc); 342f0984d40SFabiano Rosas } 343f0984d40SFabiano Rosas tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK); 344*ce07ea61SPeter Maydell fpscr = load_cpu_field_low32(vfp.fpsr); 345f0984d40SFabiano Rosas tcg_gen_andi_i32(fpscr, fpscr, ~FPCR_NZCV_MASK); 346f0984d40SFabiano Rosas tcg_gen_or_i32(fpscr, fpscr, tmp); 347*ce07ea61SPeter Maydell store_cpu_field_low32(fpscr, vfp.fpsr); 348f0984d40SFabiano Rosas break; 349f0984d40SFabiano Rosas } 350f0984d40SFabiano Rosas case ARM_VFP_FPCXT_NS: 351f0984d40SFabiano Rosas { 352f0984d40SFabiano Rosas TCGLabel *lab_active = gen_new_label(); 353f0984d40SFabiano Rosas 354f0984d40SFabiano Rosas lab_end = gen_new_label(); 355f0984d40SFabiano Rosas gen_branch_fpInactive(s, TCG_COND_EQ, lab_active); 356f0984d40SFabiano Rosas /* 357f0984d40SFabiano Rosas * fpInactive case: write is a NOP, so only do side effects 358f0984d40SFabiano Rosas * like register writeback before we branch to end 359f0984d40SFabiano Rosas */ 360f0984d40SFabiano Rosas loadfn(s, opaque, false); 361f0984d40SFabiano Rosas tcg_gen_br(lab_end); 362f0984d40SFabiano Rosas 363f0984d40SFabiano Rosas gen_set_label(lab_active); 364f0984d40SFabiano Rosas /* 365f0984d40SFabiano Rosas * !fpInactive: if FPU disabled, take NOCP exception; 366f0984d40SFabiano Rosas * otherwise PreserveFPState(), and then FPCXT_NS writes 367f0984d40SFabiano Rosas * behave the same as FPCXT_S writes. 368f0984d40SFabiano Rosas */ 369f0984d40SFabiano Rosas if (!vfp_access_check_m(s, true)) { 370f0984d40SFabiano Rosas /* 371f0984d40SFabiano Rosas * This was only a conditional exception, so override 372f0984d40SFabiano Rosas * gen_exception_insn_el()'s default to DISAS_NORETURN 373f0984d40SFabiano Rosas */ 374f0984d40SFabiano Rosas s->base.is_jmp = DISAS_NEXT; 375f0984d40SFabiano Rosas break; 376f0984d40SFabiano Rosas } 377f0984d40SFabiano Rosas } 378f0984d40SFabiano Rosas /* fall through */ 379f0984d40SFabiano Rosas case ARM_VFP_FPCXT_S: 380f0984d40SFabiano Rosas { 381f0984d40SFabiano Rosas TCGv_i32 sfpa, control; 382f0984d40SFabiano Rosas /* 383f0984d40SFabiano Rosas * Set FPSCR and CONTROL.SFPA from value; the new FPSCR takes 384f0984d40SFabiano Rosas * bits [27:0] from value and zeroes bits [31:28]. 385f0984d40SFabiano Rosas */ 386f0984d40SFabiano Rosas tmp = loadfn(s, opaque, true); 387f0984d40SFabiano Rosas sfpa = tcg_temp_new_i32(); 388f0984d40SFabiano Rosas tcg_gen_shri_i32(sfpa, tmp, 31); 389f0984d40SFabiano Rosas control = load_cpu_field(v7m.control[M_REG_S]); 390f0984d40SFabiano Rosas tcg_gen_deposit_i32(control, control, sfpa, 391f0984d40SFabiano Rosas R_V7M_CONTROL_SFPA_SHIFT, 1); 392f0984d40SFabiano Rosas store_cpu_field(control, v7m.control[M_REG_S]); 393f0984d40SFabiano Rosas tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK); 394ad75a51eSRichard Henderson gen_helper_vfp_set_fpscr(tcg_env, tmp); 395f0984d40SFabiano Rosas s->base.is_jmp = DISAS_UPDATE_NOCHAIN; 396f0984d40SFabiano Rosas break; 397f0984d40SFabiano Rosas } 398f0984d40SFabiano Rosas case ARM_VFP_VPR: 399f0984d40SFabiano Rosas /* Behaves as NOP if not privileged */ 400f0984d40SFabiano Rosas if (IS_USER(s)) { 401f0984d40SFabiano Rosas loadfn(s, opaque, false); 402f0984d40SFabiano Rosas break; 403f0984d40SFabiano Rosas } 404f0984d40SFabiano Rosas tmp = loadfn(s, opaque, true); 405f0984d40SFabiano Rosas store_cpu_field(tmp, v7m.vpr); 406f0984d40SFabiano Rosas s->base.is_jmp = DISAS_UPDATE_NOCHAIN; 407f0984d40SFabiano Rosas break; 408f0984d40SFabiano Rosas case ARM_VFP_P0: 409f0984d40SFabiano Rosas { 410f0984d40SFabiano Rosas TCGv_i32 vpr; 411f0984d40SFabiano Rosas tmp = loadfn(s, opaque, true); 412f0984d40SFabiano Rosas vpr = load_cpu_field(v7m.vpr); 413f0984d40SFabiano Rosas tcg_gen_deposit_i32(vpr, vpr, tmp, 414f0984d40SFabiano Rosas R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH); 415f0984d40SFabiano Rosas store_cpu_field(vpr, v7m.vpr); 416f0984d40SFabiano Rosas s->base.is_jmp = DISAS_UPDATE_NOCHAIN; 417f0984d40SFabiano Rosas break; 418f0984d40SFabiano Rosas } 419f0984d40SFabiano Rosas default: 420f0984d40SFabiano Rosas g_assert_not_reached(); 421f0984d40SFabiano Rosas } 422f0984d40SFabiano Rosas if (lab_end) { 423f0984d40SFabiano Rosas gen_set_label(lab_end); 424f0984d40SFabiano Rosas } 425f0984d40SFabiano Rosas return true; 426f0984d40SFabiano Rosas } 427f0984d40SFabiano Rosas 428f0984d40SFabiano Rosas static bool gen_M_fp_sysreg_read(DisasContext *s, int regno, 429f0984d40SFabiano Rosas fp_sysreg_storefn *storefn, 430f0984d40SFabiano Rosas void *opaque) 431f0984d40SFabiano Rosas { 432f0984d40SFabiano Rosas /* Do a read from an M-profile floating point system register */ 433f0984d40SFabiano Rosas TCGv_i32 tmp; 434f0984d40SFabiano Rosas TCGLabel *lab_end = NULL; 435f0984d40SFabiano Rosas bool lookup_tb = false; 436f0984d40SFabiano Rosas 437f0984d40SFabiano Rosas switch (fp_sysreg_checks(s, regno)) { 438f0984d40SFabiano Rosas case FPSysRegCheckFailed: 439f0984d40SFabiano Rosas return false; 440f0984d40SFabiano Rosas case FPSysRegCheckDone: 441f0984d40SFabiano Rosas return true; 442f0984d40SFabiano Rosas case FPSysRegCheckContinue: 443f0984d40SFabiano Rosas break; 444f0984d40SFabiano Rosas } 445f0984d40SFabiano Rosas 446f0984d40SFabiano Rosas if (regno == ARM_VFP_FPSCR_NZCVQC && !dc_isar_feature(aa32_mve, s)) { 447f0984d40SFabiano Rosas /* QC is RES0 without MVE, so NZCVQC simplifies to NZCV */ 448f0984d40SFabiano Rosas regno = QEMU_VFP_FPSCR_NZCV; 449f0984d40SFabiano Rosas } 450f0984d40SFabiano Rosas 451f0984d40SFabiano Rosas switch (regno) { 452f0984d40SFabiano Rosas case ARM_VFP_FPSCR: 453f0984d40SFabiano Rosas tmp = tcg_temp_new_i32(); 454ad75a51eSRichard Henderson gen_helper_vfp_get_fpscr(tmp, tcg_env); 455f0984d40SFabiano Rosas storefn(s, opaque, tmp, true); 456f0984d40SFabiano Rosas break; 457f0984d40SFabiano Rosas case ARM_VFP_FPSCR_NZCVQC: 458f0984d40SFabiano Rosas tmp = tcg_temp_new_i32(); 459ad75a51eSRichard Henderson gen_helper_vfp_get_fpscr(tmp, tcg_env); 460f0984d40SFabiano Rosas tcg_gen_andi_i32(tmp, tmp, FPCR_NZCVQC_MASK); 461f0984d40SFabiano Rosas storefn(s, opaque, tmp, true); 462f0984d40SFabiano Rosas break; 463f0984d40SFabiano Rosas case QEMU_VFP_FPSCR_NZCV: 464f0984d40SFabiano Rosas /* 465f0984d40SFabiano Rosas * Read just NZCV; this is a special case to avoid the 466f0984d40SFabiano Rosas * helper call for the "VMRS to CPSR.NZCV" insn. 467f0984d40SFabiano Rosas */ 468*ce07ea61SPeter Maydell tmp = load_cpu_field_low32(vfp.fpsr); 469f0984d40SFabiano Rosas tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK); 470f0984d40SFabiano Rosas storefn(s, opaque, tmp, true); 471f0984d40SFabiano Rosas break; 472f0984d40SFabiano Rosas case ARM_VFP_FPCXT_S: 473f0984d40SFabiano Rosas { 474f0984d40SFabiano Rosas TCGv_i32 control, sfpa, fpscr; 475f0984d40SFabiano Rosas /* Bits [27:0] from FPSCR, bit [31] from CONTROL.SFPA */ 476f0984d40SFabiano Rosas tmp = tcg_temp_new_i32(); 477f0984d40SFabiano Rosas sfpa = tcg_temp_new_i32(); 478ad75a51eSRichard Henderson gen_helper_vfp_get_fpscr(tmp, tcg_env); 479f0984d40SFabiano Rosas tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK); 480f0984d40SFabiano Rosas control = load_cpu_field(v7m.control[M_REG_S]); 481f0984d40SFabiano Rosas tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK); 482f0984d40SFabiano Rosas tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT); 483f0984d40SFabiano Rosas tcg_gen_or_i32(tmp, tmp, sfpa); 484f0984d40SFabiano Rosas /* 485f0984d40SFabiano Rosas * Store result before updating FPSCR etc, in case 486f0984d40SFabiano Rosas * it is a memory write which causes an exception. 487f0984d40SFabiano Rosas */ 488f0984d40SFabiano Rosas storefn(s, opaque, tmp, true); 489f0984d40SFabiano Rosas /* 490f0984d40SFabiano Rosas * Now we must reset FPSCR from FPDSCR_NS, and clear 491f0984d40SFabiano Rosas * CONTROL.SFPA; so we'll end the TB here. 492f0984d40SFabiano Rosas */ 493f0984d40SFabiano Rosas tcg_gen_andi_i32(control, control, ~R_V7M_CONTROL_SFPA_MASK); 494f0984d40SFabiano Rosas store_cpu_field(control, v7m.control[M_REG_S]); 495f0984d40SFabiano Rosas fpscr = load_cpu_field(v7m.fpdscr[M_REG_NS]); 496ad75a51eSRichard Henderson gen_helper_vfp_set_fpscr(tcg_env, fpscr); 497f0984d40SFabiano Rosas lookup_tb = true; 498f0984d40SFabiano Rosas break; 499f0984d40SFabiano Rosas } 500f0984d40SFabiano Rosas case ARM_VFP_FPCXT_NS: 501f0984d40SFabiano Rosas { 502f0984d40SFabiano Rosas TCGv_i32 control, sfpa, fpscr, fpdscr; 503f0984d40SFabiano Rosas TCGLabel *lab_active = gen_new_label(); 504f0984d40SFabiano Rosas 505f0984d40SFabiano Rosas lookup_tb = true; 506f0984d40SFabiano Rosas 507f0984d40SFabiano Rosas gen_branch_fpInactive(s, TCG_COND_EQ, lab_active); 508f0984d40SFabiano Rosas /* fpInactive case: reads as FPDSCR_NS */ 509d54deb2aSPhilippe Mathieu-Daudé tmp = load_cpu_field(v7m.fpdscr[M_REG_NS]); 510f0984d40SFabiano Rosas storefn(s, opaque, tmp, true); 511f0984d40SFabiano Rosas lab_end = gen_new_label(); 512f0984d40SFabiano Rosas tcg_gen_br(lab_end); 513f0984d40SFabiano Rosas 514f0984d40SFabiano Rosas gen_set_label(lab_active); 515f0984d40SFabiano Rosas /* 516f0984d40SFabiano Rosas * !fpInactive: if FPU disabled, take NOCP exception; 517f0984d40SFabiano Rosas * otherwise PreserveFPState(), and then FPCXT_NS 518f0984d40SFabiano Rosas * reads the same as FPCXT_S. 519f0984d40SFabiano Rosas */ 520f0984d40SFabiano Rosas if (!vfp_access_check_m(s, true)) { 521f0984d40SFabiano Rosas /* 522f0984d40SFabiano Rosas * This was only a conditional exception, so override 523f0984d40SFabiano Rosas * gen_exception_insn_el()'s default to DISAS_NORETURN 524f0984d40SFabiano Rosas */ 525f0984d40SFabiano Rosas s->base.is_jmp = DISAS_NEXT; 526f0984d40SFabiano Rosas break; 527f0984d40SFabiano Rosas } 528f0984d40SFabiano Rosas tmp = tcg_temp_new_i32(); 529f0984d40SFabiano Rosas sfpa = tcg_temp_new_i32(); 530f0984d40SFabiano Rosas fpscr = tcg_temp_new_i32(); 531ad75a51eSRichard Henderson gen_helper_vfp_get_fpscr(fpscr, tcg_env); 532f0984d40SFabiano Rosas tcg_gen_andi_i32(tmp, fpscr, ~FPCR_NZCV_MASK); 533f0984d40SFabiano Rosas control = load_cpu_field(v7m.control[M_REG_S]); 534f0984d40SFabiano Rosas tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK); 535f0984d40SFabiano Rosas tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT); 536f0984d40SFabiano Rosas tcg_gen_or_i32(tmp, tmp, sfpa); 537f0984d40SFabiano Rosas /* Store result before updating FPSCR, in case it faults */ 538f0984d40SFabiano Rosas storefn(s, opaque, tmp, true); 539f0984d40SFabiano Rosas /* If SFPA is zero then set FPSCR from FPDSCR_NS */ 540f0984d40SFabiano Rosas fpdscr = load_cpu_field(v7m.fpdscr[M_REG_NS]); 541f0984d40SFabiano Rosas tcg_gen_movcond_i32(TCG_COND_EQ, fpscr, sfpa, tcg_constant_i32(0), 542f0984d40SFabiano Rosas fpdscr, fpscr); 543ad75a51eSRichard Henderson gen_helper_vfp_set_fpscr(tcg_env, fpscr); 544f0984d40SFabiano Rosas break; 545f0984d40SFabiano Rosas } 546f0984d40SFabiano Rosas case ARM_VFP_VPR: 547f0984d40SFabiano Rosas /* Behaves as NOP if not privileged */ 548f0984d40SFabiano Rosas if (IS_USER(s)) { 549f0984d40SFabiano Rosas storefn(s, opaque, NULL, false); 550f0984d40SFabiano Rosas break; 551f0984d40SFabiano Rosas } 552f0984d40SFabiano Rosas tmp = load_cpu_field(v7m.vpr); 553f0984d40SFabiano Rosas storefn(s, opaque, tmp, true); 554f0984d40SFabiano Rosas break; 555f0984d40SFabiano Rosas case ARM_VFP_P0: 556f0984d40SFabiano Rosas tmp = load_cpu_field(v7m.vpr); 557f0984d40SFabiano Rosas tcg_gen_extract_i32(tmp, tmp, R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH); 558f0984d40SFabiano Rosas storefn(s, opaque, tmp, true); 559f0984d40SFabiano Rosas break; 560f0984d40SFabiano Rosas default: 561f0984d40SFabiano Rosas g_assert_not_reached(); 562f0984d40SFabiano Rosas } 563f0984d40SFabiano Rosas 564f0984d40SFabiano Rosas if (lab_end) { 565f0984d40SFabiano Rosas gen_set_label(lab_end); 566f0984d40SFabiano Rosas } 567f0984d40SFabiano Rosas if (lookup_tb) { 568f0984d40SFabiano Rosas gen_lookup_tb(s); 569f0984d40SFabiano Rosas } 570f0984d40SFabiano Rosas return true; 571f0984d40SFabiano Rosas } 572f0984d40SFabiano Rosas 573f0984d40SFabiano Rosas static void fp_sysreg_to_gpr(DisasContext *s, void *opaque, TCGv_i32 value, 574f0984d40SFabiano Rosas bool do_access) 575f0984d40SFabiano Rosas { 576f0984d40SFabiano Rosas arg_VMSR_VMRS *a = opaque; 577f0984d40SFabiano Rosas 578f0984d40SFabiano Rosas if (!do_access) { 579f0984d40SFabiano Rosas return; 580f0984d40SFabiano Rosas } 581f0984d40SFabiano Rosas 582f0984d40SFabiano Rosas if (a->rt == 15) { 583f0984d40SFabiano Rosas /* Set the 4 flag bits in the CPSR */ 584f0984d40SFabiano Rosas gen_set_nzcv(value); 585f0984d40SFabiano Rosas } else { 586f0984d40SFabiano Rosas store_reg(s, a->rt, value); 587f0984d40SFabiano Rosas } 588f0984d40SFabiano Rosas } 589f0984d40SFabiano Rosas 590f0984d40SFabiano Rosas static TCGv_i32 gpr_to_fp_sysreg(DisasContext *s, void *opaque, bool do_access) 591f0984d40SFabiano Rosas { 592f0984d40SFabiano Rosas arg_VMSR_VMRS *a = opaque; 593f0984d40SFabiano Rosas 594f0984d40SFabiano Rosas if (!do_access) { 595f0984d40SFabiano Rosas return NULL; 596f0984d40SFabiano Rosas } 597f0984d40SFabiano Rosas return load_reg(s, a->rt); 598f0984d40SFabiano Rosas } 599f0984d40SFabiano Rosas 600f0984d40SFabiano Rosas static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) 601f0984d40SFabiano Rosas { 602f0984d40SFabiano Rosas /* 603f0984d40SFabiano Rosas * Accesses to R15 are UNPREDICTABLE; we choose to undef. 604f0984d40SFabiano Rosas * FPSCR -> r15 is a special case which writes to the PSR flags; 605f0984d40SFabiano Rosas * set a->reg to a special value to tell gen_M_fp_sysreg_read() 606f0984d40SFabiano Rosas * we only care about the top 4 bits of FPSCR there. 607f0984d40SFabiano Rosas */ 608f0984d40SFabiano Rosas if (a->rt == 15) { 609f0984d40SFabiano Rosas if (a->l && a->reg == ARM_VFP_FPSCR) { 610f0984d40SFabiano Rosas a->reg = QEMU_VFP_FPSCR_NZCV; 611f0984d40SFabiano Rosas } else { 612f0984d40SFabiano Rosas return false; 613f0984d40SFabiano Rosas } 614f0984d40SFabiano Rosas } 615f0984d40SFabiano Rosas 616f0984d40SFabiano Rosas if (a->l) { 617f0984d40SFabiano Rosas /* VMRS, move FP system register to gp register */ 618f0984d40SFabiano Rosas return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_gpr, a); 619f0984d40SFabiano Rosas } else { 620f0984d40SFabiano Rosas /* VMSR, move gp register to FP system register */ 621f0984d40SFabiano Rosas return gen_M_fp_sysreg_write(s, a->reg, gpr_to_fp_sysreg, a); 622f0984d40SFabiano Rosas } 623f0984d40SFabiano Rosas } 624f0984d40SFabiano Rosas 625f0984d40SFabiano Rosas static void fp_sysreg_to_memory(DisasContext *s, void *opaque, TCGv_i32 value, 626f0984d40SFabiano Rosas bool do_access) 627f0984d40SFabiano Rosas { 628f0984d40SFabiano Rosas arg_vldr_sysreg *a = opaque; 629f0984d40SFabiano Rosas uint32_t offset = a->imm; 630f0984d40SFabiano Rosas TCGv_i32 addr; 631f0984d40SFabiano Rosas 632f0984d40SFabiano Rosas if (!a->a) { 633f0984d40SFabiano Rosas offset = -offset; 634f0984d40SFabiano Rosas } 635f0984d40SFabiano Rosas 636f0984d40SFabiano Rosas if (!do_access && !a->w) { 637f0984d40SFabiano Rosas return; 638f0984d40SFabiano Rosas } 639f0984d40SFabiano Rosas 640f0984d40SFabiano Rosas addr = load_reg(s, a->rn); 641f0984d40SFabiano Rosas if (a->p) { 642f0984d40SFabiano Rosas tcg_gen_addi_i32(addr, addr, offset); 643f0984d40SFabiano Rosas } 644f0984d40SFabiano Rosas 645f0984d40SFabiano Rosas if (s->v8m_stackcheck && a->rn == 13 && a->w) { 646ad75a51eSRichard Henderson gen_helper_v8m_stackcheck(tcg_env, addr); 647f0984d40SFabiano Rosas } 648f0984d40SFabiano Rosas 649f0984d40SFabiano Rosas if (do_access) { 650f0984d40SFabiano Rosas gen_aa32_st_i32(s, value, addr, get_mem_index(s), 651f0984d40SFabiano Rosas MO_UL | MO_ALIGN | s->be_data); 652f0984d40SFabiano Rosas } 653f0984d40SFabiano Rosas 654f0984d40SFabiano Rosas if (a->w) { 655f0984d40SFabiano Rosas /* writeback */ 656f0984d40SFabiano Rosas if (!a->p) { 657f0984d40SFabiano Rosas tcg_gen_addi_i32(addr, addr, offset); 658f0984d40SFabiano Rosas } 659f0984d40SFabiano Rosas store_reg(s, a->rn, addr); 660f0984d40SFabiano Rosas } 661f0984d40SFabiano Rosas } 662f0984d40SFabiano Rosas 663f0984d40SFabiano Rosas static TCGv_i32 memory_to_fp_sysreg(DisasContext *s, void *opaque, 664f0984d40SFabiano Rosas bool do_access) 665f0984d40SFabiano Rosas { 666f0984d40SFabiano Rosas arg_vldr_sysreg *a = opaque; 667f0984d40SFabiano Rosas uint32_t offset = a->imm; 668f0984d40SFabiano Rosas TCGv_i32 addr; 669f0984d40SFabiano Rosas TCGv_i32 value = NULL; 670f0984d40SFabiano Rosas 671f0984d40SFabiano Rosas if (!a->a) { 672f0984d40SFabiano Rosas offset = -offset; 673f0984d40SFabiano Rosas } 674f0984d40SFabiano Rosas 675f0984d40SFabiano Rosas if (!do_access && !a->w) { 676f0984d40SFabiano Rosas return NULL; 677f0984d40SFabiano Rosas } 678f0984d40SFabiano Rosas 679f0984d40SFabiano Rosas addr = load_reg(s, a->rn); 680f0984d40SFabiano Rosas if (a->p) { 681f0984d40SFabiano Rosas tcg_gen_addi_i32(addr, addr, offset); 682f0984d40SFabiano Rosas } 683f0984d40SFabiano Rosas 684f0984d40SFabiano Rosas if (s->v8m_stackcheck && a->rn == 13 && a->w) { 685ad75a51eSRichard Henderson gen_helper_v8m_stackcheck(tcg_env, addr); 686f0984d40SFabiano Rosas } 687f0984d40SFabiano Rosas 688f0984d40SFabiano Rosas if (do_access) { 689f0984d40SFabiano Rosas value = tcg_temp_new_i32(); 690f0984d40SFabiano Rosas gen_aa32_ld_i32(s, value, addr, get_mem_index(s), 691f0984d40SFabiano Rosas MO_UL | MO_ALIGN | s->be_data); 692f0984d40SFabiano Rosas } 693f0984d40SFabiano Rosas 694f0984d40SFabiano Rosas if (a->w) { 695f0984d40SFabiano Rosas /* writeback */ 696f0984d40SFabiano Rosas if (!a->p) { 697f0984d40SFabiano Rosas tcg_gen_addi_i32(addr, addr, offset); 698f0984d40SFabiano Rosas } 699f0984d40SFabiano Rosas store_reg(s, a->rn, addr); 700f0984d40SFabiano Rosas } 701f0984d40SFabiano Rosas return value; 702f0984d40SFabiano Rosas } 703f0984d40SFabiano Rosas 704f0984d40SFabiano Rosas static bool trans_VLDR_sysreg(DisasContext *s, arg_vldr_sysreg *a) 705f0984d40SFabiano Rosas { 706f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 707f0984d40SFabiano Rosas return false; 708f0984d40SFabiano Rosas } 709f0984d40SFabiano Rosas if (a->rn == 15) { 710f0984d40SFabiano Rosas return false; 711f0984d40SFabiano Rosas } 712f0984d40SFabiano Rosas return gen_M_fp_sysreg_write(s, a->reg, memory_to_fp_sysreg, a); 713f0984d40SFabiano Rosas } 714f0984d40SFabiano Rosas 715f0984d40SFabiano Rosas static bool trans_VSTR_sysreg(DisasContext *s, arg_vldr_sysreg *a) 716f0984d40SFabiano Rosas { 717f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 718f0984d40SFabiano Rosas return false; 719f0984d40SFabiano Rosas } 720f0984d40SFabiano Rosas if (a->rn == 15) { 721f0984d40SFabiano Rosas return false; 722f0984d40SFabiano Rosas } 723f0984d40SFabiano Rosas return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_memory, a); 724f0984d40SFabiano Rosas } 725f0984d40SFabiano Rosas 726f0984d40SFabiano Rosas static bool trans_NOCP(DisasContext *s, arg_nocp *a) 727f0984d40SFabiano Rosas { 728f0984d40SFabiano Rosas /* 729f0984d40SFabiano Rosas * Handle M-profile early check for disabled coprocessor: 730f0984d40SFabiano Rosas * all we need to do here is emit the NOCP exception if 731f0984d40SFabiano Rosas * the coprocessor is disabled. Otherwise we return false 732f0984d40SFabiano Rosas * and the real VFP/etc decode will handle the insn. 733f0984d40SFabiano Rosas */ 734f0984d40SFabiano Rosas assert(arm_dc_feature(s, ARM_FEATURE_M)); 735f0984d40SFabiano Rosas 736f0984d40SFabiano Rosas if (a->cp == 11) { 737f0984d40SFabiano Rosas a->cp = 10; 738f0984d40SFabiano Rosas } 739f0984d40SFabiano Rosas if (arm_dc_feature(s, ARM_FEATURE_V8_1M) && 740f0984d40SFabiano Rosas (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) { 741f0984d40SFabiano Rosas /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */ 742f0984d40SFabiano Rosas a->cp = 10; 743f0984d40SFabiano Rosas } 744f0984d40SFabiano Rosas 745f0984d40SFabiano Rosas if (a->cp != 10) { 746f0984d40SFabiano Rosas gen_exception_insn(s, 0, EXCP_NOCP, syn_uncategorized()); 747f0984d40SFabiano Rosas return true; 748f0984d40SFabiano Rosas } 749f0984d40SFabiano Rosas 750f0984d40SFabiano Rosas if (s->fp_excp_el != 0) { 751f0984d40SFabiano Rosas gen_exception_insn_el(s, 0, EXCP_NOCP, 752f0984d40SFabiano Rosas syn_uncategorized(), s->fp_excp_el); 753f0984d40SFabiano Rosas return true; 754f0984d40SFabiano Rosas } 755f0984d40SFabiano Rosas 756f0984d40SFabiano Rosas return false; 757f0984d40SFabiano Rosas } 758f0984d40SFabiano Rosas 759f0984d40SFabiano Rosas static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a) 760f0984d40SFabiano Rosas { 761f0984d40SFabiano Rosas /* This range needs a coprocessor check for v8.1M and later only */ 762f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { 763f0984d40SFabiano Rosas return false; 764f0984d40SFabiano Rosas } 765f0984d40SFabiano Rosas return trans_NOCP(s, a); 766f0984d40SFabiano Rosas } 767