Factor FCR→fp_status and FSR→fp_status synchronisation out of the
wur_fpu{2k,}_fcr/wur_fpu_fsr helpers into cpu_set_fcr(), cpu_set_fsr(),
and cpu_get_fsr(). Signal delivery code needs to restore the FP rounding
mode and exception flags without duplicating the flag-mapping tables.cpu_set_fcr() applies the union mask 0xfffff07f (superset of the wur_fpu_fcr mask 0x0000007f and the wur_fpu2k_fcr mask 0xfffff07f) so that FCR bits valid only on fpu2k configs are preserved while MBZ bits 7-11 are always cleared. Signed-off-by: Matt Turner <[email protected]> --- target/xtensa/cpu.h | 4 ++++ target/xtensa/fpu_helper.c | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git ./target/xtensa/cpu.h ./target/xtensa/cpu.h index 75cfeee6e3..442e98bd1b 100644 --- ./target/xtensa/cpu.h +++ ./target/xtensa/cpu.h @@ -642,6 +642,10 @@ static inline void xtensa_select_static_vectors(CPUXtensaState *env, } void xtensa_runstall(CPUXtensaState *env, bool runstall); +uint32_t cpu_get_fsr(CPUXtensaState *env); +void cpu_set_fcr(CPUXtensaState *env, uint32_t v); +void cpu_set_fsr(CPUXtensaState *env, uint32_t v); + #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) #define XTENSA_OPTION_ALL (~(uint64_t)0) diff --git ./target/xtensa/fpu_helper.c ./target/xtensa/fpu_helper.c index 5358060c50..9937bc5bea 100644 --- ./target/xtensa/fpu_helper.c +++ ./target/xtensa/fpu_helper.c @@ -64,6 +64,48 @@ void xtensa_use_first_nan(CPUXtensaState *env, bool use_first) &env->fp_status); } +uint32_t cpu_get_fsr(CPUXtensaState *env) +{ + uint32_t flags = 0; + int fef = get_float_exception_flags(&env->fp_status); + unsigned i; + + for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) { + if (fef & xtensa_fp_flag_map[i].softfloat_fp_flag) { + flags |= xtensa_fp_flag_map[i].xtensa_fp_flag; + } + } + return flags << XTENSA_FSR_FLAGS_SHIFT; +} + +void cpu_set_fcr(CPUXtensaState *env, uint32_t v) +{ + static const int rounding_mode[] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down, + }; + + env->uregs[FCR] = v & 0xfffff07f; + set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status); +} + +void cpu_set_fsr(CPUXtensaState *env, uint32_t v) +{ + uint32_t flags = v >> XTENSA_FSR_FLAGS_SHIFT; + int fef = 0; + unsigned i; + + env->uregs[FSR] = v & 0x00000f80; + for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) { + if (flags & xtensa_fp_flag_map[i].xtensa_fp_flag) { + fef |= xtensa_fp_flag_map[i].softfloat_fp_flag; + } + } + set_float_exception_flags(fef, &env->fp_status); +} + void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v) { static const int rounding_mode[] = { -- 2.53.0
