|
@@ -85,7 +85,7 @@ static inline int vfp_exceptbits_to_host(int target_bits)
|
|
return host_bits;
|
|
return host_bits;
|
|
}
|
|
}
|
|
|
|
|
|
-static uint32_t vfp_get_fpscr_from_host(CPUARMState *env)
|
|
|
|
|
|
+static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
|
|
{
|
|
{
|
|
uint32_t i;
|
|
uint32_t i;
|
|
|
|
|
|
@@ -99,14 +99,28 @@ static uint32_t vfp_get_fpscr_from_host(CPUARMState *env)
|
|
return vfp_exceptbits_from_host(i);
|
|
return vfp_exceptbits_from_host(i);
|
|
}
|
|
}
|
|
|
|
|
|
-static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val)
|
|
|
|
|
|
+static void vfp_set_fpsr_to_host(CPUARMState *env, uint32_t val)
|
|
{
|
|
{
|
|
- int i;
|
|
|
|
- uint32_t changed = env->vfp.xregs[ARM_VFP_FPSCR];
|
|
|
|
|
|
+ /*
|
|
|
|
+ * The exception flags are ORed together when we read fpscr so we
|
|
|
|
+ * only need to preserve the current state in one of our
|
|
|
|
+ * float_status values.
|
|
|
|
+ */
|
|
|
|
+ int i = vfp_exceptbits_to_host(val);
|
|
|
|
+ set_float_exception_flags(i, &env->vfp.fp_status);
|
|
|
|
+ set_float_exception_flags(0, &env->vfp.fp_status_f16);
|
|
|
|
+ set_float_exception_flags(0, &env->vfp.standard_fp_status);
|
|
|
|
+ set_float_exception_flags(0, &env->vfp.standard_fp_status_f16);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
|
|
|
|
+{
|
|
|
|
+ uint64_t changed = env->vfp.fpcr;
|
|
|
|
|
|
changed ^= val;
|
|
changed ^= val;
|
|
|
|
+ changed &= mask;
|
|
if (changed & (3 << 22)) {
|
|
if (changed & (3 << 22)) {
|
|
- i = (val >> 22) & 3;
|
|
|
|
|
|
+ int i = (val >> 22) & 3;
|
|
switch (i) {
|
|
switch (i) {
|
|
case FPROUNDING_TIEEVEN:
|
|
case FPROUNDING_TIEEVEN:
|
|
i = float_round_nearest_even;
|
|
i = float_round_nearest_even;
|
|
@@ -141,52 +155,56 @@ static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val)
|
|
set_default_nan_mode(dnan_enabled, &env->vfp.fp_status);
|
|
set_default_nan_mode(dnan_enabled, &env->vfp.fp_status);
|
|
set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16);
|
|
set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16);
|
|
}
|
|
}
|
|
-
|
|
|
|
- /*
|
|
|
|
- * The exception flags are ORed together when we read fpscr so we
|
|
|
|
- * only need to preserve the current state in one of our
|
|
|
|
- * float_status values.
|
|
|
|
- */
|
|
|
|
- i = vfp_exceptbits_to_host(val);
|
|
|
|
- set_float_exception_flags(i, &env->vfp.fp_status);
|
|
|
|
- set_float_exception_flags(0, &env->vfp.fp_status_f16);
|
|
|
|
- set_float_exception_flags(0, &env->vfp.standard_fp_status);
|
|
|
|
- set_float_exception_flags(0, &env->vfp.standard_fp_status_f16);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#else
|
|
#else
|
|
|
|
|
|
-static uint32_t vfp_get_fpscr_from_host(CPUARMState *env)
|
|
|
|
|
|
+static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
|
|
{
|
|
{
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val)
|
|
|
|
|
|
+static void vfp_set_fpsr_to_host(CPUARMState *env, uint32_t val)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
|
|
{
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
|
|
|
|
|
|
+uint32_t vfp_get_fpcr(CPUARMState *env)
|
|
{
|
|
{
|
|
- uint32_t i, fpscr;
|
|
|
|
-
|
|
|
|
- fpscr = env->vfp.xregs[ARM_VFP_FPSCR]
|
|
|
|
- | (env->vfp.vec_len << 16)
|
|
|
|
- | (env->vfp.vec_stride << 20);
|
|
|
|
|
|
+ uint32_t fpcr = env->vfp.fpcr
|
|
|
|
+ | (env->vfp.vec_len << 16)
|
|
|
|
+ | (env->vfp.vec_stride << 20);
|
|
|
|
|
|
/*
|
|
/*
|
|
- * M-profile LTPSIZE overlaps A-profile Stride; whichever of the
|
|
|
|
- * two is not applicable to this CPU will always be zero.
|
|
|
|
|
|
+ * M-profile LTPSIZE is the same bits [18:16] as A-profile Len; whichever
|
|
|
|
+ * of the two is not applicable to this CPU will always be zero.
|
|
*/
|
|
*/
|
|
- fpscr |= env->v7m.ltpsize << 16;
|
|
|
|
|
|
+ fpcr |= env->v7m.ltpsize << 16;
|
|
|
|
|
|
- fpscr |= vfp_get_fpscr_from_host(env);
|
|
|
|
|
|
+ return fpcr;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+uint32_t vfp_get_fpsr(CPUARMState *env)
|
|
|
|
+{
|
|
|
|
+ uint32_t fpsr = env->vfp.fpsr;
|
|
|
|
+ uint32_t i;
|
|
|
|
+
|
|
|
|
+ fpsr |= vfp_get_fpsr_from_host(env);
|
|
|
|
|
|
i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
|
|
i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
|
|
- fpscr |= i ? FPCR_QC : 0;
|
|
|
|
|
|
+ fpsr |= i ? FPSR_QC : 0;
|
|
|
|
+ return fpsr;
|
|
|
|
+}
|
|
|
|
|
|
- return fpscr;
|
|
|
|
|
|
+uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
|
|
|
|
+{
|
|
|
|
+ return (vfp_get_fpcr(env) & FPSCR_FPCR_MASK) |
|
|
|
|
+ (vfp_get_fpsr(env) & FPSCR_FPSR_MASK);
|
|
}
|
|
}
|
|
|
|
|
|
uint32_t vfp_get_fpscr(CPUARMState *env)
|
|
uint32_t vfp_get_fpscr(CPUARMState *env)
|
|
@@ -194,56 +212,91 @@ uint32_t vfp_get_fpscr(CPUARMState *env)
|
|
return HELPER(vfp_get_fpscr)(env);
|
|
return HELPER(vfp_get_fpscr)(env);
|
|
}
|
|
}
|
|
|
|
|
|
-void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
|
|
|
|
|
|
+void vfp_set_fpsr(CPUARMState *env, uint32_t val)
|
|
{
|
|
{
|
|
ARMCPU *cpu = env_archcpu(env);
|
|
ARMCPU *cpu = env_archcpu(env);
|
|
|
|
|
|
- /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
|
|
|
|
- if (!cpu_isar_feature(any_fp16, cpu)) {
|
|
|
|
- val &= ~FPCR_FZ16;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- vfp_set_fpscr_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_fpsr_to_host(env, val);
|
|
|
|
|
|
if (arm_feature(env, ARM_FEATURE_NEON) ||
|
|
if (arm_feature(env, ARM_FEATURE_NEON) ||
|
|
cpu_isar_feature(aa32_mve, cpu)) {
|
|
cpu_isar_feature(aa32_mve, cpu)) {
|
|
/*
|
|
/*
|
|
- * The bit we set within fpscr_q is arbitrary; the register as a
|
|
|
|
|
|
+ * The bit we set within vfp.qc[] is arbitrary; the array as a
|
|
* whole being zero/non-zero is what counts.
|
|
* whole being zero/non-zero is what counts.
|
|
- * TODO: M-profile MVE also has a QC bit.
|
|
|
|
*/
|
|
*/
|
|
- env->vfp.qc[0] = val & FPCR_QC;
|
|
|
|
|
|
+ env->vfp.qc[0] = val & FPSR_QC;
|
|
env->vfp.qc[1] = 0;
|
|
env->vfp.qc[1] = 0;
|
|
env->vfp.qc[2] = 0;
|
|
env->vfp.qc[2] = 0;
|
|
env->vfp.qc[3] = 0;
|
|
env->vfp.qc[3] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * The only FPSR bits we keep in vfp.fpsr are NZCV:
|
|
|
|
+ * the exception flags IOC|DZC|OFC|UFC|IXC|IDC are stored in
|
|
|
|
+ * fp_status, and QC is in vfp.qc[]. Store the NZCV bits there,
|
|
|
|
+ * and zero any of the other FPSR bits.
|
|
|
|
+ */
|
|
|
|
+ val &= FPSR_NZCV_MASK;
|
|
|
|
+ env->vfp.fpsr = 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. */
|
|
|
|
+ if (!cpu_isar_feature(any_fp16, cpu)) {
|
|
|
|
+ val &= ~FPCR_FZ16;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* We don't implement trapped exception handling, so the
|
|
* We don't implement trapped exception handling, so the
|
|
* trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
|
|
* trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
|
|
*
|
|
*
|
|
- * The exception flags IOC|DZC|OFC|UFC|IXC|IDC are stored in
|
|
|
|
- * fp_status; QC, Len and Stride are stored separately earlier.
|
|
|
|
- * Clear out all of those and the RES0 bits: only NZCV, AHP, DN,
|
|
|
|
- * FZ, RMode and FZ16 are kept in vfp.xregs[FPSCR].
|
|
|
|
|
|
+ * The FPCR bits we keep in vfp.fpcr are AHP, DN, FZ, RMode
|
|
|
|
+ * and FZ16. Len, Stride and LTPSIZE we just handled. Store those bits
|
|
|
|
+ * there, and zero any of the other FPCR bits and the RES0 and RAZ/WI
|
|
|
|
+ * bits.
|
|
*/
|
|
*/
|
|
- env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000;
|
|
|
|
|
|
+ val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16;
|
|
|
|
+ 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_masked(env, val, FPSCR_FPCR_MASK);
|
|
|
|
+ vfp_set_fpsr(env, val & FPSCR_FPSR_MASK);
|
|
}
|
|
}
|
|
|
|
|
|
void vfp_set_fpscr(CPUARMState *env, uint32_t val)
|
|
void vfp_set_fpscr(CPUARMState *env, uint32_t val)
|
|
@@ -315,8 +368,7 @@ static void softfloat_to_vfp_compare(CPUARMState *env, FloatRelation cmp)
|
|
default:
|
|
default:
|
|
g_assert_not_reached();
|
|
g_assert_not_reached();
|
|
}
|
|
}
|
|
- env->vfp.xregs[ARM_VFP_FPSCR] =
|
|
|
|
- deposit32(env->vfp.xregs[ARM_VFP_FPSCR], 28, 4, flags);
|
|
|
|
|
|
+ env->vfp.fpsr = deposit64(env->vfp.fpsr, 28, 4, flags); /* NZCV */
|
|
}
|
|
}
|
|
|
|
|
|
/* XXX: check quiet/signaling case */
|
|
/* XXX: check quiet/signaling case */
|
|
@@ -1119,8 +1171,7 @@ uint32_t HELPER(vjcvt)(float64 value, CPUARMState *env)
|
|
uint32_t z = (pair >> 32) == 0;
|
|
uint32_t z = (pair >> 32) == 0;
|
|
|
|
|
|
/* Store Z, clear NCV, in FPSCR.NZCV. */
|
|
/* Store Z, clear NCV, in FPSCR.NZCV. */
|
|
- env->vfp.xregs[ARM_VFP_FPSCR]
|
|
|
|
- = (env->vfp.xregs[ARM_VFP_FPSCR] & ~CPSR_NZCV) | (z * CPSR_Z);
|
|
|
|
|
|
+ env->vfp.fpsr = (env->vfp.fpsr & ~FPSR_NZCV_MASK) | (z * FPSR_Z);
|
|
|
|
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|