commit 5a1e8ffbe746b2ba4fb8dbdebf3f99d2403fb53e
Author: ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Date:   Fri May 11 17:08:26 2007 +0000

    Implemented cabs FP instructions, and improve exception handling for
    trunc/floor/ceil/round.
    
    
    git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2804 c046a42c-6fe2-441c-8c8c-71466251a162

diff --git a/target-mips/op.c b/target-mips/op.c
index 15c541c..748f997 100644
--- a/target-mips/op.c
+++ b/target-mips/op.c
@@ -1965,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();
 }
@@ -1973,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();
 }
@@ -1981,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();
 }
@@ -1989,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();
 }
@@ -1996,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();
 }
@@ -2023,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();
 }
@@ -2031,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();
 }
@@ -2039,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();
 }
@@ -2047,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();
 }
@@ -2056,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();
 }
@@ -2064,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();
 }
@@ -2072,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();
 }
@@ -2080,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();
 }
@@ -2396,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)
@@ -2444,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)
@@ -2498,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,
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 94fce57..79a33c5 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -490,33 +490,36 @@ FGEN32(gen_op_store_fpr_WTH1, gen_op_store_fpr_WTH1_fpr);
 FGEN32(gen_op_load_fpr_WTH2,  gen_op_load_fpr_WTH2_fpr);
 FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr);
 
-#define FOP_CONDS(fmt) \
-static GenOpFunc1 * cond_ ## fmt ## _table[16] = {                      \
-    gen_op_cmp_ ## fmt ## _f,                                           \
-    gen_op_cmp_ ## fmt ## _un,                                          \
-    gen_op_cmp_ ## fmt ## _eq,                                          \
-    gen_op_cmp_ ## fmt ## _ueq,                                         \
-    gen_op_cmp_ ## fmt ## _olt,                                         \
-    gen_op_cmp_ ## fmt ## _ult,                                         \
-    gen_op_cmp_ ## fmt ## _ole,                                         \
-    gen_op_cmp_ ## fmt ## _ule,                                         \
-    gen_op_cmp_ ## fmt ## _sf,                                          \
-    gen_op_cmp_ ## fmt ## _ngle,                                        \
-    gen_op_cmp_ ## fmt ## _seq,                                         \
-    gen_op_cmp_ ## fmt ## _ngl,                                         \
-    gen_op_cmp_ ## fmt ## _lt,                                          \
-    gen_op_cmp_ ## fmt ## _nge,                                         \
-    gen_op_cmp_ ## fmt ## _le,                                          \
-    gen_op_cmp_ ## fmt ## _ngt,                                         \
+#define FOP_CONDS(type, fmt)                                            \
+static GenOpFunc1 * cond ## type ## _ ## fmt ## _table[16] = {          \
+    gen_op_cmp ## type ## _ ## fmt ## _f,                               \
+    gen_op_cmp ## type ## _ ## fmt ## _un,                              \
+    gen_op_cmp ## type ## _ ## fmt ## _eq,                              \
+    gen_op_cmp ## type ## _ ## fmt ## _ueq,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _olt,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _ult,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _ole,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _ule,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _sf,                              \
+    gen_op_cmp ## type ## _ ## fmt ## _ngle,                            \
+    gen_op_cmp ## type ## _ ## fmt ## _seq,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _ngl,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _lt,                              \
+    gen_op_cmp ## type ## _ ## fmt ## _nge,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _le,                              \
+    gen_op_cmp ## type ## _ ## fmt ## _ngt,                             \
 };                                                                      \
-static inline void gen_cmp_ ## fmt(int n, long cc)                      \
+static inline void gen_cmp ## type ## _ ## fmt(int n, long cc)          \
 {                                                                       \
-    cond_ ## fmt ## _table[n](cc);                                      \
+    cond ## type ## _ ## fmt ## _table[n](cc);                          \
 }
 
