]> Git Repo - qemu.git/blobdiff - target/xtensa/fpu_helper.c
*: Use fprintf between qemu_log_trylock/unlock
[qemu.git] / target / xtensa / fpu_helper.c
index 87487293f9a15f3f13e386df1cd3937e7d562c88..d2a10cc797302ec54945e933d776fd0d16a6d421 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/log.h"
 #include "qemu/main-loop.h"
 #include "cpu.h"
 #include "exec/helper-proto.h"
 #include "exec/exec-all.h"
 #include "fpu/softfloat.h"
 
-void HELPER(wur_fcr)(CPUXtensaState *env, uint32_t v)
+enum {
+    XTENSA_FP_I = 0x1,
+    XTENSA_FP_U = 0x2,
+    XTENSA_FP_O = 0x4,
+    XTENSA_FP_Z = 0x8,
+    XTENSA_FP_V = 0x10,
+};
+
+enum {
+    XTENSA_FCR_FLAGS_SHIFT = 2,
+    XTENSA_FSR_FLAGS_SHIFT = 7,
+};
+
+static const struct {
+    uint32_t xtensa_fp_flag;
+    int softfloat_fp_flag;
+} xtensa_fp_flag_map[] = {
+    { XTENSA_FP_I, float_flag_inexact, },
+    { XTENSA_FP_U, float_flag_underflow, },
+    { XTENSA_FP_O, float_flag_overflow, },
+    { XTENSA_FP_Z, float_flag_divbyzero, },
+    { XTENSA_FP_V, float_flag_invalid, },
+};
+
+void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
 {
     static const int rounding_mode[] = {
         float_round_nearest_even,
@@ -46,121 +71,379 @@ void HELPER(wur_fcr)(CPUXtensaState *env, uint32_t v)
     set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
 }
 
+void HELPER(wur_fpu_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,
+    };
+
+    if (v & 0xfffff000) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "MBZ field of FCR is written non-zero: %08x\n", v);
+    }
+    env->uregs[FCR] = v & 0x0000007f;
+    set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
+}
+
+void HELPER(wur_fpu_fsr)(CPUXtensaState *env, uint32_t v)
+{
+    uint32_t flags = v >> XTENSA_FSR_FLAGS_SHIFT;
+    int fef = 0;
+    unsigned i;
+
+    if (v & 0xfffff000) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "MBZ field of FSR is written non-zero: %08x\n", v);
+    }
+    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);
+}
+
+uint32_t HELPER(rur_fpu_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;
+        }
+    }
+    env->uregs[FSR] = flags << XTENSA_FSR_FLAGS_SHIFT;
+    return flags << XTENSA_FSR_FLAGS_SHIFT;
+}
+
+float64 HELPER(abs_d)(float64 v)
+{
+    return float64_abs(v);
+}
+
 float32 HELPER(abs_s)(float32 v)
 {
     return float32_abs(v);
 }
 
+float64 HELPER(neg_d)(float64 v)
+{
+    return float64_chs(v);
+}
+
 float32 HELPER(neg_s)(float32 v)
 {
     return float32_chs(v);
 }
 
+float32 HELPER(fpu2k_add_s)(CPUXtensaState *env, float32 a, float32 b)
+{
+    return float32_add(a, b, &env->fp_status);
+}
+
+float32 HELPER(fpu2k_sub_s)(CPUXtensaState *env, float32 a, float32 b)
+{
+    return float32_sub(a, b, &env->fp_status);
+}
+
+float32 HELPER(fpu2k_mul_s)(CPUXtensaState *env, float32 a, float32 b)
+{
+    return float32_mul(a, b, &env->fp_status);
+}
+
+float32 HELPER(fpu2k_madd_s)(CPUXtensaState *env,
+                             float32 a, float32 b, float32 c)
+{
+    return float32_muladd(b, c, a, 0, &env->fp_status);
+}
+
+float32 HELPER(fpu2k_msub_s)(CPUXtensaState *env,
+                             float32 a, float32 b, float32 c)
+{
+    return float32_muladd(b, c, a, float_muladd_negate_product,
+                          &env->fp_status);
+}
+
+float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b)
+{
+    set_use_first_nan(true, &env->fp_status);
+    return float64_add(a, b, &env->fp_status);
+}
+
 float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b)
 {
+    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
     return float32_add(a, b, &env->fp_status);
 }
 
+float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b)
+{
+    set_use_first_nan(true, &env->fp_status);
+    return float64_sub(a, b, &env->fp_status);
+}
+
 float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b)
 {
+    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
     return float32_sub(a, b, &env->fp_status);
 }
 
