commit d7e4b87e53923542c1a7220e08bcae2252f5a22e
Author: j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Date:   Sun Sep 30 01:11:48 2007 +0000

    Implement new floating-point instructions (fre, frin, friz, frip, frim)
      as defined in the PowerPC 2.04 specification.
    
    
    git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3281 c046a42c-6fe2-441c-8c8c-71466251a162

diff --git a/target-ppc/op.c b/target-ppc/op.c
index 4622534..46843d7 100644
--- a/target-ppc/op.c
+++ b/target-ppc/op.c
@@ -1701,6 +1701,13 @@ void OPPROTO op_fsqrt (void)
     RETURN();
 }
 
+/* fre - fre. */
+void OPPROTO op_fre (void)
+{
+    do_fre();
+    RETURN();
+}
+
 /* fres - fres. */
 void OPPROTO op_fres (void)
 {
@@ -1806,6 +1813,30 @@ void OPPROTO op_fctidz (void)
 }
 #endif
 
+void OPPROTO op_frin (void)
+{
+    do_frin();
+    RETURN();
+}
+
+void OPPROTO op_friz (void)
+{
+    do_friz();
+    RETURN();
+}
+
+void OPPROTO op_frip (void)
+{
+    do_frip();
+    RETURN();
+}
+
+void OPPROTO op_frim (void)
+{
+    do_frim();
+    RETURN();
+}
+
 /***                         Floating-Point compare                        ***/
 /* fcmpu */
 void OPPROTO op_fcmpu (void)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 9a79953..08441ca 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -700,6 +700,36 @@ void do_fctidz (void)
 
 #endif
 
+static inline void do_fri (int rounding_mode)
+{
+    int curmode;
+
+    curmode = env->fp_status.float_rounding_mode;
+    set_float_rounding_mode(rounding_mode, &env->fp_status);
+    FT0 = float64_round_to_int(FT0, &env->fp_status);
+    set_float_rounding_mode(curmode, &env->fp_status);
+}
+
+void do_frin (void)
+{
+    do_fri(float_round_nearest_even);
+}
+
+void do_friz (void)
+{
+    do_fri(float_round_to_zero);
+}
+
+void do_frip (void)
+{
+    do_fri(float_round_up);
+}
+
+void do_frim (void)
+{
+    do_fri(float_round_down);
+}
+
 #if USE_PRECISE_EMULATION
 void do_fmadd (void)
 {
@@ -789,6 +819,32 @@ void do_fsqrt (void)
     FT0 = float64_sqrt(FT0, &env->fp_status);
 }
 
+void do_fre (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    if (likely(isnormal(FT0))) {
+        FT0 = float64_div(1.0, FT0, &env->fp_status);
+    } else {
+        p.d = FT0;
+        if (p.i == 0x8000000000000000ULL) {
+            p.i = 0xFFF0000000000000ULL;
+        } else if (p.i == 0x0000000000000000ULL) {
+            p.i = 0x7FF0000000000000ULL;
+        } else if (isnan(FT0)) {
+            p.i = 0x7FF8000000000000ULL;
+        } else if (FT0 < 0.0) {
+            p.i = 0x8000000000000000ULL;
+        } else {
+            p.i = 0x0000000000000000ULL;
+        }
+        FT0 = p.d;
+    }
+}
+
 void do_fres (void)
 {
     union {
diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h
index 4db8ac5..6c0d2fb 100644
--- a/target-ppc/op_helper.h
+++ b/target-ppc/op_helper.h
@@ -94,6 +94,7 @@ void do_popcntb_64 (void);
 
 /* Floating-point arithmetic helpers */
 void do_fsqrt (void);
+void do_fre (void);
 void do_fres (void);
 void do_frsqrte (void);
 void do_fsel (void);
@@ -110,6 +111,10 @@ void do_fcfid (void);
 void do_fctid (void);
 void do_fctidz (void);
 #endif
+void do_frin (void);
+void do_friz (void);
+void do_frip (void);
+void do_frim (void);
 void do_fcmpu (void);
 void do_fcmpo (void);
 
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 7f84ed7..f4ff22e 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -476,6 +476,8 @@ enum {
     PPC_RFMCI         = 0x0000020000000000ULL,
     /* user-mode DCR access, implemented in PowerPC 460 */
     PPC_DCRUX         = 0x0000040000000000ULL,
+    /* New floating-point extensions (PowerPC 2.0x)     */
+    PPC_FLOAT_EXT     = 0x0000080000000000ULL,
 };
 
 /*****************************************************************************/
@@ -1660,6 +1662,9 @@ GEN_FLOAT_AB(div, 0x12, 0x000007C0);
 /* fmul - fmuls */
 GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
 
+/* fre */
+GEN_FLOAT_BS(re, 0x3F, 0x18, PPC_FLOAT_EXT);
+
 /* fres */
 GEN_FLOAT_BS(res, 0x3B, 0x18, PPC_FLOAT_FRES);
 
@@ -1727,6 +1732,15 @@ GEN_FLOAT_B(ctid, 0x0E, 0x19, PPC_64B);
 GEN_FLOAT_B(ctidz, 0x0F, 0x19, PPC_64B);
 #endif
 
+/* frin */
+GEN_FLOAT_B(rin, 0x08, 0x0C, PPC_FLOAT_EXT);
+/* friz */
+GEN_FLOAT_B(riz, 0x08, 0x0D, PPC_FLOAT_EXT);
+/* frip */
+GEN_FLOAT_B(rip, 0x08, 0x0E, PPC_FLOAT_EXT);
+/* frim */
+GEN_FLOAT_B(rim, 0x08, 0x0F, PPC_FLOAT_EXT);
+
 /***                         Floating-Point compare                        ***/
 /* fcmpo */
 GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