-FOP_CONDS(d)
-FOP_CONDS(s)
-FOP_CONDS(ps)
+FOP_CONDS(, d)
+FOP_CONDS(abs, d)
+FOP_CONDS(, s)
+FOP_CONDS(abs, s)
+FOP_CONDS(, ps)
+FOP_CONDS(abs, ps)
 
 typedef struct DisasContext {
     struct TranslationBlock *tb;
@@ -4453,7 +4456,25 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
             "c.le",
             "c.ngt",
     };
-    int binary = 0;
+    const char *condnames_abs[] = {
+            "cabs.f",
+            "cabs.un",
+            "cabs.eq",
+            "cabs.ueq",
+            "cabs.olt",
+            "cabs.ult",
+            "cabs.ole",
+            "cabs.ule",
+            "cabs.sf",
+            "cabs.ngle",
+            "cabs.seq",
+            "cabs.ngl",
+            "cabs.lt",
+            "cabs.nge",
+            "cabs.le",
+            "cabs.ngt",
+    };
+    enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP;
     uint32_t func = ctx->opcode & 0x3f;
 
     switch (ctx->opcode & FOP(0x3f, 0x1f)) {
@@ -4463,7 +4484,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         gen_op_float_add_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "add.s";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(1, 16):
         GEN_LOAD_FREG_FTN(WT0, fs);
@@ -4471,7 +4492,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         gen_op_float_sub_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "sub.s";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(2, 16):
         GEN_LOAD_FREG_FTN(WT0, fs);
@@ -4479,7 +4500,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         gen_op_float_mul_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "mul.s";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(3, 16):
         GEN_LOAD_FREG_FTN(WT0, fs);
@@ -4487,7 +4508,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         gen_op_float_div_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "div.s";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(4, 16):
         GEN_LOAD_FREG_FTN(WT0, fs);
@@ -4635,8 +4656,13 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
     case FOP(63, 16):
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
-        gen_cmp_s(func-48, cc);
-        opn = condnames[func-48];
+        if (ctx->opcode & (1 << 6)) {
+            gen_cmpabs_s(func-48, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_s(func-48, cc);
+            opn = condnames[func-48];
+        }
         break;
     case FOP(0, 17):
         CHECK_FR(ctx, fs | ft | fd);
@@ -4645,7 +4671,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         gen_op_float_add_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "add.d";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(1, 17):
         CHECK_FR(ctx, fs | ft | fd);
@@ -4654,7 +4680,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         gen_op_float_sub_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "sub.d";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(2, 17):
         CHECK_FR(ctx, fs | ft | fd);
@@ -4663,7 +4689,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         gen_op_float_mul_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "mul.d";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(3, 17):
         CHECK_FR(ctx, fs | ft | fd);
@@ -4672,7 +4698,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         gen_op_float_div_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "div.d";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(4, 17):
         CHECK_FR(ctx, fs | fd);
@@ -4801,8 +4827,13 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         CHECK_FR(ctx, fs | ft);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
-        gen_cmp_d(func-48, cc);
-        opn = condnames[func-48];
+        if (ctx->opcode & (1 << 6)) {
+            gen_cmpabs_d(func-48, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_d(func-48, cc);
+            opn = condnames[func-48];
+        }
         break;
     case FOP(32, 17):
         CHECK_FR(ctx, fs);
@@ -5042,18 +5073,30 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         GEN_LOAD_FREG_FTN(WTH1, ft);
-        gen_cmp_ps(func-48, cc);
-        opn = condnames[func-48];
+        if (ctx->opcode & (1 << 6)) {
+            gen_cmpabs_ps(func-48, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_ps(func-48, cc);
+            opn = condnames[func-48];
+        }
         break;
     default:
         MIPS_INVAL(opn);
         generate_exception (ctx, EXCP_RI);
         return;
     }
-    if (binary)
+    switch (optype) {
+    case BINOP:
         MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
-    else
+        break;
+    case CMPOP:
+        MIPS_DEBUG("%s %s,%s", opn, fregnames[fs], fregnames[ft]);
+        break;
+    default:
         MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
+        break;
+    }
 }
 
 /* Coprocessor 3 (FPU) */
