target/arm: Split vfp_access_check() into A and M versions

vfp_access_check and its helper routine full_vfp_access_check() has
gradually grown and is now an awkward mix of A-profile only and
M-profile only pieces.  Refactor it into an A-profile only and an
M-profile only version, taking advantage of the fact that now the
only direct call to full_vfp_access_check() is in A-profile-only
code.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20210618141019.10671-7-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2021-06-18 15:10:18 +01:00
parent 95aceeeac9
commit e8cedaf779
1 changed files with 48 additions and 31 deletions

View File

@ -188,32 +188,19 @@ static void gen_update_fp_context(DisasContext *s)
} }
/* /*
* Check that VFP access is enabled. If it is, do the necessary * Check that VFP access is enabled, A-profile specific version.
* M-profile lazy-FP handling and then return true. *
* If not, emit code to generate an appropriate exception and * If VFP is enabled, return true. If not, emit code to generate an
* return false. * appropriate exception and return false.
* The ignore_vfp_enabled argument specifies that we should ignore * The ignore_vfp_enabled argument specifies that we should ignore
* whether VFP is enabled via FPEXC[EN]: this should be true for FMXR/FMRX * whether VFP is enabled via FPEXC.EN: this should be true for FMXR/FMRX
* accesses to FPSID, FPEXC, MVFR0, MVFR1, MVFR2, and false for all other insns. * accesses to FPSID, FPEXC, MVFR0, MVFR1, MVFR2, and false for all other insns.
*/ */
static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled) static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled)
{ {
if (s->fp_excp_el) { if (s->fp_excp_el) {
if (arm_dc_feature(s, ARM_FEATURE_M)) { gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
/* syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
* M-profile mostly catches the "FPU disabled" case early, in
* disas_m_nocp(), but a few insns (eg LCTP, WLSTP, DLSTP)
* which do coprocessor-checks are outside the large ranges of
* the encoding space handled by the patterns in m-nocp.decode,
* and for them we may need to raise NOCP here.
*/
gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
syn_uncategorized(), s->fp_excp_el);
} else {
gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
syn_fp_access_trap(1, 0xe, false),
s->fp_excp_el);
}
return false; return false;
} }
@ -222,17 +209,39 @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled)
unallocated_encoding(s); unallocated_encoding(s);
return false; return false;
} }
return true;
}
if (arm_dc_feature(s, ARM_FEATURE_M)) { /*
/* Handle M-profile lazy FP state mechanics */ * Check that VFP access is enabled, M-profile specific version.
*
/* Trigger lazy-state preservation if necessary */ * If VFP is enabled, do the necessary M-profile lazy-FP handling and then
gen_preserve_fp_state(s); * return true. If not, emit code to generate an appropriate exception and
* return false.
/* Update ownership of FP context and create new FP context if needed */ */
gen_update_fp_context(s); static bool vfp_access_check_m(DisasContext *s)
{
if (s->fp_excp_el) {
/*
* M-profile mostly catches the "FPU disabled" case early, in
* disas_m_nocp(), but a few insns (eg LCTP, WLSTP, DLSTP)
* which do coprocessor-checks are outside the large ranges of
* the encoding space handled by the patterns in m-nocp.decode,
* and for them we may need to raise NOCP here.
*/
gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
syn_uncategorized(), s->fp_excp_el);
return false;
} }
/* Handle M-profile lazy FP state mechanics */
/* Trigger lazy-state preservation if necessary */
gen_preserve_fp_state(s);
/* Update ownership of FP context and create new FP context if needed */
gen_update_fp_context(s);
return true; return true;
} }
@ -242,7 +251,11 @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled)
*/ */
bool vfp_access_check(DisasContext *s) bool vfp_access_check(DisasContext *s)
{ {
return full_vfp_access_check(s, false); if (arm_dc_feature(s, ARM_FEATURE_M)) {
return vfp_access_check_m(s);
} else {
return vfp_access_check_a(s, false);
}
} }
static bool trans_VSEL(DisasContext *s, arg_VSEL *a) static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
@ -732,7 +745,11 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
return false; return false;
} }
if (!full_vfp_access_check(s, ignore_vfp_enabled)) { /*
* Call vfp_access_check_a() directly, because we need to tell
* it to ignore FPEXC.EN for some register accesses.
*/
if (!vfp_access_check_a(s, ignore_vfp_enabled)) {
return true; return true;
} }