Implement recip1/recip2/rsqrt1/rsqrt2.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3026 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index e4f2676..9478225 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -597,6 +597,13 @@
 
 /* Complex FPU operations which may need stack space. */
 
+#define FLOAT_SIGN32 (1 << 31)
+#define FLOAT_SIGN64 (1ULL << 63)
+#define FLOAT_ONE32 (0x3f8 << 20)
+#define FLOAT_ONE64 (0x3ffULL << 52)
+#define FLOAT_TWO32 (1 << 30)
+#define FLOAT_TWO64 (1ULL << 62)
+
 /* convert MIPS rounding mode in FCR31 to IEEE library */
 unsigned int ieee_rm[] = {
     float_round_nearest_even,
@@ -912,58 +919,78 @@
         WT2 = 0x7fffffff;
 }
 
-/* unary operations, MIPS specific, s and d */
-#define FLOAT_UNOP(name)  \
-FLOAT_OP(name, d)         \
-{                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-/* XXX: not implemented */ \
-/*    FDT2 = float64_ ## name (FDT0, &env->fp_status);*/          \
-do_raise_exception(EXCP_RI); \
-    update_fcr31();       \
-}                         \
-FLOAT_OP(name, s)         \
-{                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-/* XXX: not implemented */ \
-/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
-do_raise_exception(EXCP_RI); \
-    update_fcr31();       \
+/* MIPS specific unary operations */
+FLOAT_OP(recip, d)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fp_status);
+    update_fcr31();
 }
-FLOAT_UNOP(rsqrt)
-FLOAT_UNOP(recip)
-#undef FLOAT_UNOP
+FLOAT_OP(recip, s)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status);
+    update_fcr31();
+}
 
-/* unary operations, MIPS specific, s, d and ps */
-#define FLOAT_UNOP(name)  \
-FLOAT_OP(name, d)         \
-{                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-/* XXX: not implemented */ \
-/*    FDT2 = float64_ ## name (FDT0, &env->fp_status);*/          \
-do_raise_exception(EXCP_RI); \
-    update_fcr31();       \
-}                         \
-FLOAT_OP(name, s)         \
-{                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-/* XXX: not implemented */ \
-/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
-do_raise_exception(EXCP_RI); \
-    update_fcr31();       \
-}                         \
-FLOAT_OP(name, ps)        \
-{                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-/* XXX: not implemented */ \
-/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
-/*    FSTH2 = float32_ ## name (FSTH0, &env->fp_status);*/        \
-do_raise_exception(EXCP_RI); \
-    update_fcr31();       \
+FLOAT_OP(rsqrt, d)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FDT2 = float64_sqrt(FDT0, &env->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fp_status);
+    update_fcr31();
 }
-FLOAT_UNOP(rsqrt1)
-FLOAT_UNOP(recip1)
-#undef FLOAT_UNOP
+FLOAT_OP(rsqrt, s)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_sqrt(FST0, &env->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status);
+    update_fcr31();
+}
+
+FLOAT_OP(recip1, d)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(recip1, s)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(recip1, ps)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status);
+    FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fp_status);
+    update_fcr31();
+}
+
+FLOAT_OP(rsqrt1, d)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FDT2 = float64_sqrt(FDT0, &env->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(rsqrt1, s)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_sqrt(FST0, &env->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(rsqrt1, ps)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_sqrt(FST0, &env->fp_status);
+    FSTH2 = float32_sqrt(FSTH0, &env->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status);
+    FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fp_status);
+    update_fcr31();
+}
 
 /* binary operations */
 #define FLOAT_BINOP(name) \
@@ -976,7 +1003,7 @@
         FDT2 = 0x7ff7ffffffffffffULL;                         \
     else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {       \
         if ((env->fcr31 & 0x3) == 0)                          \
-            FDT2 &= 0x8000000000000000ULL;                    \
+            FDT2 &= FLOAT_SIGN64;                             \
     }                     \
 }                         \
 FLOAT_OP(name, s)         \
@@ -988,7 +1015,7 @@
         FST2 = 0x7fbfffff;                                    \
     else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {       \
         if ((env->fcr31 & 0x3) == 0)                          \
-            FST2 &= 0x80000000ULL;                            \
+            FST2 &= FLOAT_SIGN32;                             \
     }                     \
 }                         \
 FLOAT_OP(name, ps)        \
@@ -1002,8 +1029,8 @@
         FSTH2 = 0x7fbfffff;                                   \
     } else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {     \
         if ((env->fcr31 & 0x3) == 0) {                        \
-            FST2 &= 0x80000000ULL;                            \
-            FSTH2 &= 0x80000000ULL;                           \
+            FST2 &= FLOAT_SIGN32;                             \
+            FSTH2 &= FLOAT_SIGN32;                            \
         }                 \
     }                     \
 }
@@ -1013,36 +1040,58 @@
 FLOAT_BINOP(div)
 #undef FLOAT_BINOP
 
-/* binary operations, MIPS specific */
-#define FLOAT_BINOP(name) \
-FLOAT_OP(name, d)         \
-{                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-/* XXX: not implemented */ \
-/*    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);*/    \
-do_raise_exception(EXCP_RI); \
-    update_fcr31();       \
-}                         \
-FLOAT_OP(name, s)         \
-{                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-/* XXX: not implemented */ \
-/*    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/    \
-do_raise_exception(EXCP_RI); \
-    update_fcr31();       \
-}                         \
-FLOAT_OP(name, ps)        \
-{                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-/* XXX: not implemented */ \
-/*    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/    \
-/*    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status);*/ \
-do_raise_exception(EXCP_RI); \
-    update_fcr31();       \
+/* MIPS specific binary operations */
+FLOAT_OP(recip2, d)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FDT2 = float64_mul(FDT0, FDT2, &env->fp_status);
+    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fp_status) ^ FLOAT_SIGN64;
+    update_fcr31();
 }
-FLOAT_BINOP(rsqrt2)
-FLOAT_BINOP(recip2)
-#undef FLOAT_BINOP
+FLOAT_OP(recip2, s)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32;
+    update_fcr31();
+}
+FLOAT_OP(recip2, ps)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fp_status);
+    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32;
+    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32;
+    update_fcr31();
+}
+
+FLOAT_OP(rsqrt2, d)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FDT2 = float64_mul(FDT0, FDT2, &env->fp_status);
+    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fp_status);
+    FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fp_status) ^ FLOAT_SIGN64;
+    update_fcr31();
+}
+FLOAT_OP(rsqrt2, s)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status);
+    FST2 = float32_div(FST2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32;
+    update_fcr31();
+}
+FLOAT_OP(rsqrt2, ps)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fp_status);
+    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status);
+    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fp_status);
+    FST2 = float32_div(FST2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32;
+    FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32;
+    update_fcr31();
+}
 
 FLOAT_OP(addr, ps)
 {
@@ -1060,6 +1109,7 @@
     update_fcr31();
 }
 
+/* compare operations */
 #define FOP_COND_D(op, cond)                   \
 void do_cmp_d_ ## op (long cc)                 \
 {                                              \
@@ -1073,8 +1123,8 @@
 void do_cmpabs_d_ ## op (long cc)              \
 {                                              \
     int c;                                     \
-    FDT0 &= ~(1ULL << 63);                     \
-    FDT1 &= ~(1ULL << 63);                     \
+    FDT0 &= ~FLOAT_SIGN64;                     \
+    FDT1 &= ~FLOAT_SIGN64;                     \
     c = cond;                                  \
     update_fcr31();                            \
     if (c)                                     \
@@ -1131,8 +1181,8 @@
 void do_cmpabs_s_ ## op (long cc)              \
 {                                              \
     int c;                                     \
-    FST0 &= ~(1 << 31);                        \
-    FST1 &= ~(1 << 31);                        \
+    FST0 &= ~FLOAT_SIGN32;                     \
+    FST1 &= ~FLOAT_SIGN32;                     \
     c = cond;                                  \
     update_fcr31();                            \
     if (c)                                     \
@@ -1194,10 +1244,10 @@
 void do_cmpabs_ps_ ## op (long cc)             \
 {                                              \
     int cl, ch;                                \
-    FST0 &= ~(1 << 31);                        \
-    FSTH0 &= ~(1 << 31);                       \
-    FST1 &= ~(1 << 31);                        \
-    FSTH1 &= ~(1 << 31);                       \
+    FST0 &= ~FLOAT_SIGN32;                     \
+    FSTH0 &= ~FLOAT_SIGN32;                    \
+    FST1 &= ~FLOAT_SIGN32;                     \
+    FSTH1 &= ~FLOAT_SIGN32;                    \
     cl = condl;                                \
     ch = condh;                                \
     update_fcr31();                            \
diff --git a/target-mips/translate.c b/target-mips/translate.c
index b5a8b5b..7f5141c 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -4551,7 +4551,7 @@
     case FOP(31, 16):
         check_cp1_64bitmode(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
-        GEN_LOAD_FREG_FTN(WT2, fd);
+        GEN_LOAD_FREG_FTN(WT2, ft);
         gen_op_float_rsqrt2_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "rsqrt2.s";
@@ -5036,8 +5036,8 @@
         check_cp1_64bitmode(ctx);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
-        GEN_LOAD_FREG_FTN(WT2, fd);
-        GEN_LOAD_FREG_FTN(WTH2, fd);
+        GEN_LOAD_FREG_FTN(WT2, ft);
+        GEN_LOAD_FREG_FTN(WTH2, ft);
         gen_op_float_rsqrt2_ps();
         GEN_STORE_FTN_FREG(fd, WT2);
         GEN_STORE_FTN_FREG(fd, WTH2);