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