diff --git a/qemu/target/arm/cpu.h b/qemu/target/arm/cpu.h index 1fda9e24..6618bccc 100644 --- a/qemu/target/arm/cpu.h +++ b/qemu/target/arm/cpu.h @@ -568,11 +568,13 @@ typedef struct CPUARMState { ARMPredicateReg preg_tmp; #endif - uint32_t xregs[16]; /* We store these fpcsr fields separately for convenience. */ + uint32_t QEMU_ALIGNED(16, qc[4]); int vec_len; int vec_stride; + uint32_t xregs[16]; + /* Scratch space for aa32 neon expansion. */ uint32_t scratch[8]; @@ -1369,6 +1371,7 @@ void vfp_set_fpscr(CPUARMState *env, uint32_t val); #define FPCR_FZ16 (1 << 19) /* ARMv8.2+, FP16 flush-to-zero */ #define FPCR_FZ (1 << 24) /* Flush-to-zero enable bit */ #define FPCR_DN (1 << 25) /* Default NaN enable bit */ +#define FPCR_QC (1 << 27) /* Cumulative saturation bit */ static inline uint32_t vfp_get_fpsr(CPUARMState *env) { diff --git a/qemu/target/arm/helper.c b/qemu/target/arm/helper.c index 7a38131c..a2a52b70 100644 --- a/qemu/target/arm/helper.c +++ b/qemu/target/arm/helper.c @@ -11779,8 +11779,7 @@ static inline int vfp_exceptbits_from_host(int host_bits) uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env) { - int i; - uint32_t fpscr; + uint32_t i, fpscr; fpscr = env->vfp.xregs[ARM_VFP_FPSCR] | (env->vfp.vec_len << 16) @@ -11792,6 +11791,10 @@ uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env) i |= (get_float_exception_flags(&env->vfp.fp_status_f16) & ~float_flag_input_denormal); fpscr |= vfp_exceptbits_from_host(i); + + i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3]; + fpscr |= i ? FPCR_QC : 0; + return fpscr; } @@ -11838,10 +11841,19 @@ void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val) * (which are stored in fp_status), and the other RES0 bits * in between, then we clear all of the low 16 bits. */ - env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xffc80000; + env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000; env->vfp.vec_len = (val >> 16) & 7; env->vfp.vec_stride = (val >> 20) & 3; + /* + * The bit we set within fpscr_q is arbitrary; the register as a + * whole being zero/non-zero is what counts. + */ + env->vfp.qc[0] = val & FPCR_QC; + env->vfp.qc[1] = 0; + env->vfp.qc[2] = 0; + env->vfp.qc[3] = 0; + changed ^= val; if (changed & (3 << 22)) { i = (val >> 22) & 3; diff --git a/qemu/target/arm/neon_helper.c b/qemu/target/arm/neon_helper.c index 88ab2bc6..d0ded9ee 100644 --- a/qemu/target/arm/neon_helper.c +++ b/qemu/target/arm/neon_helper.c @@ -16,7 +16,7 @@ #define SIGNBIT (uint32_t)0x80000000 #define SIGNBIT64 ((uint64_t)1 << 63) -#define SET_QC() env->vfp.xregs[ARM_VFP_FPSCR] |= CPSR_Q +#define SET_QC() env->vfp.qc[0] = 1 #define NEON_TYPE1(name, type) \ typedef struct \ diff --git a/qemu/target/arm/vec_helper.c b/qemu/target/arm/vec_helper.c index dcf3feb4..930d7151 100644 --- a/qemu/target/arm/vec_helper.c +++ b/qemu/target/arm/vec_helper.c @@ -37,7 +37,7 @@ #define H4(x) (x) #endif -#define SET_QC() env->vfp.xregs[ARM_VFP_FPSCR] |= CPSR_Q +#define SET_QC() env->vfp.qc[0] = 1 static void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz) {