From cf5503b384c1901637e97d67de604e4f26dcab71 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jul 2024 14:18:07 +0100 Subject: [PATCH] target/arm: Allow FPCR bits that aren't in FPSCR In order to allow FPCR bits that aren't in the FPSCR (like the new bits that are defined for FEAT_AFP), we need to make sure that writes to the FPSCR only write to the bits of FPCR that are architecturally mapped, and not the others. Implement this with a new function vfp_set_fpcr_masked() which takes a mask of which bits to update. (We could do the same for FPSR, but we leave that until we actually are likely to need it.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20240628142347.1283015-10-peter.maydell@linaro.org Message-Id: <20240711131822.3909903-10-peter.maydell@linaro.org> --- target/arm/vfp_helper.c | 56 +++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index cbe69ae3fe3..b3698da8ca7 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -113,11 +113,12 @@ static void vfp_set_fpsr_to_host(CPUARMState *env, uint32_t val) set_float_exception_flags(0, &env->vfp.standard_fp_status_f16); } -static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val) +static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask) { uint64_t changed = env->vfp.fpcr; changed ^= val; + changed &= mask; if (changed & (3 << 22)) { int i = (val >> 22) & 3; switch (i) { @@ -167,7 +168,7 @@ static void vfp_set_fpsr_to_host(CPUARMState *env, uint32_t val) { } -static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val) +static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask) { } @@ -239,8 +240,13 @@ void vfp_set_fpsr(CPUARMState *env, uint32_t val) env->vfp.fpsr = val; } -void vfp_set_fpcr(CPUARMState *env, uint32_t val) +static void vfp_set_fpcr_masked(CPUARMState *env, uint32_t val, uint32_t mask) { + /* + * We only set FPCR bits defined by mask, and leave the others alone. + * We assume the mask is sensible (e.g. doesn't try to set only + * part of a field) + */ ARMCPU *cpu = env_archcpu(env); /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */ @@ -248,22 +254,24 @@ void vfp_set_fpcr(CPUARMState *env, uint32_t val) val &= ~FPCR_FZ16; } - vfp_set_fpcr_to_host(env, val); - - if (!arm_feature(env, ARM_FEATURE_M)) { - /* - * Short-vector length and stride; on M-profile these bits - * are used for different purposes. - * We can't make this conditional be "if MVFR0.FPShVec != 0", - * because in v7A no-short-vector-support cores still had to - * allow Stride/Len to be written with the only effect that - * some insns are required to UNDEF if the guest sets them. - */ - env->vfp.vec_len = extract32(val, 16, 3); - env->vfp.vec_stride = extract32(val, 20, 2); - } else if (cpu_isar_feature(aa32_mve, cpu)) { - env->v7m.ltpsize = extract32(val, FPCR_LTPSIZE_SHIFT, - FPCR_LTPSIZE_LENGTH); + vfp_set_fpcr_to_host(env, val, mask); + + if (mask & (FPCR_LEN_MASK | FPCR_STRIDE_MASK)) { + if (!arm_feature(env, ARM_FEATURE_M)) { + /* + * Short-vector length and stride; on M-profile these bits + * are used for different purposes. + * We can't make this conditional be "if MVFR0.FPShVec != 0", + * because in v7A no-short-vector-support cores still had to + * allow Stride/Len to be written with the only effect that + * some insns are required to UNDEF if the guest sets them. + */ + env->vfp.vec_len = extract32(val, 16, 3); + env->vfp.vec_stride = extract32(val, 20, 2); + } else if (cpu_isar_feature(aa32_mve, cpu)) { + env->v7m.ltpsize = extract32(val, FPCR_LTPSIZE_SHIFT, + FPCR_LTPSIZE_LENGTH); + } } /* @@ -276,12 +284,18 @@ void vfp_set_fpcr(CPUARMState *env, uint32_t val) * bits. */ val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16; - env->vfp.fpcr = val; + env->vfp.fpcr &= ~mask; + env->vfp.fpcr |= val; +} + +void vfp_set_fpcr(CPUARMState *env, uint32_t val) +{ + vfp_set_fpcr_masked(env, val, MAKE_64BIT_MASK(0, 32)); } void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val) { - vfp_set_fpcr(env, val & FPSCR_FPCR_MASK); + vfp_set_fpcr_masked(env, val, FPSCR_FPCR_MASK); vfp_set_fpsr(env, val & FPSCR_FPSR_MASK); }