mirror of https://gitee.com/openkylin/qemu.git
target/arm: Implement FPCXT_NS fp system register
Implement the v8.1M FPCXT_NS floating-point system register. This is a little more complicated than FPCXT_S, because it has specific handling for "current FP state is inactive", and it only wants to do PreserveFPState(), not the full set of actions done by ExecuteFPCheck() which vfp_access_check() implements. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20201210201433.26262-4-peter.maydell@linaro.org
This commit is contained in:
parent
7fbf95a037
commit
eb20dafdbf
|
@ -663,6 +663,7 @@ static FPSysRegCheckResult fp_sysreg_checks(DisasContext *s, int regno)
|
|||
}
|
||||
break;
|
||||
case ARM_VFP_FPCXT_S:
|
||||
case ARM_VFP_FPCXT_NS:
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -674,13 +675,48 @@ static FPSysRegCheckResult fp_sysreg_checks(DisasContext *s, int regno)
|
|||
return FPSysRegCheckFailed;
|
||||
}
|
||||
|
||||
if (!vfp_access_check(s)) {
|
||||
/*
|
||||
* FPCXT_NS is a special case: it has specific handling for
|
||||
* "current FP state is inactive", and must do the PreserveFPState()
|
||||
* but not the usual full set of actions done by ExecuteFPCheck().
|
||||
* So we don't call vfp_access_check() and the callers must handle this.
|
||||
*/
|
||||
if (regno != ARM_VFP_FPCXT_NS && !vfp_access_check(s)) {
|
||||
return FPSysRegCheckDone;
|
||||
}
|
||||
|
||||
return FPSysRegCheckContinue;
|
||||
}
|
||||
|
||||
static void gen_branch_fpInactive(DisasContext *s, TCGCond cond,
|
||||
TCGLabel *label)
|
||||
{
|
||||
/*
|
||||
* FPCXT_NS is a special case: it has specific handling for
|
||||
* "current FP state is inactive", and must do the PreserveFPState()
|
||||
* but not the usual full set of actions done by ExecuteFPCheck().
|
||||
* We don't have a TB flag that matches the fpInactive check, so we
|
||||
* do it at runtime as we don't expect FPCXT_NS accesses to be frequent.
|
||||
*
|
||||
* Emit code that checks fpInactive and does a conditional
|
||||
* branch to label based on it:
|
||||
* if cond is TCG_COND_NE then branch if fpInactive != 0 (ie if inactive)
|
||||
* if cond is TCG_COND_EQ then branch if fpInactive == 0 (ie if active)
|
||||
*/
|
||||
assert(cond == TCG_COND_EQ || cond == TCG_COND_NE);
|
||||
|
||||
/* fpInactive = FPCCR_NS.ASPEN == 1 && CONTROL.FPCA == 0 */
|
||||
TCGv_i32 aspen, fpca;
|
||||
aspen = load_cpu_field(v7m.fpccr[M_REG_NS]);
|
||||
fpca = load_cpu_field(v7m.control[M_REG_S]);
|
||||
tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
|
||||
tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
|
||||
tcg_gen_andi_i32(fpca, fpca, R_V7M_CONTROL_FPCA_MASK);
|
||||
tcg_gen_or_i32(fpca, fpca, aspen);
|
||||
tcg_gen_brcondi_i32(tcg_invert_cond(cond), fpca, 0, label);
|
||||
tcg_temp_free_i32(aspen);
|
||||
tcg_temp_free_i32(fpca);
|
||||
}
|
||||
|
||||
static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
|
||||
|
||||
fp_sysreg_loadfn *loadfn,
|
||||
|
@ -688,6 +724,7 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
|
|||
{
|
||||
/* Do a write to an M-profile floating point system register */
|
||||
TCGv_i32 tmp;
|
||||
TCGLabel *lab_end = NULL;
|
||||
|
||||
switch (fp_sysreg_checks(s, regno)) {
|
||||
case FPSysRegCheckFailed:
|
||||
|
@ -721,6 +758,13 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
|
|||
tcg_temp_free_i32(tmp);
|
||||
break;
|
||||
}
|
||||
case ARM_VFP_FPCXT_NS:
|
||||
lab_end = gen_new_label();
|
||||
/* fpInactive case: write is a NOP, so branch to end */
|
||||
gen_branch_fpInactive(s, TCG_COND_NE, lab_end);
|
||||
/* !fpInactive: PreserveFPState(), and reads same as FPCXT_S */
|
||||
gen_preserve_fp_state(s);
|
||||
/* fall through */
|
||||
case ARM_VFP_FPCXT_S:
|
||||
{
|
||||
TCGv_i32 sfpa, control;
|
||||
|
@ -744,6 +788,9 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
|
|||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
if (lab_end) {
|
||||
gen_set_label(lab_end);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -753,6 +800,8 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
|
|||
{
|
||||
/* Do a read from an M-profile floating point system register */
|
||||
TCGv_i32 tmp;
|
||||
TCGLabel *lab_end = NULL;
|
||||
bool lookup_tb = false;
|
||||
|
||||
switch (fp_sysreg_checks(s, regno)) {
|
||||
case FPSysRegCheckFailed:
|
||||
|
@ -811,12 +860,59 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
|
|||
fpscr = load_cpu_field(v7m.fpdscr[M_REG_NS]);
|
||||
gen_helper_vfp_set_fpscr(cpu_env, fpscr);
|
||||
tcg_temp_free_i32(fpscr);
|
||||
gen_lookup_tb(s);
|
||||
lookup_tb = true;
|
||||
break;
|
||||
}
|
||||
case ARM_VFP_FPCXT_NS:
|
||||
{
|
||||
TCGv_i32 control, sfpa, fpscr, fpdscr, zero;
|
||||
TCGLabel *lab_active = gen_new_label();
|
||||
|
||||
lookup_tb = true;
|
||||
|
||||
gen_branch_fpInactive(s, TCG_COND_EQ, lab_active);
|
||||
/* fpInactive case: reads as FPDSCR_NS */
|
||||
TCGv_i32 tmp = load_cpu_field(v7m.fpdscr[M_REG_NS]);
|
||||
storefn(s, opaque, tmp);
|
||||
lab_end = gen_new_label();
|
||||
tcg_gen_br(lab_end);
|
||||
|
||||
gen_set_label(lab_active);
|
||||
/* !fpInactive: Reads the same as FPCXT_S, but side effects differ */
|
||||
gen_preserve_fp_state(s);
|
||||
tmp = tcg_temp_new_i32();
|
||||
sfpa = tcg_temp_new_i32();
|
||||
fpscr = tcg_temp_new_i32();
|
||||
gen_helper_vfp_get_fpscr(fpscr, cpu_env);
|
||||
tcg_gen_andi_i32(tmp, fpscr, ~FPCR_NZCV_MASK);
|
||||
control = load_cpu_field(v7m.control[M_REG_S]);
|
||||
tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK);
|
||||
tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT);
|
||||
tcg_gen_or_i32(tmp, tmp, sfpa);
|
||||
tcg_temp_free_i32(control);
|
||||
/* Store result before updating FPSCR, in case it faults */
|
||||
storefn(s, opaque, tmp);
|
||||
/* If SFPA is zero then set FPSCR from FPDSCR_NS */
|
||||
fpdscr = load_cpu_field(v7m.fpdscr[M_REG_NS]);
|
||||
zero = tcg_const_i32(0);
|
||||
tcg_gen_movcond_i32(TCG_COND_EQ, fpscr, sfpa, zero, fpdscr, fpscr);
|
||||
gen_helper_vfp_set_fpscr(cpu_env, fpscr);
|
||||
tcg_temp_free_i32(zero);
|
||||
tcg_temp_free_i32(sfpa);
|
||||
tcg_temp_free_i32(fpdscr);
|
||||
tcg_temp_free_i32(fpscr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (lab_end) {
|
||||
gen_set_label(lab_end);
|
||||
}
|
||||
if (lookup_tb) {
|
||||
gen_lookup_tb(s);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue