]> Git Repo - qemu.git/blobdiff - target-mips/op.c
Implemented cabs FP instructions, and improve exception handling for
[qemu.git] / target-mips / op.c
index 899892f68cb22a664e929d37c52470d289249b30..748f997d22c10601b3b71f64e24fcfa0f3dbb36f 100644 (file)
@@ -289,6 +289,22 @@ void op_store_LO (void)
 #undef MEMSUFFIX
 #endif
 
+/* Addresses computation */
+void op_addr_add (void)
+{
+/* For compatibility with 32-bit code, data reference in user mode
+   with Status_UX = 0 should be casted to 32-bit and sign extended.
+   See the MIPS64 PRA manual, section 4.10. */
+#ifdef TARGET_MIPS64
+    if ((env->CP0_Status & (1 << CP0St_UM)) &&
+        !(env->CP0_Status & (1 << CP0St_UX)))
+        T0 = (int64_t)(int32_t)(T0 + T1);
+    else
+#endif
+        T0 += T1;
+    RETURN();
+}
+
 /* Arithmetic */
 void op_add (void)
 {
@@ -1647,22 +1663,22 @@ unsigned int ieee_rm[] = {
 #define RESTORE_ROUNDING_MODE \
     set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
 
-inline char ieee_ex_to_mips(char ieee)
+inline char ieee_ex_to_mips(char xcpt)
 {
-    return (ieee & float_flag_inexact) >> 5 |
-           (ieee & float_flag_underflow) >> 3 |
-           (ieee & float_flag_overflow) >> 1 |
-           (ieee & float_flag_divbyzero) << 1 |
-           (ieee & float_flag_invalid) << 4;
+    return (xcpt & float_flag_inexact) >> 5 |
+           (xcpt & float_flag_underflow) >> 3 |
+           (xcpt & float_flag_overflow) >> 1 |
+           (xcpt & float_flag_divbyzero) << 1 |
+           (xcpt & float_flag_invalid) << 4;
 }
 
-inline char mips_ex_to_ieee(char mips)
+inline char mips_ex_to_ieee(char xcpt)
 {
-    return (mips & FP_INEXACT) << 5 |
-           (mips & FP_UNDERFLOW) << 3 |
-           (mips & FP_OVERFLOW) << 1 |
-           (mips & FP_DIV0) >> 1 |
-           (mips & FP_INVALID) >> 4;
+    return (xcpt & FP_INEXACT) << 5 |
+           (xcpt & FP_UNDERFLOW) << 3 |
+           (xcpt & FP_OVERFLOW) << 1 |
+           (xcpt & FP_DIV0) >> 1 |
+           (xcpt & FP_INVALID) >> 4;
 }
 
 inline void update_fcr31(void)
@@ -1949,6 +1965,9 @@ FLOAT_OP(roundl, d)
     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
     DT2 = float64_round_to_int(FDT0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -1957,6 +1976,9 @@ FLOAT_OP(roundl, s)
     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
     DT2 = float32_round_to_int(FST0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -1965,6 +1987,9 @@ FLOAT_OP(roundw, d)
     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
     WT2 = float64_round_to_int(FDT0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -1973,6 +1998,9 @@ FLOAT_OP(roundw, s)
     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
     WT2 = float32_round_to_int(FST0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -1980,24 +2008,36 @@ FLOAT_OP(roundw, s)
 FLOAT_OP(truncl, d)
 {
     DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(truncl, s)
 {
     DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(truncw, d)
 {
     WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(truncw, s)
 {
     WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -2007,6 +2047,9 @@ FLOAT_OP(ceill, d)
     set_float_rounding_mode(float_round_up, &env->fp_status);
     DT2 = float64_round_to_int(FDT0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -2015,6 +2058,9 @@ FLOAT_OP(ceill, s)
     set_float_rounding_mode(float_round_up, &env->fp_status);
     DT2 = float32_round_to_int(FST0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -2023,6 +2069,9 @@ FLOAT_OP(ceilw, d)
     set_float_rounding_mode(float_round_up, &env->fp_status);
     WT2 = float64_round_to_int(FDT0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -2031,6 +2080,9 @@ FLOAT_OP(ceilw, s)
     set_float_rounding_mode(float_round_up, &env->fp_status);
     WT2 = float32_round_to_int(FST0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -2040,6 +2092,9 @@ FLOAT_OP(floorl, d)
     set_float_rounding_mode(float_round_down, &env->fp_status);
     DT2 = float64_round_to_int(FDT0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -2048,6 +2103,9 @@ FLOAT_OP(floorl, s)
     set_float_rounding_mode(float_round_down, &env->fp_status);
     DT2 = float32_round_to_int(FST0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -2056,6 +2114,9 @@ FLOAT_OP(floorw, d)
     set_float_rounding_mode(float_round_down, &env->fp_status);
     WT2 = float64_round_to_int(FDT0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -2064,6 +2125,9 @@ FLOAT_OP(floorw, s)
     set_float_rounding_mode(float_round_down, &env->fp_status);
     WT2 = float32_round_to_int(FST0, &env->fp_status);
     RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -2169,6 +2233,7 @@ FLOAT_OP(name, d)         \
     FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);    \
     update_fcr31();       \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
 }                         \
 FLOAT_OP(name, s)         \
 {                         \
@@ -2176,6 +2241,7 @@ FLOAT_OP(name, s)         \
     FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
     update_fcr31();       \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
 }                         \
 FLOAT_OP(name, ps)        \
 {                         \
@@ -2184,6 +2250,7 @@ FLOAT_OP(name, ps)        \
     FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \
     update_fcr31();       \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
 }
 FLOAT_BINOP(add)
 FLOAT_BINOP(sub)
@@ -2191,6 +2258,16 @@ FLOAT_BINOP(mul)
 FLOAT_BINOP(div)
 #undef FLOAT_BINOP
 
+FLOAT_OP(addr, ps)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_add (FST0, FSTH0, &env->fp_status);
+    FSTH2 = float32_add (FST1, FSTH1, &env->fp_status);
+    update_fcr31();
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
 /* ternary operations */
 #define FLOAT_TERNOP(name1, name2) \
 FLOAT_OP(name1 ## name2, d)        \
@@ -2198,12 +2275,14 @@ FLOAT_OP(name1 ## name2, d)        \
     FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status);    \
     FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status);    \
     DEBUG_FPU_STATE();             \
+    RETURN();                      \
 }                                  \
 FLOAT_OP(name1 ## name2, s)        \
 {                                  \
     FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status);    \
     FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status);    \
     DEBUG_FPU_STATE();             \
+    RETURN();                      \
 }                                  \
 FLOAT_OP(name1 ## name2, ps)       \
 {                                  \
@@ -2212,28 +2291,65 @@ FLOAT_OP(name1 ## name2, ps)       \
     FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status);    \
     FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \
     DEBUG_FPU_STATE();             \
+    RETURN();                      \
 }
 FLOAT_TERNOP(mul, add)
 FLOAT_TERNOP(mul, sub)
 #undef FLOAT_TERNOP
 
+/* negated ternary operations */
+#define FLOAT_NTERNOP(name1, name2) \
+FLOAT_OP(n ## name1 ## name2, d)    \
+{                                   \
+    FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status);    \
+    FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status);    \
+    FDT2 ^= 1ULL << 63;             \
+    DEBUG_FPU_STATE();              \
+    RETURN();                       \
+}                                   \
+FLOAT_OP(n ## name1 ## name2, s)    \
+{                                   \
+    FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status);    \
+    FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status);    \
+    FST2 ^= 1 << 31;                \
+    DEBUG_FPU_STATE();              \
+    RETURN();                       \
+}                                   \
+FLOAT_OP(n ## name1 ## name2, ps)   \
+{                                   \
+    FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status);    \
+    FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \
+    FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status);    \
+    FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \
+    FST2 ^= 1 << 31;                \
+    FSTH2 ^= 1 << 31;               \
+    DEBUG_FPU_STATE();              \
+    RETURN();                       \
+}
+FLOAT_NTERNOP(mul, add)
+FLOAT_NTERNOP(mul, sub)
+#undef FLOAT_NTERNOP
+
 /* unary operations, modifying fp status  */
 #define FLOAT_UNOP(name)  \
 FLOAT_OP(name, d)         \
 {                         \
     FDT2 = float64_ ## name(FDT0, &env->fp_status);   \
     DEBUG_FPU_STATE();    \
+    RETURN();                      \
 }                         \
 FLOAT_OP(name, s)         \
 {                         \
     FST2 = float32_ ## name(FST0, &env->fp_status);   \
     DEBUG_FPU_STATE();    \
+    RETURN();                      \
 }                         \
 FLOAT_OP(name, ps)        \
 {                         \
     FST2 = float32_ ## name(FST0, &env->fp_status);   \
     FSTH2 = float32_ ## name(FSTH0, &env->fp_status); \
     DEBUG_FPU_STATE();    \
+    RETURN();                      \
 }
 FLOAT_UNOP(sqrt)
 #undef FLOAT_UNOP
@@ -2244,17 +2360,20 @@ FLOAT_OP(name, d)         \
 {                         \
     FDT2 = float64_ ## name(FDT0);   \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
 }                         \
 FLOAT_OP(name, s)         \
 {                         \
     FST2 = float32_ ## name(FST0);   \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
 }                         \
 FLOAT_OP(name, ps)        \
 {                         \
     FST2 = float32_ ## name(FST0);   \
     FSTH2 = float32_ ## name(FSTH0); \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
 }
 FLOAT_UNOP(abs)
 FLOAT_UNOP(chs)
@@ -2325,6 +2444,20 @@ void op_cmp_d_ ## op (void)                    \
         CLEAR_FP_COND(PARAM1, env);            \
     DEBUG_FPU_STATE();                         \
     RETURN();                                  \
+}                                              \
+void op_cmpabs_d_ ## op (void)                 \
+{                                              \
+    int c;                                     \
+    FDT0 &= ~(1ULL << 63);                     \
+    FDT1 &= ~(1ULL << 63);                     \
+    c = cond;                                  \
+    update_fcr31();                            \
+    if (c)                                     \
+        SET_FP_COND(PARAM1, env);              \
+    else                                       \
+        CLEAR_FP_COND(PARAM1, env);            \
+    DEBUG_FPU_STATE();                         \
+    RETURN();                                  \
 }
 
 int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
@@ -2373,6 +2506,20 @@ void op_cmp_s_ ## op (void)                    \
         CLEAR_FP_COND(PARAM1, env);            \
     DEBUG_FPU_STATE();                         \
     RETURN();                                  \
+}                                              \
+void op_cmpabs_s_ ## op (void)                 \
+{                                              \
+    int c;                                     \
+    FST0 &= ~(1 << 31);                        \
+    FST1 &= ~(1 << 31);                        \
+    c = cond;                                  \
+    update_fcr31();                            \
+    if (c)                                     \
+        SET_FP_COND(PARAM1, env);              \
+    else                                       \
+        CLEAR_FP_COND(PARAM1, env);            \
+    DEBUG_FPU_STATE();                         \
+    RETURN();                                  \
 }
 
 flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
@@ -2427,6 +2574,27 @@ void op_cmp_ps_ ## op (void)                   \
         CLEAR_FP_COND(PARAM1 + 1, env);        \
     DEBUG_FPU_STATE();                         \
     RETURN();                                  \
+}                                              \
+void op_cmpabs_ps_ ## op (void)                \
+{                                              \
+    int cl, ch;                                \
+    FST0 &= ~(1 << 31);                        \
+    FSTH0 &= ~(1 << 31);                       \
+    FST1 &= ~(1 << 31);                        \
+    FSTH1 &= ~(1 << 31);                       \
+    cl = condl;                                \
+    ch = condh;                                \
+    update_fcr31();                            \
+    if (cl)                                    \
+        SET_FP_COND(PARAM1, env);              \
+    else                                       \
+        CLEAR_FP_COND(PARAM1, env);            \
+    if (ch)                                    \
+        SET_FP_COND(PARAM1 + 1, env);          \
+    else                                       \
+        CLEAR_FP_COND(PARAM1 + 1, env);        \
+    DEBUG_FPU_STATE();                         \
+    RETURN();                                  \
 }
 
 /* NOTE: the comma operator will make "cond" to eval to false,
This page took 0.035896 seconds and 4 git commands to generate.