@@ -254,10 +254,10 @@ FOP_PROTO(recip)
FOP_PROTO(rint)
#undef FOP_PROTO
-#define FOP_PROTO(op) \
-DEF_HELPER_1(float_ ## op ## _s, i32, i32) \
-DEF_HELPER_1(float_ ## op ## _d, i64, i64) \
-DEF_HELPER_1(float_ ## op ## _ps, i64, i64)
+#define FOP_PROTO(op) \
+DEF_HELPER_2(float_ ## op ## _s, i32, env, i32) \
+DEF_HELPER_2(float_ ## op ## _d, i64, env, i64) \
+DEF_HELPER_2(float_ ## op ## _ps, i64, env, i64)
FOP_PROTO(abs)
FOP_PROTO(chs)
#undef FOP_PROTO
@@ -924,6 +924,8 @@ DEF_HELPER_4(msa_pcnt_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_nloc_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_nlzc_df, void, env, i32, i32, i32)
+DEF_HELPER_2(msa_class_s, i32, env, i32)
+DEF_HELPER_2(msa_class_d, i64, env, i64)
DEF_HELPER_4(msa_fclass_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ftrunc_s_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ftrunc_u_df, void, env, i32, i32, i32)
@@ -2924,19 +2924,67 @@ void helper_msa_fmax_a_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
msa_move_v(pwd, pwx);
}
+#define MSA_CLASS_SIGNALING_NAN 0x001
+#define MSA_CLASS_QUIET_NAN 0x002
+#define MSA_CLASS_NEGATIVE_INFINITY 0x004
+#define MSA_CLASS_NEGATIVE_NORMAL 0x008
+#define MSA_CLASS_NEGATIVE_SUBNORMAL 0x010
+#define MSA_CLASS_NEGATIVE_ZERO 0x020
+#define MSA_CLASS_POSITIVE_INFINITY 0x040
+#define MSA_CLASS_POSITIVE_NORMAL 0x080
+#define MSA_CLASS_POSITIVE_SUBNORMAL 0x100
+#define MSA_CLASS_POSITIVE_ZERO 0x200
+
+#define MSA_CLASS(name, bits) \
+uint ## bits ## _t helper_msa_ ## name (CPUMIPSState *env, \
+ uint ## bits ## _t arg) \
+{ \
+ if (float ## bits ## _is_signaling_nan(arg, \
+ &env->active_tc.msa_fp_status)) { \
+ return MSA_CLASS_SIGNALING_NAN; \
+ } else if (float ## bits ## _is_quiet_nan(arg, \
+ &env->active_tc.msa_fp_status)) { \
+ return MSA_CLASS_QUIET_NAN; \
+ } else if (float ## bits ## _is_neg(arg)) { \
+ if (float ## bits ## _is_infinity(arg)) { \
+ return MSA_CLASS_NEGATIVE_INFINITY; \
+ } else if (float ## bits ## _is_zero(arg)) { \
+ return MSA_CLASS_NEGATIVE_ZERO; \
+ } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
+ return MSA_CLASS_NEGATIVE_SUBNORMAL; \
+ } else { \
+ return MSA_CLASS_NEGATIVE_NORMAL; \
+ } \
+ } else { \
+ if (float ## bits ## _is_infinity(arg)) { \
+ return MSA_CLASS_POSITIVE_INFINITY; \
+ } else if (float ## bits ## _is_zero(arg)) { \
+ return MSA_CLASS_POSITIVE_ZERO; \
+ } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
+ return MSA_CLASS_POSITIVE_SUBNORMAL; \
+ } else { \
+ return MSA_CLASS_POSITIVE_NORMAL; \
+ } \
+ } \
+}
+
+MSA_CLASS(class_s, 32)
+MSA_CLASS(class_d, 64)
+#undef FLOAT_MSA_CLASS
+
void helper_msa_fclass_df(CPUMIPSState *env, uint32_t df,
uint32_t wd, uint32_t ws)
{
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
if (df == DF_WORD) {
- pwd->w[0] = helper_float_class_s(env, pws->w[0]);
- pwd->w[1] = helper_float_class_s(env, pws->w[1]);
- pwd->w[2] = helper_float_class_s(env, pws->w[2]);
- pwd->w[3] = helper_float_class_s(env, pws->w[3]);
+ pwd->w[0] = helper_msa_class_s(env, pws->w[0]);
+ pwd->w[1] = helper_msa_class_s(env, pws->w[1]);
+ pwd->w[2] = helper_msa_class_s(env, pws->w[2]);
+ pwd->w[3] = helper_msa_class_s(env, pws->w[3]);
} else {
- pwd->d[0] = helper_float_class_d(env, pws->d[0]);
- pwd->d[1] = helper_float_class_d(env, pws->d[1]);
+ pwd->d[0] = helper_msa_class_d(env, pws->d[0]);
+ pwd->d[1] = helper_msa_class_d(env, pws->d[1]);
}
}
@@ -2621,9 +2621,23 @@ uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
uint64_t dt2;
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- dt2 = FP_TO_INT64_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float64_is_any_nan(fdt0)) {
+ dt2 = 0;
+ } else {
+ if (float64_is_neg(fdt0))
+ dt2 = INT64_MIN;
+ else
+ dt2 = INT64_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return dt2;
@@ -2634,14 +2648,29 @@ uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0)
uint64_t dt2;
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- dt2 = FP_TO_INT64_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float32_is_any_nan(fst0)) {
+ dt2 = 0;
+ } else {
+ if (float32_is_neg(fst0))
+ dt2 = INT64_MIN;
+ else
+ dt2 = INT64_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return dt2;
}
+
uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
{
uint32_t fst2;
@@ -2729,9 +2758,23 @@ uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
uint32_t wt2;
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- wt2 = FP_TO_INT32_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float32_is_any_nan(fst0)) {
+ wt2 = 0;
+ } else {
+ if (float32_is_neg(fst0))
+ wt2 = INT32_MIN;
+ else
+ wt2 = INT32_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return wt2;
@@ -2742,9 +2785,23 @@ uint32_t helper_float_cvtw_d(CPUMIPSState *env, uint64_t fdt0)
uint32_t wt2;
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- wt2 = FP_TO_INT32_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float64_is_any_nan(fdt0)) {
+ wt2 = 0;
+ } else {
+ if (float64_is_neg(fdt0))
+ wt2 = INT32_MIN;
+ else
+ wt2 = INT32_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return wt2;
@@ -2757,9 +2814,23 @@ uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- dt2 = FP_TO_INT64_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float64_is_any_nan(fdt0)) {
+ dt2 = 0;
+ } else {
+ if (float64_is_neg(fdt0))
+ dt2 = INT64_MIN;
+ else
+ dt2 = INT64_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return dt2;
@@ -2772,9 +2843,23 @@ uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- dt2 = FP_TO_INT64_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float32_is_any_nan(fst0)) {
+ dt2 = 0;
+ } else {
+ if (float32_is_neg(fst0))
+ dt2 = INT64_MIN;
+ else
+ dt2 = INT64_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return dt2;
@@ -2787,9 +2872,23 @@ uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- wt2 = FP_TO_INT32_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float64_is_any_nan(fdt0)) {
+ wt2 = 0;
+ } else {
+ if (float64_is_neg(fdt0))
+ wt2 = INT32_MIN;
+ else
+ wt2 = INT32_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return wt2;
@@ -2802,9 +2901,23 @@ uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- wt2 = FP_TO_INT32_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float32_is_any_nan(fst0)) {
+ wt2 = 0;
+ } else {
+ if (float32_is_neg(fst0))
+ wt2 = INT32_MIN;
+ else
+ wt2 = INT32_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return wt2;
@@ -2815,9 +2928,23 @@ uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
uint64_t dt2;
dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- dt2 = FP_TO_INT64_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float64_is_any_nan(fdt0)) {
+ dt2 = 0;
+ } else {
+ if (float64_is_neg(fdt0))
+ dt2 = INT64_MIN;
+ else
+ dt2 = INT64_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return dt2;
@@ -2828,9 +2955,23 @@ uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
uint64_t dt2;
dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- dt2 = FP_TO_INT64_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float32_is_any_nan(fst0)) {
+ dt2 = 0;
+ } else {
+ if (float32_is_neg(fst0))
+ dt2 = INT64_MIN;
+ else
+ dt2 = INT64_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return dt2;
@@ -2841,9 +2982,23 @@ uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
uint32_t wt2;
wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- wt2 = FP_TO_INT32_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float64_is_any_nan(fdt0)) {
+ wt2 = 0;
+ } else {
+ if (float64_is_neg(fdt0))
+ wt2 = INT32_MIN;
+ else
+ wt2 = INT32_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return wt2;
@@ -2854,9 +3009,23 @@ uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
uint32_t wt2;
wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- wt2 = FP_TO_INT32_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float32_is_any_nan(fst0)) {
+ wt2 = 0;
+ } else {
+ if (float32_is_neg(fst0))
+ wt2 = INT32_MIN;
+ else
+ wt2 = INT32_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return wt2;
@@ -2869,9 +3038,23 @@ uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- dt2 = FP_TO_INT64_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float64_is_any_nan(fdt0)) {
+ dt2 = 0;
+ } else {
+ if (float64_is_neg(fdt0))
+ dt2 = INT64_MIN;
+ else
+ dt2 = INT64_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return dt2;
@@ -2884,9 +3067,23 @@ uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- dt2 = FP_TO_INT64_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float32_is_any_nan(fst0)) {
+ dt2 = 0;
+ } else {
+ if (float32_is_neg(fst0))
+ dt2 = INT64_MIN;
+ else
+ dt2 = INT64_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return dt2;
@@ -2899,9 +3096,23 @@ uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- wt2 = FP_TO_INT32_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float64_is_any_nan(fdt0)) {
+ wt2 = 0;
+ } else {
+ if (float64_is_neg(fdt0))
+ wt2 = INT32_MIN;
+ else
+ wt2 = INT32_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return wt2;
@@ -2914,9 +3125,23 @@ uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- wt2 = FP_TO_INT32_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float32_is_any_nan(fst0)) {
+ wt2 = 0;
+ } else {
+ if (float32_is_neg(fst0))
+ wt2 = INT32_MIN;
+ else
+ wt2 = INT32_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return wt2;
@@ -2929,9 +3154,23 @@ uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- dt2 = FP_TO_INT64_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float64_is_any_nan(fdt0)) {
+ dt2 = 0;
+ } else {
+ if (float64_is_neg(fdt0))
+ dt2 = INT64_MIN;
+ else
+ dt2 = INT64_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return dt2;
@@ -2944,9 +3183,23 @@ uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- dt2 = FP_TO_INT64_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float32_is_any_nan(fst0)) {
+ dt2 = 0;
+ } else {
+ if (float32_is_neg(fst0))
+ dt2 = INT64_MIN;
+ else
+ dt2 = INT64_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return dt2;
@@ -2959,9 +3212,23 @@ uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- wt2 = FP_TO_INT32_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float64_is_any_nan(fdt0)) {
+ wt2 = 0;
+ } else {
+ if (float64_is_neg(fdt0))
+ wt2 = INT32_MIN;
+ else
+ wt2 = INT32_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return wt2;
@@ -2974,36 +3241,121 @@ uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
restore_rounding_mode(env);
- if (get_float_exception_flags(&env->active_fpu.fp_status)
- & (float_flag_invalid | float_flag_overflow)) {
- wt2 = FP_TO_INT32_OVERFLOW;
+ if (env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ if (float32_is_any_nan(fst0)) {
+ wt2 = 0;
+ } else {
+ if (float32_is_neg(fst0))
+ wt2 = INT32_MIN;
+ else
+ wt2 = INT32_MAX;
+ }
+ }
+ } else {
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
}
update_fcr31(env, GETPC());
return wt2;
}
-/* unary operations, not modifying fp status */
-#define FLOAT_UNOP(name) \
-uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
-{ \
- return float64_ ## name(fdt0); \
-} \
-uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
-{ \
- return float32_ ## name(fst0); \
-} \
-uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
-{ \
- uint32_t wt0; \
- uint32_t wth0; \
- \
- wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
- wth0 = float32_ ## name(fdt0 >> 32); \
- return ((uint64_t)wth0 << 32) | wt0; \
-}
-FLOAT_UNOP(abs)
-FLOAT_UNOP(chs)
-#undef FLOAT_UNOP
+uint64_t helper_float_abs_d(CPUMIPSState *env, uint64_t fdt0)
+{
+ uint64_t fdt1;
+
+ if (env->active_fpu.fcr31 & (1 << FCR31_ABS2008)) {
+ fdt1 = float64_abs(fdt0);
+ } else {
+ if (float64_is_neg(fdt0)) {
+ fdt1 = float64_sub(0, fdt0, &env->active_fpu.fp_status);
+ } else {
+ fdt1 = float64_add(0, fdt0, &env->active_fpu.fp_status);
+ }
+ update_fcr31(env, GETPC());
+ }
+ return fdt1;
+}
+
+uint32_t helper_float_abs_s(CPUMIPSState *env, uint32_t fst0)
+{
+ uint32_t fst1;
+
+ if (env->active_fpu.fcr31 & (1 << FCR31_ABS2008)) {
+ fst1 = float32_abs(fst0);
+ } else {
+ if (float32_is_neg(fst0)) {
+ fst1 = float32_sub(0, fst0, &env->active_fpu.fp_status);
+ } else {
+ fst1 = float32_add(0, fst0, &env->active_fpu.fp_status);
+ }
+ update_fcr31(env, GETPC());
+ }
+ return fst1;
+}
+
+uint64_t helper_float_abs_ps(CPUMIPSState *env, uint64_t fpst0)
+{
+ uint32_t fst0 = fpst0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fpst0 >> 32;
+ uint32_t fst1;
+ uint32_t fsth1;
+
+ if (float32_is_neg(fst0)) {
+ fst1 = float32_sub(0, fst0, &env->active_fpu.fp_status);
+ } else {
+ fst1 = float32_add(0, fst0, &env->active_fpu.fp_status);
+ }
+ if (float32_is_neg(fsth0)) {
+ fsth1 = float32_sub(0, fsth0, &env->active_fpu.fp_status);
+ } else {
+ fsth1 = float32_add(0, fsth0, &env->active_fpu.fp_status);
+ }
+ update_fcr31(env, GETPC());
+ return ((uint64_t)fsth1 << 32) | fst1;
+}
+
+uint64_t helper_float_chs_d(CPUMIPSState *env, uint64_t fdt0)
+{
+ uint64_t fdt1;
+
+ if (env->active_fpu.fcr31 & (1 << FCR31_ABS2008)) {
+ fdt1 = float64_chs(fdt0);
+ } else {
+ fdt1 = float64_sub(0, fdt0, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ }
+ return fdt1;
+}
+
+uint32_t helper_float_chs_s(CPUMIPSState *env, uint32_t fst0)
+{
+ uint32_t fst1;
+
+ if (env->active_fpu.fcr31 & (1 << FCR31_ABS2008)) {
+ fst1 = float32_chs(fst0);
+ } else {
+ fst1 = float32_sub(0, fst0, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ }
+ return fst1;
+}
+
+uint64_t helper_float_chs_ps(CPUMIPSState *env, uint64_t fpst0)
+{
+ uint32_t fst0 = fpst0 & 0XFFFFFFFF;
+ uint32_t fsth0 = fpst0 >> 32;
+ uint32_t fst1;
+ uint32_t fsth1;
+
+ fst1 = float32_sub(0, fst0, &env->active_fpu.fp_status);
+ fsth1 = float32_sub(0, fsth0, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return ((uint64_t)fsth1 << 32) | fst1;
+}
/* MIPS specific unary operations */
uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
@@ -8792,7 +8792,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
TCGv_i32 fp0 = tcg_temp_new_i32();
gen_load_fpr32(ctx, fp0, fs);
- gen_helper_float_abs_s(fp0, fp0);
+ gen_helper_float_abs_s(fp0, cpu_env, fp0);
gen_store_fpr32(ctx, fp0, fd);
tcg_temp_free_i32(fp0);
}
@@ -8811,7 +8811,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
TCGv_i32 fp0 = tcg_temp_new_i32();
gen_load_fpr32(ctx, fp0, fs);
- gen_helper_float_chs_s(fp0, fp0);
+ gen_helper_float_chs_s(fp0, cpu_env, fp0);
gen_store_fpr32(ctx, fp0, fd);
tcg_temp_free_i32(fp0);
}
@@ -9282,7 +9282,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
TCGv_i64 fp0 = tcg_temp_new_i64();
gen_load_fpr64(ctx, fp0, fs);
- gen_helper_float_abs_d(fp0, fp0);
+ gen_helper_float_abs_d(fp0, cpu_env, fp0);
gen_store_fpr64(ctx, fp0, fd);
tcg_temp_free_i64(fp0);
}
@@ -9303,7 +9303,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
TCGv_i64 fp0 = tcg_temp_new_i64();
gen_load_fpr64(ctx, fp0, fs);
- gen_helper_float_chs_d(fp0, fp0);
+ gen_helper_float_chs_d(fp0, cpu_env, fp0);
gen_store_fpr64(ctx, fp0, fd);
tcg_temp_free_i64(fp0);
}
@@ -9794,7 +9794,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
TCGv_i64 fp0 = tcg_temp_new_i64();
gen_load_fpr64(ctx, fp0, fs);
- gen_helper_float_abs_ps(fp0, fp0);
+ gen_helper_float_abs_ps(fp0, cpu_env, fp0);
gen_store_fpr64(ctx, fp0, fd);
tcg_temp_free_i64(fp0);
}
@@ -9815,7 +9815,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
TCGv_i64 fp0 = tcg_temp_new_i64();
gen_load_fpr64(ctx, fp0, fs);
- gen_helper_float_chs_ps(fp0, fp0);
+ gen_helper_float_chs_ps(fp0, cpu_env, fp0);
gen_store_fpr64(ctx, fp0, fd);
tcg_temp_free_i64(fp0);
}
@@ -9934,7 +9934,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
}
break;
case OPC_CVT_S_PU:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -9956,7 +9956,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
}
break;
case OPC_CVT_S_PL:
- check_cp1_64bitmode(ctx);
+ check_ps(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -273,6 +273,7 @@ static const mips_def_t mips_defs[] =
.CP0_Status_rw_bitmask = 0x3678FF1F,
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
(1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+ .CP1_fcr31 = 0,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
@@ -303,6 +304,7 @@ static const mips_def_t mips_defs[] =
(0xff << CP0TCSt_TASID),
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
(1 << FCR0_D) | (1 << FCR0_S) | (0x95 << FCR0_PRID),
+ .CP1_fcr31 = 0,
.CP0_SRSCtl = (0xf << CP0SRSCtl_HSS),
.CP0_SRSConf0_rw_bitmask = 0x3fffffff,
.CP0_SRSConf0 = (1U << CP0SRSC0_M) | (0x3fe << CP0SRSC0_SRS3) |
@@ -343,6 +345,7 @@ static const mips_def_t mips_defs[] =
.CP0_Status_rw_bitmask = 0x3778FF1F,
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
(1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+ .CP1_fcr31 = 0,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP | ASE_DSPR2,
@@ -433,8 +436,7 @@ static const mips_def_t mips_defs[] =
},
{
/* A generic CPU supporting MIPS32 Release 6 ISA.
- FIXME: Support IEEE 754-2008 FP.
- Eventually this should be replaced by a real CPU model. */
+ FIXME: Eventually this should be replaced by a real CPU model. */
.name = "mips32r6-generic",
.CP0_PRid = 0x00010000,
.CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AR) |
@@ -484,6 +486,7 @@ static const mips_def_t mips_defs[] =
.CP0_Status_rw_bitmask = 0x3678FFFF,
/* The R4000 has a full 64bit FPU but doesn't use the fcr0 bits. */
.CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV),
+ .CP1_fcr31 = 0,
.SEGBITS = 40,
.PABITS = 36,
.insn_flags = CPU_MIPS3,
@@ -502,6 +505,7 @@ static const mips_def_t mips_defs[] =
.CP0_Status_rw_bitmask = 0x3678FFFF,
/* The VR5432 has a full 64bit FPU but doesn't use the fcr0 bits. */
.CP1_fcr0 = (0x54 << FCR0_PRID) | (0x0 << FCR0_REV),
+ .CP1_fcr31 = 0,
.SEGBITS = 40,
.PABITS = 32,
.insn_flags = CPU_VR54XX,
@@ -547,6 +551,7 @@ static const mips_def_t mips_defs[] =
/* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */
.CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) |
(0x81 << FCR0_PRID) | (0x0 << FCR0_REV),
+ .CP1_fcr31 = 0,
.SEGBITS = 42,
.PABITS = 36,
.insn_flags = CPU_MIPS64,
@@ -574,6 +579,7 @@ static const mips_def_t mips_defs[] =
.CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) |
(1 << FCR0_D) | (1 << FCR0_S) |
(0x82 << FCR0_PRID) | (0x0 << FCR0_REV),
+ .CP1_fcr31 = 0,
.SEGBITS = 40,
.PABITS = 36,
.insn_flags = CPU_MIPS64 | ASE_MIPS3D,
@@ -600,6 +606,7 @@ static const mips_def_t mips_defs[] =
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |
(1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
+ .CP1_fcr31 = 0,
.SEGBITS = 42,
.PABITS = 36,
.insn_flags = CPU_MIPS64R2 | ASE_MIPS3D,
@@ -702,6 +709,7 @@ static const mips_def_t mips_defs[] =
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x35D0FFFF,
.CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV),
+ .CP1_fcr31 = 0,
.SEGBITS = 40,
.PABITS = 40,
.insn_flags = CPU_LOONGSON2E,
@@ -720,6 +728,7 @@ static const mips_def_t mips_defs[] =
.CCRes = 2,
.CP0_Status_rw_bitmask = 0xF5D0FF1F, /* Bits 7:5 not writable. */
.CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV),
+ .CP1_fcr31 = 0,
.SEGBITS = 40,
.PABITS = 40,
.insn_flags = CPU_LOONGSON2F,
@@ -747,6 +756,7 @@ static const mips_def_t mips_defs[] =
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |
(1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
+ .CP1_fcr31 = 0,
.SEGBITS = 42,
.PABITS = 36,
.insn_flags = CPU_MIPS64R2 | ASE_DSP | ASE_DSPR2,
@@ -834,7 +844,11 @@ static void fpu_init (CPUMIPSState *env, const mips_def_t *def)
for (i = 0; i < MIPS_FPU_MAX; i++) {
env->fpus[i].fcr0 = def->CP1_fcr0;
- set_snan_bit_is_one(1, &env->fpus[i].fp_status);
+ if (env->insn_flags & ISA_MIPS32R6) {
+ set_snan_bit_is_one(0, &env->fpus[i].fp_status);
+ } else {
+ set_snan_bit_is_one(1, &env->fpus[i].fp_status);
+ }
}
memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu));
@@ -893,5 +907,5 @@ static void msa_reset(CPUMIPSState *env)
/* clear float_status nan mode */
set_default_nan_mode(0, &env->active_tc.msa_fp_status);
- set_snan_bit_is_one(1, &env->active_tc.msa_fp_status);
+ set_snan_bit_is_one(0, &env->active_tc.msa_fp_status);
}