Now that we have refactored the set/get functions so that the FPSCR
format is no longer the authoritative one, we can keep FPSR and FPCR
in separate CPU state fields.
As well as the get and set functions, we also have a scattering of
places in the code which directly access vfp.xregs[ARM_VFP_FPSCR] to
extract single fields which are stored there. These all change to
directly access either vfp.fpsr or vfp.fpcr, depending on the
location of the field. (Most commonly, this is the NZCV flags.)
We make the field in the CPU state struct 64 bits, because
architecturally FPSR and FPCR are 64 bits. However we leave the
types of the arguments and return values of the get/set functions as
32 bits, since we don't need to make that change with the current
architecture and various callsites would be unable to handle
set bits in the high half (for instance the gdbstub protocol
assumes they're only 32 bit registers).
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id:
20240628142347.
1283015-7-peter.maydell@linaro.org
int vec_len;
int vec_stride;
+ /*
+ * Floating point status and control registers. Some bits are
+ * stored separately in other fields or in the float_status below.
+ */
+ uint64_t fpsr;
+ uint64_t fpcr;
+
uint32_t xregs[16];
/* Scratch space for aa32 neon expansion. */
if (update_flags) {
/* Store C, clear NZV. */
- env->vfp.xregs[ARM_VFP_FPSCR] &= ~FPCR_NZCV_MASK;
- env->vfp.xregs[ARM_VFP_FPSCR] |= carry_in * FPCR_C;
+ env->vfp.fpsr &= ~FPCR_NZCV_MASK;
+ env->vfp.fpsr |= carry_in * FPCR_C;
}
mve_advance_vpt(env);
}
void HELPER(mve_vadc)(CPUARMState *env, void *vd, void *vn, void *vm)
{
- bool carry_in = env->vfp.xregs[ARM_VFP_FPSCR] & FPCR_C;
+ bool carry_in = env->vfp.fpsr & FPCR_C;
do_vadc(env, vd, vn, vm, 0, carry_in, false);
}
void HELPER(mve_vsbc)(CPUARMState *env, void *vd, void *vn, void *vm)
{
- bool carry_in = env->vfp.xregs[ARM_VFP_FPSCR] & FPCR_C;
+ bool carry_in = env->vfp.fpsr & FPCR_C;
do_vadc(env, vd, vn, vm, -1, carry_in, false);
}
uint32_t *m = vm;
uint16_t r;
uint16_t mask = mve_element_mask(env);
- bool ieee = !(env->vfp.xregs[ARM_VFP_FPSCR] & FPCR_AHP);
+ bool ieee = !(env->vfp.fpcr & FPCR_AHP);
unsigned e;
float_status *fpst;
float_status scratch_fpst;
uint16_t *m = vm;
uint32_t r;
uint16_t mask = mve_element_mask(env);
- bool ieee = !(env->vfp.xregs[ARM_VFP_FPSCR] & FPCR_AHP);
+ bool ieee = !(env->vfp.fpcr & FPCR_AHP);
unsigned e;
float_status *fpst;
float_status scratch_fpst;
16, 16, qc);
}
tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK);
- fpscr = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
+ fpscr = load_cpu_field_low32(vfp.fpsr);
tcg_gen_andi_i32(fpscr, fpscr, ~FPCR_NZCV_MASK);
tcg_gen_or_i32(fpscr, fpscr, tmp);
- store_cpu_field(fpscr, vfp.xregs[ARM_VFP_FPSCR]);
+ store_cpu_field_low32(fpscr, vfp.fpsr);
break;
}
case ARM_VFP_FPCXT_NS:
* Read just NZCV; this is a special case to avoid the
* helper call for the "VMRS to CPSR.NZCV" insn.
*/
- tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
+ tmp = load_cpu_field_low32(vfp.fpsr);
tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK);
storefn(s, opaque, tmp, true);
break;
break;
case ARM_VFP_FPSCR:
if (a->rt == 15) {
- tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
+ tmp = load_cpu_field_low32(vfp.fpsr);
tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK);
} else {
tmp = tcg_temp_new_i32();
{
TCGv_i32 ret = tcg_temp_new_i32();
- tcg_gen_ld_i32(ret, tcg_env,
- offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPSCR]));
+ tcg_gen_ld_i32(ret, tcg_env, offsetoflow32(CPUARMState, vfp.fpcr));
tcg_gen_extract_i32(ret, ret, 26, 1);
return ret;
static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val)
{
- uint32_t changed = env->vfp.xregs[ARM_VFP_FPSCR];
+ uint64_t changed = env->vfp.fpcr;
changed ^= val;
if (changed & (3 << 22)) {
uint32_t vfp_get_fpcr(CPUARMState *env)
{
- uint32_t fpcr = (env->vfp.xregs[ARM_VFP_FPSCR] & FPCR_MASK)
+ uint32_t fpcr = env->vfp.fpcr
| (env->vfp.vec_len << 16)
| (env->vfp.vec_stride << 20);
uint32_t vfp_get_fpsr(CPUARMState *env)
{
- uint32_t fpsr = env->vfp.xregs[ARM_VFP_FPSCR] & FPSR_MASK;
+ uint32_t fpsr = env->vfp.fpsr;
uint32_t i;
fpsr |= vfp_get_fpsr_from_host(env);
}
/*
- * The only FPSR bits we keep in vfp.xregs[FPSCR] are NZCV:
+ * 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 (but preserve the FPCR
- * bits).
+ * and zero any of the other FPSR bits.
*/
val &= FPCR_NZCV_MASK;
- env->vfp.xregs[ARM_VFP_FPSCR] &= ~FPSR_MASK;
- env->vfp.xregs[ARM_VFP_FPSCR] |= val;
+ env->vfp.fpsr = val;
}
void vfp_set_fpcr(CPUARMState *env, uint32_t val)
* We don't implement trapped exception handling, so the
* trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
*
- * The FPCR bits we keep in vfp.xregs[FPSCR] are AHP, DN, FZ, RMode
+ * 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.
*/
val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16;
- env->vfp.xregs[ARM_VFP_FPSCR] &= ~FPCR_MASK;
- env->vfp.xregs[ARM_VFP_FPSCR] |= val;
+ env->vfp.fpcr = val;
}
void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
default:
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 */
uint32_t z = (pair >> 32) == 0;
/* 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 & ~FPCR_NZCV_MASK) | (z * FPCR_Z);
return result;
}