target/arm: Implement M-profile FPSCR_nzcvqc
v8.1M defines a new FP system register FPSCR_nzcvqc; this behaves like the existing FPSCR, except that it reads and writes only bits [31:27] of the FPSCR (the N, Z, C, V and QC flag bits). (Unlike the FPSCR, the special case for Rt=15 of writing the CPSR.NZCV is not permitted.) Implement the register. Since we don't yet implement MVE, we handle the QC bit as RES0, with todo comments for where we will need to add support later. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20201119215617.29887-11-peter.maydell@linaro.org
This commit is contained in:
parent
0bf0dd4dcb
commit
9542c30bcf
|
@ -1524,6 +1524,13 @@ void vfp_set_fpscr(CPUARMState *env, uint32_t val);
|
||||||
#define FPCR_FZ (1 << 24) /* Flush-to-zero enable bit */
|
#define FPCR_FZ (1 << 24) /* Flush-to-zero enable bit */
|
||||||
#define FPCR_DN (1 << 25) /* Default NaN enable bit */
|
#define FPCR_DN (1 << 25) /* Default NaN enable bit */
|
||||||
#define FPCR_QC (1 << 27) /* Cumulative saturation bit */
|
#define FPCR_QC (1 << 27) /* Cumulative saturation bit */
|
||||||
|
#define FPCR_V (1 << 28) /* FP overflow flag */
|
||||||
|
#define FPCR_C (1 << 29) /* FP carry flag */
|
||||||
|
#define FPCR_Z (1 << 30) /* FP zero flag */
|
||||||
|
#define FPCR_N (1 << 31) /* FP negative flag */
|
||||||
|
|
||||||
|
#define FPCR_NZCV_MASK (FPCR_N | FPCR_Z | FPCR_C | FPCR_V)
|
||||||
|
#define FPCR_NZCVQC_MASK (FPCR_NZCV_MASK | FPCR_QC)
|
||||||
|
|
||||||
static inline uint32_t vfp_get_fpsr(CPUARMState *env)
|
static inline uint32_t vfp_get_fpsr(CPUARMState *env)
|
||||||
{
|
{
|
||||||
|
@ -1568,6 +1575,12 @@ enum arm_cpu_mode {
|
||||||
#define ARM_VFP_FPEXC 8
|
#define ARM_VFP_FPEXC 8
|
||||||
#define ARM_VFP_FPINST 9
|
#define ARM_VFP_FPINST 9
|
||||||
#define ARM_VFP_FPINST2 10
|
#define ARM_VFP_FPINST2 10
|
||||||
|
/* These ones are M-profile only */
|
||||||
|
#define ARM_VFP_FPSCR_NZCVQC 2
|
||||||
|
#define ARM_VFP_VPR 12
|
||||||
|
#define ARM_VFP_P0 13
|
||||||
|
#define ARM_VFP_FPCXT_NS 14
|
||||||
|
#define ARM_VFP_FPCXT_S 15
|
||||||
|
|
||||||
/* QEMU-internal value meaning "FPSCR, but we care only about NZCV" */
|
/* QEMU-internal value meaning "FPSCR, but we care only about NZCV" */
|
||||||
#define QEMU_VFP_FPSCR_NZCV 0xffff
|
#define QEMU_VFP_FPSCR_NZCV 0xffff
|
||||||
|
|
|
@ -648,6 +648,11 @@ static FPSysRegCheckResult fp_sysreg_checks(DisasContext *s, int regno)
|
||||||
case ARM_VFP_FPSCR:
|
case ARM_VFP_FPSCR:
|
||||||
case QEMU_VFP_FPSCR_NZCV:
|
case QEMU_VFP_FPSCR_NZCV:
|
||||||
break;
|
break;
|
||||||
|
case ARM_VFP_FPSCR_NZCVQC:
|
||||||
|
if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return FPSysRegCheckFailed;
|
return FPSysRegCheckFailed;
|
||||||
}
|
}
|
||||||
|
@ -683,6 +688,22 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
|
||||||
tcg_temp_free_i32(tmp);
|
tcg_temp_free_i32(tmp);
|
||||||
gen_lookup_tb(s);
|
gen_lookup_tb(s);
|
||||||
break;
|
break;
|
||||||
|
case ARM_VFP_FPSCR_NZCVQC:
|
||||||
|
{
|
||||||
|
TCGv_i32 fpscr;
|
||||||
|
tmp = loadfn(s, opaque);
|
||||||
|
/*
|
||||||
|
* TODO: when we implement MVE, write the QC bit.
|
||||||
|
* For non-MVE, QC is RES0.
|
||||||
|
*/
|
||||||
|
tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK);
|
||||||
|
fpscr = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
|
||||||
|
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]);
|
||||||
|
tcg_temp_free_i32(tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
@ -711,6 +732,12 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
|
||||||
gen_helper_vfp_get_fpscr(tmp, cpu_env);
|
gen_helper_vfp_get_fpscr(tmp, cpu_env);
|
||||||
storefn(s, opaque, tmp);
|
storefn(s, opaque, tmp);
|
||||||
break;
|
break;
|
||||||
|
case ARM_VFP_FPSCR_NZCVQC:
|
||||||
|
/*
|
||||||
|
* TODO: MVE has a QC bit, which we probably won't store
|
||||||
|
* in the xregs[] field. For non-MVE, where QC is RES0,
|
||||||
|
* we can just fall through to the FPSCR_NZCV case.
|
||||||
|
*/
|
||||||
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
|
||||||
|
|
Loading…
Reference in a new issue