+float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b)
+{
+    set_use_first_nan(true, &env->fp_status);
+    return float64_mul(a, b, &env->fp_status);
+}
+
 float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b)
 {
+    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
     return float32_mul(a, b, &env->fp_status);
 }
 
+float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
+{
+    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    return float64_muladd(b, c, a, 0, &env->fp_status);
+}
+
 float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
 {
+    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
     return float32_muladd(b, c, a, 0, &env->fp_status);
 }
 
+float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
+{
+    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    return float64_muladd(b, c, a, float_muladd_negate_product,
+                          &env->fp_status);
+}
+
 float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
 {
+    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
     return float32_muladd(b, c, a, float_muladd_negate_product,
                           &env->fp_status);
 }
 
-uint32_t HELPER(ftoi)(float32 v, uint32_t rounding_mode, uint32_t scale)
+float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b)
+{
+    set_use_first_nan(true, &env->fp_status);
+    return float64_div(b, a, &env->fp_status);
+}
+
+float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b)
+{
+    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    return float32_div(b, a, &env->fp_status);
+}
+
+float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v)
+{
+    set_use_first_nan(true, &env->fp_status);
+    return float64_sqrt(v, &env->fp_status);
+}
+
+float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v)
+{
+    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    return float32_sqrt(v, &env->fp_status);
+}
+
+uint32_t HELPER(ftoi_d)(CPUXtensaState *env, float64 v,
+                        uint32_t rounding_mode, uint32_t scale)
+{
+    float_status fp_status = env->fp_status;
+    uint32_t res;
+
+    set_float_rounding_mode(rounding_mode, &fp_status);
+    res = float64_to_int32(float64_scalbn(v, scale, &fp_status), &fp_status);
+    set_float_exception_flags(get_float_exception_flags(&fp_status),
+                              &env->fp_status);
+    return res;
+}
+
+uint32_t HELPER(ftoi_s)(CPUXtensaState *env, float32 v,
+                        uint32_t rounding_mode, uint32_t scale)
 {
-    float_status fp_status = {0};
+    float_status fp_status = env->fp_status;
+    uint32_t res;
 
     set_float_rounding_mode(rounding_mode, &fp_status);
-    return float32_to_int32(float32_scalbn(v, scale, &fp_status), &fp_status);
+    res = float32_to_int32(float32_scalbn(v, scale, &fp_status), &fp_status);
+    set_float_exception_flags(get_float_exception_flags(&fp_status),
+                              &env->fp_status);
+    return res;
 }
 
-uint32_t HELPER(ftoui)(float32 v, uint32_t rounding_mode, uint32_t scale)
+uint32_t HELPER(ftoui_d)(CPUXtensaState *env, float64 v,
+                         uint32_t rounding_mode, uint32_t scale)
 {
-    float_status fp_status = {0};
+    float_status fp_status = env->fp_status;
+    float64 res;
+    uint32_t rv;
+
+    set_float_rounding_mode(rounding_mode, &fp_status);
+
+    res = float64_scalbn(v, scale, &fp_status);
+
+    if (float64_is_neg(v) && !float64_is_any_nan(v)) {
+        set_float_exception_flags(float_flag_invalid, &fp_status);
+        rv = float64_to_int32(res, &fp_status);
+    } else {
+        rv = float64_to_uint32(res, &fp_status);
+    }
+    set_float_exception_flags(get_float_exception_flags(&fp_status),
+                              &env->fp_status);
+    return rv;
+}
+
+uint32_t HELPER(ftoui_s)(CPUXtensaState *env, float32 v,
+                         uint32_t rounding_mode, uint32_t scale)
+{
+    float_status fp_status = env->fp_status;
     float32 res;
+    uint32_t rv;
 
     set_float_rounding_mode(rounding_mode, &fp_status);
 
     res = float32_scalbn(v, scale, &fp_status);
 
     if (float32_is_neg(v) && !float32_is_any_nan(v)) {
-        return float32_to_int32(res, &fp_status);
+        rv = float32_to_int32(res, &fp_status);
+        if (rv) {
+            set_float_exception_flags(float_flag_invalid, &fp_status);
+        }
     } else {
-        return float32_to_uint32(res, &fp_status);
+        rv = float32_to_uint32(res, &fp_status);
     }
+    set_float_exception_flags(get_float_exception_flags(&fp_status),
+                              &env->fp_status);
+    return rv;
+}
+
+float64 HELPER(itof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale)
+{
+    return float64_scalbn(int32_to_float64(v, &env->fp_status),
+                          (int32_t)scale, &env->fp_status);
 }
 
