1 /* 2 * ARM VFP floating-point: handling of FPSCR/FPCR/FPSR 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "qemu/osdep.h" 21 #include "cpu.h" 22 #include "internals.h" 23 #include "cpu-features.h" 24 25 uint32_t vfp_get_fpcr(CPUARMState *env) 26 { 27 uint32_t fpcr = env->vfp.fpcr 28 | (env->vfp.vec_len << 16) 29 | (env->vfp.vec_stride << 20); 30 31 /* 32 * M-profile LTPSIZE is the same bits [18:16] as A-profile Len; whichever 33 * of the two is not applicable to this CPU will always be zero. 34 */ 35 fpcr |= env->v7m.ltpsize << 16; 36 37 return fpcr; 38 } 39 40 uint32_t vfp_get_fpsr(CPUARMState *env) 41 { 42 uint32_t fpsr = env->vfp.fpsr; 43 uint32_t i; 44 45 fpsr |= vfp_get_fpsr_from_host(env); 46 47 i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3]; 48 fpsr |= i ? FPSR_QC : 0; 49 return fpsr; 50 } 51 52 uint32_t vfp_get_fpscr(CPUARMState *env) 53 { 54 return (vfp_get_fpcr(env) & FPSCR_FPCR_MASK) | 55 (vfp_get_fpsr(env) & FPSCR_FPSR_MASK); 56 } 57 58 void vfp_set_fpsr(CPUARMState *env, uint32_t val) 59 { 60 ARMCPU *cpu = env_archcpu(env); 61 62 if (arm_feature(env, ARM_FEATURE_NEON) || 63 cpu_isar_feature(aa32_mve, cpu)) { 64 /* 65 * The bit we set within vfp.qc[] is arbitrary; the array as a 66 * whole being zero/non-zero is what counts. 67 */ 68 env->vfp.qc[0] = val & FPSR_QC; 69 env->vfp.qc[1] = 0; 70 env->vfp.qc[2] = 0; 71 env->vfp.qc[3] = 0; 72 } 73 74 /* 75 * NZCV lives only in env->vfp.fpsr. The cumulative exception flags 76 * IOC|DZC|OFC|UFC|IXC|IDC also live in env->vfp.fpsr, with possible 77 * extra pending exception information that hasn't yet been folded in 78 * living in the float_status values (for TCG). 79 * Since this FPSR write gives us the up to date values of the exception 80 * flags, we want to store into vfp.fpsr the NZCV and CEXC bits, zeroing 81 * anything else. We also need to clear out the float_status exception 82 * information so that the next vfp_get_fpsr does not fold in stale data. 83 */ 84 val &= FPSR_NZCV_MASK | FPSR_CEXC_MASK; 85 env->vfp.fpsr = val; 86 vfp_clear_float_status_exc_flags(env); 87 } 88 89 static void vfp_set_fpcr_masked(CPUARMState *env, uint32_t val, uint32_t mask) 90 { 91 /* 92 * We only set FPCR bits defined by mask, and leave the others alone. 93 * We assume the mask is sensible (e.g. doesn't try to set only 94 * part of a field) 95 */ 96 ARMCPU *cpu = env_archcpu(env); 97 98 /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */ 99 if (!cpu_isar_feature(any_fp16, cpu)) { 100 val &= ~FPCR_FZ16; 101 } 102 if (!cpu_isar_feature(aa64_afp, cpu)) { 103 val &= ~(FPCR_FIZ | FPCR_AH | FPCR_NEP); 104 } 105 106 if (!cpu_isar_feature(aa64_ebf16, cpu)) { 107 val &= ~FPCR_EBF; 108 } 109 110 vfp_set_fpcr_to_host(env, val, mask); 111 112 if (mask & (FPCR_LEN_MASK | FPCR_STRIDE_MASK)) { 113 if (!arm_feature(env, ARM_FEATURE_M)) { 114 /* 115 * Short-vector length and stride; on M-profile these bits 116 * are used for different purposes. 117 * We can't make this conditional be "if MVFR0.FPShVec != 0", 118 * because in v7A no-short-vector-support cores still had to 119 * allow Stride/Len to be written with the only effect that 120 * some insns are required to UNDEF if the guest sets them. 121 */ 122 env->vfp.vec_len = extract32(val, 16, 3); 123 env->vfp.vec_stride = extract32(val, 20, 2); 124 } else if (cpu_isar_feature(aa32_mve, cpu)) { 125 env->v7m.ltpsize = extract32(val, FPCR_LTPSIZE_SHIFT, 126 FPCR_LTPSIZE_LENGTH); 127 } 128 } 129 130 /* 131 * We don't implement trapped exception handling, so the 132 * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!) 133 * 134 * The FPCR bits we keep in vfp.fpcr are AHP, DN, FZ, RMode, EBF, FZ16, 135 * FIZ, AH, and NEP. 136 * Len, Stride and LTPSIZE we just handled. Store those bits 137 * there, and zero any of the other FPCR bits and the RES0 and RAZ/WI 138 * bits. 139 */ 140 val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16 | 141 FPCR_EBF | FPCR_FIZ | FPCR_AH | FPCR_NEP; 142 env->vfp.fpcr &= ~mask; 143 env->vfp.fpcr |= val; 144 } 145 146 void vfp_set_fpcr(CPUARMState *env, uint32_t val) 147 { 148 vfp_set_fpcr_masked(env, val, MAKE_64BIT_MASK(0, 32)); 149 } 150 151 void vfp_set_fpscr(CPUARMState *env, uint32_t val) 152 { 153 vfp_set_fpcr_masked(env, val, FPSCR_FPCR_MASK); 154 vfp_set_fpsr(env, val & FPSCR_FPSR_MASK); 155 } 156