target/arm: Enable FPSCR.QC bit for MVE
MVE has an FPSCR.QC bit similar to the A-profile Neon one; when MVE is implemented make the bit writeable, both in the generic "load and store FPSCR" helper functions and in the code for handling the NZCVQC sysreg which we had previously left as "TODO when we implement MVE". Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20210614151007.4545-3-peter.maydell@linaro.org
This commit is contained in:
parent
6e802db3c4
commit
c485ce2c49
|
@ -784,10 +784,17 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
|
||||||
{
|
{
|
||||||
TCGv_i32 fpscr;
|
TCGv_i32 fpscr;
|
||||||
tmp = loadfn(s, opaque);
|
tmp = loadfn(s, opaque);
|
||||||
|
if (dc_isar_feature(aa32_mve, s)) {
|
||||||
|
/* QC is only present for MVE; otherwise RES0 */
|
||||||
|
TCGv_i32 qc = tcg_temp_new_i32();
|
||||||
|
tcg_gen_andi_i32(qc, tmp, FPCR_QC);
|
||||||
/*
|
/*
|
||||||
* TODO: when we implement MVE, write the QC bit.
|
* The 4 vfp.qc[] fields need only be "zero" vs "non-zero";
|
||||||
* For non-MVE, QC is RES0.
|
* here writing the same value into all elements is simplest.
|
||||||
*/
|
*/
|
||||||
|
tcg_gen_gvec_dup_i32(MO_32, offsetof(CPUARMState, vfp.qc),
|
||||||
|
16, 16, qc);
|
||||||
|
}
|
||||||
tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK);
|
tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK);
|
||||||
fpscr = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
|
fpscr = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
|
||||||
tcg_gen_andi_i32(fpscr, fpscr, ~FPCR_NZCV_MASK);
|
tcg_gen_andi_i32(fpscr, fpscr, ~FPCR_NZCV_MASK);
|
||||||
|
@ -869,6 +876,11 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (regno == ARM_VFP_FPSCR_NZCVQC && !dc_isar_feature(aa32_mve, s)) {
|
||||||
|
/* QC is RES0 without MVE, so NZCVQC simplifies to NZCV */
|
||||||
|
regno = QEMU_VFP_FPSCR_NZCV;
|
||||||
|
}
|
||||||
|
|
||||||
switch (regno) {
|
switch (regno) {
|
||||||
case ARM_VFP_FPSCR:
|
case ARM_VFP_FPSCR:
|
||||||
tmp = tcg_temp_new_i32();
|
tmp = tcg_temp_new_i32();
|
||||||
|
@ -876,11 +888,11 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
|
||||||
storefn(s, opaque, tmp);
|
storefn(s, opaque, tmp);
|
||||||
break;
|
break;
|
||||||
case ARM_VFP_FPSCR_NZCVQC:
|
case ARM_VFP_FPSCR_NZCVQC:
|
||||||
/*
|
tmp = tcg_temp_new_i32();
|
||||||
* TODO: MVE has a QC bit, which we probably won't store
|
gen_helper_vfp_get_fpscr(tmp, cpu_env);
|
||||||
* in the xregs[] field. For non-MVE, where QC is RES0,
|
tcg_gen_andi_i32(tmp, tmp, FPCR_NZCVQC_MASK);
|
||||||
* we can just fall through to the FPSCR_NZCV case.
|
storefn(s, opaque, tmp);
|
||||||
*/
|
break;
|
||||||
case QEMU_VFP_FPSCR_NZCV:
|
case QEMU_VFP_FPSCR_NZCV:
|
||||||
/*
|
/*
|
||||||
* Read just NZCV; this is a special case to avoid the
|
* Read just NZCV; this is a special case to avoid the
|
||||||
|
|
|
@ -220,7 +220,8 @@ void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
|
||||||
FPCR_LTPSIZE_LENGTH);
|
FPCR_LTPSIZE_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_NEON)) {
|
if (arm_feature(env, ARM_FEATURE_NEON) ||
|
||||||
|
cpu_isar_feature(aa32_mve, cpu)) {
|
||||||
/*
|
/*
|
||||||
* The bit we set within fpscr_q is arbitrary; the register as a
|
* The bit we set within fpscr_q is arbitrary; the register as a
|
||||||
* whole being zero/non-zero is what counts.
|
* whole being zero/non-zero is what counts.
|
||||||
|
|
Loading…
Reference in a new issue