-float32 HELPER(itof)(CPUXtensaState *env, uint32_t v, uint32_t scale)
+float32 HELPER(itof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale)
 {
     return float32_scalbn(int32_to_float32(v, &env->fp_status),
                           (int32_t)scale, &env->fp_status);
 }
 
-float32 HELPER(uitof)(CPUXtensaState *env, uint32_t v, uint32_t scale)
+float64 HELPER(uitof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale)
+{
+    return float64_scalbn(uint32_to_float64(v, &env->fp_status),
+                          (int32_t)scale, &env->fp_status);
+}
+
+float32 HELPER(uitof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale)
 {
     return float32_scalbn(uint32_to_float32(v, &env->fp_status),
                           (int32_t)scale, &env->fp_status);
 }
 
-static inline void set_br(CPUXtensaState *env, bool v, uint32_t br)
+float64 HELPER(cvtd_s)(CPUXtensaState *env, float32 v)
 {
-    if (v) {
-        env->sregs[BR] |= br;
-    } else {
-        env->sregs[BR] &= ~br;
-    }
+    return float32_to_float64(v, &env->fp_status);
+}
+
+float32 HELPER(cvts_d)(CPUXtensaState *env, float64 v)
+{
+    return float64_to_float32(v, &env->fp_status);
+}
+
+uint32_t HELPER(un_d)(CPUXtensaState *env, float64 a, float64 b)
+{
+    return float64_unordered_quiet(a, b, &env->fp_status);
 }
 
-void HELPER(un_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
+uint32_t HELPER(un_s)(CPUXtensaState *env, float32 a, float32 b)
 {
-    set_br(env, float32_unordered_quiet(a, b, &env->fp_status), br);
+    return float32_unordered_quiet(a, b, &env->fp_status);
 }
 
-void HELPER(oeq_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
+uint32_t HELPER(oeq_d)(CPUXtensaState *env, float64 a, float64 b)
 {
-    set_br(env, float32_eq_quiet(a, b, &env->fp_status), br);
+    return float64_eq_quiet(a, b, &env->fp_status);
 }
 
-void HELPER(ueq_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
+uint32_t HELPER(oeq_s)(CPUXtensaState *env, float32 a, float32 b)
+{
+    return float32_eq_quiet(a, b, &env->fp_status);
+}
+
+uint32_t HELPER(ueq_d)(CPUXtensaState *env, float64 a, float64 b)
+{
+    FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
+
+    return v == float_relation_equal ||
+           v == float_relation_unordered;
+}
+
+uint32_t HELPER(ueq_s)(CPUXtensaState *env, float32 a, float32 b)
 {
     FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
-    set_br(env, v == float_relation_equal || v == float_relation_unordered, br);
+
+    return v == float_relation_equal ||
+           v == float_relation_unordered;
 }
 
-void HELPER(olt_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
+uint32_t HELPER(olt_d)(CPUXtensaState *env, float64 a, float64 b)
 {
-    set_br(env, float32_lt_quiet(a, b, &env->fp_status), br);
+    return float64_lt(a, b, &env->fp_status);
 }
 
-void HELPER(ult_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
+uint32_t HELPER(olt_s)(CPUXtensaState *env, float32 a, float32 b)
+{
+    return float32_lt(a, b, &env->fp_status);
+}
+
+uint32_t HELPER(ult_d)(CPUXtensaState *env, float64 a, float64 b)
+{
+    FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
+
+    return v == float_relation_less ||
+           v == float_relation_unordered;
+}
+
+uint32_t HELPER(ult_s)(CPUXtensaState *env, float32 a, float32 b)
 {
     FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
-    set_br(env, v == float_relation_less || v == float_relation_unordered, br);
+
+    return v == float_relation_less ||
+           v == float_relation_unordered;
 }
 
-void HELPER(ole_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
+uint32_t HELPER(ole_d)(CPUXtensaState *env, float64 a, float64 b)
 {
-    set_br(env, float32_le_quiet(a, b, &env->fp_status), br);
+    return float64_le(a, b, &env->fp_status);
 }
 
-void HELPER(ule_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b)
+uint32_t HELPER(ole_s)(CPUXtensaState *env, float32 a, float32 b)
+{
+    return float32_le(a, b, &env->fp_status);
+}
+
+uint32_t HELPER(ule_d)(CPUXtensaState *env, float64 a, float64 b)
+{
+    FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
+
+    return v != float_relation_greater;
+}
+
+uint32_t HELPER(ule_s)(CPUXtensaState *env, float32 a, float32 b)
 {
     FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
-    set_br(env, v != float_relation_greater, br);
+
+    return v != float_relation_greater;
 }
This page took 0.037014 seconds and 4 git commands to generate.