diff --git a/target/arm/cpu.h b/target/arm/cpu.h index c75b0a73ae..4c656bdbb7 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1687,15 +1687,19 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) uint32_t vfp_get_fpscr(CPUARMState *env); void vfp_set_fpscr(CPUARMState *env, uint32_t val); -/* FPCR, Floating Point Control Register - * FPSR, Floating Poiht Status Register +/* + * FPCR, Floating Point Control Register + * FPSR, Floating Point Status Register * - * For A64 the FPSCR is split into two logically distinct registers, - * FPCR and FPSR. However since they still use non-overlapping bits - * we store the underlying state in fpscr and just mask on read/write. + * For A64 floating point control and status bits are stored in + * two logically distinct registers, FPCR and FPSR. We store these + * in QEMU in vfp.fpcr and vfp.fpsr. + * For A32 there was only one register, FPSCR. The bits are arranged + * such that FPSCR bits map to FPCR or FPSR bits in the same bit positions, + * so we can use appropriate masking to handle FPSCR reads and writes. + * Note that the FPCR has some bits which are not visible in the + * AArch32 view (for FEAT_AFP). Writing the FPSCR leaves these unchanged. */ -#define FPSR_MASK 0xf800009f -#define FPCR_MASK 0x07ff9f00 /* FPCR bits */ #define FPCR_IOE (1 << 8) /* Invalid Operation exception trap enable */ @@ -1704,7 +1708,9 @@ void vfp_set_fpscr(CPUARMState *env, uint32_t val); #define FPCR_UFE (1 << 11) /* Underflow exception trap enable */ #define FPCR_IXE (1 << 12) /* Inexact exception trap enable */ #define FPCR_IDE (1 << 15) /* Input Denormal exception trap enable */ +#define FPCR_LEN_MASK (7 << 16) /* LEN, A-profile only */ #define FPCR_FZ16 (1 << 19) /* ARMv8.2+, FP16 flush-to-zero */ +#define FPCR_STRIDE_MASK (3 << 20) /* Stride */ #define FPCR_RMODE_MASK (3 << 22) /* Rounding mode */ #define FPCR_FZ (1 << 24) /* Flush-to-zero enable bit */ #define FPCR_DN (1 << 25) /* Default NaN enable bit */ @@ -1714,16 +1720,37 @@ void vfp_set_fpscr(CPUARMState *env, uint32_t val); #define FPCR_LTPSIZE_MASK (7 << FPCR_LTPSIZE_SHIFT) #define FPCR_LTPSIZE_LENGTH 3 +/* Cumulative exception trap enable bits */ +#define FPCR_EEXC_MASK (FPCR_IOE | FPCR_DZE | FPCR_OFE | FPCR_UFE | FPCR_IXE | FPCR_IDE) + /* FPSR bits */ +#define FPSR_IOC (1 << 0) /* Invalid Operation cumulative exception */ +#define FPSR_DZC (1 << 1) /* Divide by Zero cumulative exception */ +#define FPSR_OFC (1 << 2) /* Overflow cumulative exception */ +#define FPSR_UFC (1 << 3) /* Underflow cumulative exception */ +#define FPSR_IXC (1 << 4) /* Inexact cumulative exception */ +#define FPSR_IDC (1 << 7) /* Input Denormal cumulative exception */ #define FPSR_QC (1 << 27) /* Cumulative saturation bit */ #define FPSR_V (1 << 28) /* FP overflow flag */ #define FPSR_C (1 << 29) /* FP carry flag */ #define FPSR_Z (1 << 30) /* FP zero flag */ #define FPSR_N (1 << 31) /* FP negative flag */ +/* Cumulative exception status bits */ +#define FPSR_CEXC_MASK (FPSR_IOC | FPSR_DZC | FPSR_OFC | FPSR_UFC | FPSR_IXC | FPSR_IDC) + #define FPSR_NZCV_MASK (FPSR_N | FPSR_Z | FPSR_C | FPSR_V) #define FPSR_NZCVQC_MASK (FPSR_NZCV_MASK | FPSR_QC) +/* A32 FPSCR bits which architecturally map to FPSR bits */ +#define FPSCR_FPSR_MASK (FPSR_NZCVQC_MASK | FPSR_CEXC_MASK) +/* A32 FPSCR bits which architecturally map to FPCR bits */ +#define FPSCR_FPCR_MASK (FPCR_EEXC_MASK | FPCR_LEN_MASK | FPCR_FZ16 | \ + FPCR_STRIDE_MASK | FPCR_RMODE_MASK | \ + FPCR_FZ | FPCR_DN | FPCR_AHP) +/* These masks don't overlap: each bit lives in only one place */ +QEMU_BUILD_BUG_ON(FPSCR_FPSR_MASK & FPSCR_FPCR_MASK); + /** * vfp_get_fpsr: read the AArch64 FPSR * @env: CPU context diff --git a/target/arm/machine.c b/target/arm/machine.c index 8c820955d9..a3c1e05e65 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -43,7 +43,8 @@ static bool vfp_fpcr_fpsr_needed(void *opaque) ARMCPU *cpu = opaque; CPUARMState *env = &cpu->env; - return (vfp_get_fpcr(env) & ~FPCR_MASK) || (vfp_get_fpsr(env) & ~FPSR_MASK); + return (vfp_get_fpcr(env) & ~FPSCR_FPCR_MASK) || + (vfp_get_fpsr(env) & ~FPSCR_FPSR_MASK); } static int get_fpscr(QEMUFile *f, void *opaque, size_t size, diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 85e50ede37..cbe69ae3fe 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -202,7 +202,8 @@ uint32_t vfp_get_fpsr(CPUARMState *env) uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env) { - return (vfp_get_fpcr(env) & FPCR_MASK) | (vfp_get_fpsr(env) & FPSR_MASK); + return (vfp_get_fpcr(env) & FPSCR_FPCR_MASK) | + (vfp_get_fpsr(env) & FPSCR_FPSR_MASK); } uint32_t vfp_get_fpscr(CPUARMState *env) @@ -280,8 +281,8 @@ void vfp_set_fpcr(CPUARMState *env, uint32_t val) void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val) { - vfp_set_fpcr(env, val & FPCR_MASK); - vfp_set_fpsr(env, val & FPSR_MASK); + vfp_set_fpcr(env, val & FPSCR_FPCR_MASK); + vfp_set_fpsr(env, val & FPSCR_FPSR_MASK); } void vfp_set_fpscr(CPUARMState *env, uint32_t val)