Add support for the IEEE 754-2008 features introduced to revision 3.50 
[1][2] of the MIPS Architecture as follows.

1. IEEE 754-2008 NaN encoding.

   Implement the CP1.FCSR.NAN2008 bit with the expected intepretation.  
   Update code to handle CP1.FCSR.NAN2008 correctly in CTC1 and the GDB 
   stub, and to respect the bit in SoftFloat and integer conversion 
   operations.  Strap MSA operations to the 2008-NaN mode as per the MSA 
   architecture specification [3]; the MSACSR register has no 
   corresponding NAN2008 bit.

   Configure CP1.FCSR.NAN2008 at startup in the Linux user emulation 
   mode according to the value of the EF_MIPS_NAN2008 ELF file header 
   flag of the executable invoked, or reject it if the requested NaN 
   mode is not supported by the processor selected for emulation.

2. IEEE 754-2008 non-arithmetic ABS and NEG instructions.

   Reimplement legacy ABS.fmt and NEG.fmt instructions as arithmetic, as 
   defined by the MIPS Architecture.  Implement the CP1.FCSR.ABS2008 
   bits with the expected intepretation.  Update code to respect the bit 
   in the implementation of the ABS.fmt and NEG.fmt instructions.

Implement the CP1.FIR.HAS2008 bit with the expected meaning.  Implement 
a CP1.FCSR reset value and r/w bit mask so that NAN2008 and ABS2008 bits 
can be r/o or r/w and preset as required; as a side effect correctly 
handle the remaining CP1.FCSR bits that can be r/o or r/w depending on 
the architecture level, specifically FCC[7:1]; FS could benefit sometime 
too.

References:

[1] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
    MIPS32 Architecture", MIPS Technologies, Inc., Document Number:
    MD00082, Revision 3.50, September 20, 2012, Section 2.1.2.3 "MIPSr3
    Architecture", p. 21

[2] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
    MIPS64 Architecture", MIPS Technologies, Inc., Document Number:
    MD00083, Revision 3.50, September 20, 2012, Section 2.1.2.3 "MIPSr3
    Architecture", p. 21

[3] "MIPS Architecture for Programmers, Volume IV-j: The MIPS32 SIMD
    Architecture Module", MIPS Technologies, Inc., Document Number:
    MD00866, Revision 1.07, October 2, 2013, Section 3.3.2 
    "Floating-Point Registers Mapping", p. 38

Signed-off-by: Thomas Schwinge <tho...@codesourcery.com>
Signed-off-by: Maciej W. Rozycki <ma...@codesourcery.com>
---
 Shall I post the artificial *-nan2008 processors we've been using for 
testing or will you be adding real CPU templates with CP1.FCSR NAN2008 
and ABS2008 bits writable?

  Maciej

qemu-mips-nan2008.diff
Index: qemu-git-trunk/include/elf.h
===================================================================
--- qemu-git-trunk.orig/include/elf.h   2014-12-08 23:22:12.000000000 +0000
+++ qemu-git-trunk/include/elf.h        2014-12-08 23:25:02.558929097 +0000
@@ -53,6 +53,7 @@ typedef int64_t  Elf64_Sxword;
 #define EF_MIPS_ABI2           0x00000020
 #define EF_MIPS_OPTIONS_FIRST  0x00000080
 #define EF_MIPS_32BITMODE      0x00000100
+#define EF_MIPS_NAN2008         0x00000400
 #define EF_MIPS_ABI            0x0000f000
 #define EF_MIPS_ARCH      0xf0000000
 
Index: qemu-git-trunk/linux-user/main.c
===================================================================
--- qemu-git-trunk.orig/linux-user/main.c       2014-12-08 23:22:12.000000000 
+0000
+++ qemu-git-trunk/linux-user/main.c    2014-12-09 00:48:02.598941233 +0000
@@ -4342,6 +4342,18 @@ int main(int argc, char **argv, char **e
         if (regs->cp0_epc & 1) {
             env->hflags |= MIPS_HFLAG_M16;
         }
+        if (info->elf_flags & EF_MIPS_NAN2008)
+            env->active_fpu.fcr31 |=
+                (1 << FCR31_NAN2008) & env->active_fpu.fcr31_rw_bitmask;
+        else
+            env->active_fpu.fcr31 &=
+                ~((1 << FCR31_NAN2008) & env->active_fpu.fcr31_rw_bitmask);
+        if (((info->elf_flags & EF_MIPS_NAN2008) != 0) !=
+            ((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) != 0)) {
+            fprintf(stderr, "ELF binary's NaN mode not supported by CPU\n");
+            exit(1);
+        }
+        restore_nan_mode(env);
     }
 #elif defined(TARGET_OPENRISC)
     {
Index: qemu-git-trunk/target-mips/cpu.h
===================================================================
--- qemu-git-trunk.orig/target-mips/cpu.h       2014-12-08 23:22:12.000000000 
+0000
+++ qemu-git-trunk/target-mips/cpu.h    2014-12-08 23:25:02.558929097 +0000
@@ -102,6 +102,7 @@ struct CPUMIPSFPUContext {
     /* fpu implementation/revision register (fir) */
     uint32_t fcr0;
 #define FCR0_UFRP 28
+#define FCR0_HAS2008 23
 #define FCR0_F64 22
 #define FCR0_L 21
 #define FCR0_W 20
@@ -112,7 +113,10 @@ struct CPUMIPSFPUContext {
 #define FCR0_PRID 8
 #define FCR0_REV 0
     /* fcsr */
+    uint32_t fcr31_rw_bitmask;
     uint32_t fcr31;
+#define FCR31_ABS2008 19
+#define FCR31_NAN2008 18
 #define SET_FP_COND(num,env)     do { ((env).fcr31) |= ((num) ? (1 << ((num) + 
24)) : (1 << 23)); } while(0)
 #define CLEAR_FP_COND(num,env)   do { ((env).fcr31) &= ~((num) ? (1 << ((num) 
+ 24)) : (1 << 23)); } while(0)
 #define GET_FP_COND(env)         ((((env).fcr31 >> 24) & 0xfe) | (((env).fcr31 
>> 23) & 0x1))
@@ -793,6 +797,12 @@ static inline void restore_flush_mode(CP
                       &env->active_fpu.fp_status);
 }
 
+static inline void restore_nan_mode(CPUMIPSState *env)
+{
+    set_nan2008_mode((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) != 0,
+                          &env->active_fpu.fp_status);
+}
+
 extern target_ulong mdi_semihost_breakpoint;
 void do_mips_semihosting(CPUMIPSState *env);
 void install_semihosting_breakpoint(CPUState *cs, target_ulong bkpt_address);
Index: qemu-git-trunk/target-mips/gdbstub.c
===================================================================
--- qemu-git-trunk.orig/target-mips/gdbstub.c   2014-12-08 23:22:12.000000000 
+0000
+++ qemu-git-trunk/target-mips/gdbstub.c        2014-12-08 23:25:02.558929097 
+0000
@@ -91,11 +91,14 @@ int mips_cpu_gdb_write_register(CPUState
     if (env->CP0_Config1 & (1 << CP0C1_FP) && n >= 38 && n < 72) {
         switch (n) {
         case 70:
-            env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
+            env->active_fpu.fcr31 &= ~env->active_fpu.fcr31_rw_bitmask;
+            env->active_fpu.fcr31 |= tmp & env->active_fpu.fcr31_rw_bitmask;
             /* set rounding mode */
             restore_rounding_mode(env);
             /* set flush-to-zero mode */
             restore_flush_mode(env);
+            /* set NaN mode */
+            restore_nan_mode(env);
             break;
         case 71:
             /* FIR is read-only.  Ignore writes.  */
Index: qemu-git-trunk/target-mips/helper.h
===================================================================
--- qemu-git-trunk.orig/target-mips/helper.h    2014-12-08 23:22:12.000000000 
+0000
+++ qemu-git-trunk/target-mips/helper.h 2014-12-08 23:25:02.558929097 +0000
@@ -248,12 +248,20 @@ FOP_PROTO(recip)
 FOP_PROTO(rint)
 #undef FOP_PROTO
 
+#define FOP_PROTO(op)                            \
+DEF_HELPER_2(float_ ## op ## _s, i32, env, i32)  \
+DEF_HELPER_2(float_ ## op ## _d, i64, env, i64)  \
+DEF_HELPER_2(float_ ## op ## _ps, i64, env, i64)
+FOP_PROTO(abs)
+FOP_PROTO(chs)
+#undef FOP_PROTO
+
 #define FOP_PROTO(op)                       \
 DEF_HELPER_1(float_ ## op ## _s, i32, i32)  \
 DEF_HELPER_1(float_ ## op ## _d, i64, i64)  \
 DEF_HELPER_1(float_ ## op ## _ps, i64, i64)
-FOP_PROTO(abs)
-FOP_PROTO(chs)
+FOP_PROTO(abs2008)
+FOP_PROTO(chs2008)
 #undef FOP_PROTO
 
 #define FOP_PROTO(op)                            \
Index: qemu-git-trunk/target-mips/op_helper.c
===================================================================
--- qemu-git-trunk.orig/target-mips/op_helper.c 2014-12-08 23:22:12.000000000 
+0000
+++ qemu-git-trunk/target-mips/op_helper.c      2014-12-08 23:25:02.558929097 
+0000
@@ -2274,8 +2274,12 @@ void mips_cpu_unassigned_access(CPUState
 
 #define FLOAT_TWO32 make_float32(1 << 30)
 #define FLOAT_TWO64 make_float64(1ULL << 62)
-#define FP_TO_INT32_OVERFLOW 0x7fffffff
-#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
+#define FLOAT_INAN32(env)                                               \
+    (((env)->active_fpu.fcr31 & (1 << FCR31_NAN2008))                   \
+     ? 0x00000000 : 0x7fffffff)
+#define FLOAT_INAN64(env)                                               \
+    (((env)->active_fpu.fcr31 & (1 << FCR31_NAN2008))                   \
+     ? 0x0000000000000000ULL : 0x7fffffffffffffffULL)
 
 /* convert MIPS rounding mode in FCR31 to IEEE library */
 unsigned int ieee_rm[] = {
@@ -2367,13 +2371,8 @@ void helper_ctc1(CPUMIPSState *env, targ
                      ((arg1 & 0x4) << 22);
         break;
     case 31:
-        if (env->insn_flags & ISA_MIPS32R6) {
-            uint32_t mask = 0xfefc0000;
-            env->active_fpu.fcr31 = (arg1 & ~mask) |
-                (env->active_fpu.fcr31 & mask);
-        } else if (!(arg1 & 0x007c0000)) {
-            env->active_fpu.fcr31 = arg1;
-        }
+        env->active_fpu.fcr31 &= ~env->active_fpu.fcr31_rw_bitmask;
+        env->active_fpu.fcr31 |= arg1 & env->active_fpu.fcr31_rw_bitmask;
         break;
     default:
         return;
@@ -2382,6 +2381,8 @@ void helper_ctc1(CPUMIPSState *env, targ
     restore_rounding_mode(env);
     /* set flush-to-zero mode */
     restore_flush_mode(env);
+    /* set NaN mode */
+    restore_nan_mode(env);
     set_float_exception_flags(0, &env->active_fpu.fp_status);
     if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & 
GET_FP_CAUSE(env->active_fpu.fcr31))
         do_raise_exception(env, EXCP_FPE, GETPC());
@@ -2481,7 +2482,7 @@ uint64_t helper_float_cvtl_d(CPUMIPSStat
     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        dt2 = FP_TO_INT64_OVERFLOW;
+        dt2 = FLOAT_INAN64(env);
     }
     update_fcr31(env, GETPC());
     return dt2;
@@ -2494,7 +2495,7 @@ uint64_t helper_float_cvtl_s(CPUMIPSStat
     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        dt2 = FP_TO_INT64_OVERFLOW;
+        dt2 = FLOAT_INAN64(env);
     }
     update_fcr31(env, GETPC());
     return dt2;
@@ -2520,14 +2521,14 @@ uint64_t helper_float_cvtpw_ps(CPUMIPSSt
     wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
     excp = get_float_exception_flags(&env->active_fpu.fp_status);
     if (excp & (float_flag_overflow | float_flag_invalid)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
 
     set_float_exception_flags(0, &env->active_fpu.fp_status);
     wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
     excph = get_float_exception_flags(&env->active_fpu.fp_status);
     if (excph & (float_flag_overflow | float_flag_invalid)) {
-        wth2 = FP_TO_INT32_OVERFLOW;
+        wth2 = FLOAT_INAN32(env);
     }
 
     set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
@@ -2588,7 +2589,7 @@ uint32_t helper_float_cvtw_s(CPUMIPSStat
     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
     update_fcr31(env, GETPC());
     return wt2;
@@ -2601,7 +2602,7 @@ uint32_t helper_float_cvtw_d(CPUMIPSStat
     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
     update_fcr31(env, GETPC());
     return wt2;
@@ -2616,7 +2617,7 @@ uint64_t helper_float_roundl_d(CPUMIPSSt
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        dt2 = FP_TO_INT64_OVERFLOW;
+        dt2 = FLOAT_INAN64(env);
     }
     update_fcr31(env, GETPC());
     return dt2;
@@ -2631,7 +2632,7 @@ uint64_t helper_float_roundl_s(CPUMIPSSt
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        dt2 = FP_TO_INT64_OVERFLOW;
+        dt2 = FLOAT_INAN64(env);
     }
     update_fcr31(env, GETPC());
     return dt2;
@@ -2646,7 +2647,7 @@ uint32_t helper_float_roundw_d(CPUMIPSSt
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
     update_fcr31(env, GETPC());
     return wt2;
@@ -2661,7 +2662,7 @@ uint32_t helper_float_roundw_s(CPUMIPSSt
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
     update_fcr31(env, GETPC());
     return wt2;
@@ -2674,7 +2675,7 @@ uint64_t helper_float_truncl_d(CPUMIPSSt
     dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        dt2 = FP_TO_INT64_OVERFLOW;
+        dt2 = FLOAT_INAN64(env);
     }
     update_fcr31(env, GETPC());
     return dt2;
@@ -2687,7 +2688,7 @@ uint64_t helper_float_truncl_s(CPUMIPSSt
     dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        dt2 = FP_TO_INT64_OVERFLOW;
+        dt2 = FLOAT_INAN64(env);
     }
     update_fcr31(env, GETPC());
     return dt2;
@@ -2700,7 +2701,7 @@ uint32_t helper_float_truncw_d(CPUMIPSSt
     wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
     update_fcr31(env, GETPC());
     return wt2;
@@ -2713,7 +2714,7 @@ uint32_t helper_float_truncw_s(CPUMIPSSt
     wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
     update_fcr31(env, GETPC());
     return wt2;
@@ -2728,7 +2729,7 @@ uint64_t helper_float_ceill_d(CPUMIPSSta
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        dt2 = FP_TO_INT64_OVERFLOW;
+        dt2 = FLOAT_INAN64(env);
     }
     update_fcr31(env, GETPC());
     return dt2;
@@ -2743,7 +2744,7 @@ uint64_t helper_float_ceill_s(CPUMIPSSta
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        dt2 = FP_TO_INT64_OVERFLOW;
+        dt2 = FLOAT_INAN64(env);
     }
     update_fcr31(env, GETPC());
     return dt2;
@@ -2758,7 +2759,7 @@ uint32_t helper_float_ceilw_d(CPUMIPSSta
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
     update_fcr31(env, GETPC());
     return wt2;
@@ -2773,7 +2774,7 @@ uint32_t helper_float_ceilw_s(CPUMIPSSta
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
     update_fcr31(env, GETPC());
     return wt2;
@@ -2788,7 +2789,7 @@ uint64_t helper_float_floorl_d(CPUMIPSSt
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        dt2 = FP_TO_INT64_OVERFLOW;
+        dt2 = FLOAT_INAN64(env);
     }
     update_fcr31(env, GETPC());
     return dt2;
@@ -2803,7 +2804,7 @@ uint64_t helper_float_floorl_s(CPUMIPSSt
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        dt2 = FP_TO_INT64_OVERFLOW;
+        dt2 = FLOAT_INAN64(env);
     }
     update_fcr31(env, GETPC());
     return dt2;
@@ -2818,7 +2819,7 @@ uint32_t helper_float_floorw_d(CPUMIPSSt
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
     update_fcr31(env, GETPC());
     return wt2;
@@ -2833,23 +2834,23 @@ uint32_t helper_float_floorw_s(CPUMIPSSt
     restore_rounding_mode(env);
     if (get_float_exception_flags(&env->active_fpu.fp_status)
         & (float_flag_invalid | float_flag_overflow)) {
-        wt2 = FP_TO_INT32_OVERFLOW;
+        wt2 = FLOAT_INAN32(env);
     }
     update_fcr31(env, GETPC());
     return wt2;
 }
 
-/* unary operations, not modifying fp status  */
+/* IEEE 754-2008 unary operations, not modifying fp status.  */
 #define FLOAT_UNOP(name)                                       \
-uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
+uint64_t helper_float_ ## name ## 2008_d(uint64_t fdt0)        \
 {                                                              \
     return float64_ ## name(fdt0);                             \
 }                                                              \
-uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
+uint32_t helper_float_ ## name ## 2008_s(uint32_t fst0)        \
 {                                                              \
     return float32_ ## name(fst0);                             \
 }                                                              \
-uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
+uint64_t helper_float_ ## name ## 2008_ps(uint64_t fdt0)       \
 {                                                              \
     uint32_t wt0;                                              \
     uint32_t wth0;                                             \
@@ -2862,6 +2863,85 @@ FLOAT_UNOP(abs)
 FLOAT_UNOP(chs)
 #undef FLOAT_UNOP
 
+/* Legacy unary operations, arithmetic.  */
+uint64_t helper_float_abs_d(CPUMIPSState *env, uint64_t fdt0)
+{
+    uint64_t fdt1;
+
+    if (float64_is_neg(fdt0)) {
+        fdt1 = float64_sub(0, fdt0, &env->active_fpu.fp_status);
+    } else {
+        fdt1 = float64_add(0, fdt0, &env->active_fpu.fp_status);
+    }
+    update_fcr31(env, GETPC());
+    return fdt1;
+}
+
+uint32_t helper_float_abs_s(CPUMIPSState *env, uint32_t fst0)
+{
+    uint32_t fst1;
+
+    if (float32_is_neg(fst0)) {
+        fst1 = float32_sub(0, fst0, &env->active_fpu.fp_status);
+    } else {
+        fst1 = float32_add(0, fst0, &env->active_fpu.fp_status);
+    }
+    update_fcr31(env, GETPC());
+    return fst1;
+}
+
+uint64_t helper_float_abs_ps(CPUMIPSState *env, uint64_t fpst0)
+{
+    uint32_t fst0 = fpst0 & 0XFFFFFFFF;
+    uint32_t fsth0 = fpst0 >> 32;
+    uint32_t fst1;
+    uint32_t fsth1;
+
+    if (float32_is_neg(fst0)) {
+        fst1 = float32_sub(0, fst0, &env->active_fpu.fp_status);
+    } else {
+        fst1 = float32_add(0, fst0, &env->active_fpu.fp_status);
+    }
+    if (float32_is_neg(fsth0)) {
+        fsth1 = float32_sub(0, fsth0, &env->active_fpu.fp_status);
+    } else {
+        fsth1 = float32_add(0, fsth0, &env->active_fpu.fp_status);
+    }
+    update_fcr31(env, GETPC());
+    return ((uint64_t)fsth1 << 32) | fst1;
+}
+
+uint64_t helper_float_chs_d(CPUMIPSState *env, uint64_t fdt0)
+{
+    uint64_t fdt1;
+
+    fdt1 = float64_sub(0, fdt0, &env->active_fpu.fp_status);
+    update_fcr31(env, GETPC());
+    return fdt1;
+}
+
+uint32_t helper_float_chs_s(CPUMIPSState *env, uint32_t fst0)
+{
+    uint32_t fst1;
+
+    fst1 = float32_sub(0, fst0, &env->active_fpu.fp_status);
+    update_fcr31(env, GETPC());
+    return fst1;
+}
+
+uint64_t helper_float_chs_ps(CPUMIPSState *env, uint64_t fpst0)
+{
+    uint32_t fst0 = fpst0 & 0XFFFFFFFF;
+    uint32_t fsth0 = fpst0 >> 32;
+    uint32_t fst1;
+    uint32_t fsth1;
+
+    fst1 = float32_sub(0, fst0, &env->active_fpu.fp_status);
+    fsth1 = float32_sub(0, fsth0, &env->active_fpu.fp_status);
+    update_fcr31(env, GETPC());
+    return ((uint64_t)fsth1 << 32) | fst1;
+}
+
 /* MIPS specific unary operations */
 uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
 {
Index: qemu-git-trunk/target-mips/translate.c
===================================================================
--- qemu-git-trunk.orig/target-mips/translate.c 2014-12-08 23:22:12.000000000 
+0000
+++ qemu-git-trunk/target-mips/translate.c      2014-12-08 23:25:02.558929097 
+0000
@@ -1424,6 +1424,7 @@ typedef struct DisasContext {
     int ie;
     bool bi;
     bool bp;
+    bool abs2008;
 } DisasContext;
 
 enum {
@@ -8718,7 +8719,10 @@ static void gen_farith (DisasContext *ct
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
             gen_load_fpr32(fp0, fs);
-            gen_helper_float_abs_s(fp0, fp0);
+            if (ctx->abs2008)
+                gen_helper_float_abs2008_s(fp0, fp0);
+            else
+                gen_helper_float_abs_s(fp0, cpu_env, fp0);
             gen_store_fpr32(fp0, fd);
             tcg_temp_free_i32(fp0);
         }
@@ -8739,7 +8743,10 @@ static void gen_farith (DisasContext *ct
             TCGv_i32 fp0 = tcg_temp_new_i32();
 
             gen_load_fpr32(fp0, fs);
-            gen_helper_float_chs_s(fp0, fp0);
+            if (ctx->abs2008)
+                gen_helper_float_chs2008_s(fp0, fp0);
+            else
+                gen_helper_float_chs_s(fp0, cpu_env, fp0);
             gen_store_fpr32(fp0, fd);
             tcg_temp_free_i32(fp0);
         }
@@ -9259,7 +9266,10 @@ static void gen_farith (DisasContext *ct
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
             gen_load_fpr64(ctx, fp0, fs);
-            gen_helper_float_abs_d(fp0, fp0);
+            if (ctx->abs2008)
+                gen_helper_float_abs2008_d(fp0, fp0);
+            else
+                gen_helper_float_abs_d(fp0, cpu_env, fp0);
             gen_store_fpr64(ctx, fp0, fd);
             tcg_temp_free_i64(fp0);
         }
@@ -9282,7 +9292,10 @@ static void gen_farith (DisasContext *ct
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
             gen_load_fpr64(ctx, fp0, fs);
-            gen_helper_float_chs_d(fp0, fp0);
+            if (ctx->abs2008)
+                gen_helper_float_chs2008_d(fp0, fp0);
+            else
+                gen_helper_float_chs_d(fp0, cpu_env, fp0);
             gen_store_fpr64(ctx, fp0, fd);
             tcg_temp_free_i64(fp0);
         }
@@ -9818,7 +9831,10 @@ static void gen_farith (DisasContext *ct
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
             gen_load_fpr64(ctx, fp0, fs);
-            gen_helper_float_abs_ps(fp0, fp0);
+            if (ctx->abs2008)
+                gen_helper_float_abs2008_ps(fp0, fp0);
+            else
+                gen_helper_float_abs_ps(fp0, cpu_env, fp0);
             gen_store_fpr64(ctx, fp0, fd);
             tcg_temp_free_i64(fp0);
         }
@@ -9841,7 +9857,10 @@ static void gen_farith (DisasContext *ct
             TCGv_i64 fp0 = tcg_temp_new_i64();
 
             gen_load_fpr64(ctx, fp0, fs);
-            gen_helper_float_chs_ps(fp0, fp0);
+            if (ctx->abs2008)
+                gen_helper_float_chs2008_ps(fp0, fp0);
+            else
+                gen_helper_float_chs_ps(fp0, cpu_env, fp0);
             gen_store_fpr64(ctx, fp0, fd);
             tcg_temp_free_i64(fp0);
         }
@@ -19121,6 +19140,7 @@ gen_intermediate_code_internal(MIPSCPU *
     /* Restore delay slot state from the tb context.  */
     ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */
     ctx.ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1;
+    ctx.abs2008 = (env->active_fpu.fcr31 >> FCR31_ABS2008) & 1;
     restore_cpu_state(env, &ctx);
 #ifdef CONFIG_USER_ONLY
         ctx.mem_idx = MIPS_HFLAG_UM;
@@ -19527,6 +19547,8 @@ void cpu_state_reset(CPUMIPSState *env)
     env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask;
     env->CP0_PageGrain = env->cpu_model->CP0_PageGrain;
     env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
+    env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask;
+    env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31;
     env->msair = env->cpu_model->MSAIR;
     env->insn_flags = env->cpu_model->insn_flags;
 
@@ -19634,6 +19656,7 @@ void cpu_state_reset(CPUMIPSState *env)
     compute_hflags(env);
     restore_rounding_mode(env);
     restore_flush_mode(env);
+    restore_nan_mode(env);
     cs->exception_index = EXCP_NONE;
 }
 
Index: qemu-git-trunk/target-mips/translate_init.c
===================================================================
--- qemu-git-trunk.orig/target-mips/translate_init.c    2014-12-08 
23:22:12.000000000 +0000
+++ qemu-git-trunk/target-mips/translate_init.c 2014-12-09 00:51:53.118937156 
+0000
@@ -84,6 +84,8 @@ struct mips_def_t {
     int32_t CP0_TCStatus_rw_bitmask;
     int32_t CP0_SRSCtl;
     int32_t CP1_fcr0;
+    int32_t CP1_fcr31;
+    int32_t CP1_fcr31_rw_bitmask;
     int32_t MSAIR;
     int32_t SEGBITS;
     int32_t PABITS;
@@ -315,6 +317,8 @@ static const mips_def_t mips_defs[] =
         .CP0_Status_rw_bitmask = 0x3678FF1F,
         .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
                     (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 32,
         .PABITS = 32,
         .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
@@ -368,6 +372,8 @@ static const mips_def_t mips_defs[] =
                     (0xff << CP0TCSt_TASID),
         .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
                     (1 << FCR0_D) | (1 << FCR0_S) | (0x95 << FCR0_PRID),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .CP0_SRSCtl = (0xf << CP0SRSCtl_HSS),
         .CP0_SRSConf0_rw_bitmask = 0x3fffffff,
         .CP0_SRSConf0 = (1U << CP0SRSC0_M) | (0x3fe << CP0SRSC0_SRS3) |
@@ -408,6 +414,8 @@ static const mips_def_t mips_defs[] =
         .CP0_Status_rw_bitmask = 0x3778FF1F,
         .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
                     (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 32,
         .PABITS = 32,
         .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP | ASE_DSPR2,
@@ -479,9 +487,11 @@ static const mips_def_t mips_defs[] =
         .SYNCI_Step = 32,
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x3778FF1F,
-        .CP1_fcr0 = (1 << FCR0_UFRP) | (1 << FCR0_F64) | (1 << FCR0_L) |
-                    (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) |
-                    (0x93 << FCR0_PRID),
+        .CP1_fcr0 = (1 << FCR0_UFRP) | (1 << FCR0_HAS2008) |
+                    (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+                    (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = (1 << FCR31_ABS2008) | (1 << FCR31_NAN2008),
         .SEGBITS = 32,
         .PABITS = 32,
         .insn_flags = CPU_MIPS32R5 | ASE_MIPS16 | ASE_MSA,
@@ -503,6 +513,8 @@ static const mips_def_t mips_defs[] =
         .CP0_Status_rw_bitmask = 0x3678FFFF,
         /* The R4000 has a full 64bit FPU but doesn't use the fcr0 bits. */
         .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr31_rw_bitmask = 0x0183FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 40,
         .PABITS = 36,
         .insn_flags = CPU_MIPS3,
@@ -521,6 +533,8 @@ static const mips_def_t mips_defs[] =
         .CP0_Status_rw_bitmask = 0x3678FFFF,
         /* The VR5432 has a full 64bit FPU but doesn't use the fcr0 bits. */
         .CP1_fcr0 = (0x54 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 40,
         .PABITS = 32,
         .insn_flags = CPU_VR54XX,
@@ -566,6 +580,8 @@ static const mips_def_t mips_defs[] =
         /* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */
         .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) |
                     (0x81 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 42,
         .PABITS = 36,
         .insn_flags = CPU_MIPS64,
@@ -593,6 +609,8 @@ static const mips_def_t mips_defs[] =
         .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) |
                     (1 << FCR0_D) | (1 << FCR0_S) |
                     (0x82 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 40,
         .PABITS = 36,
         .insn_flags = CPU_MIPS64 | ASE_MIPS3D,
@@ -619,6 +637,8 @@ static const mips_def_t mips_defs[] =
         .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |
                     (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
                     (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 42,
         /* The architectural limit is 59, but we have hardcoded 36 bit
            in some places...
@@ -667,6 +687,8 @@ static const mips_def_t mips_defs[] =
         .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
                     (1 << FCR0_D) | (1 << FCR0_S) |
                     (0x89 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 42,
         .PABITS = 36,
         .insn_flags = CPU_MIPS64R2,
@@ -750,6 +772,8 @@ static const mips_def_t mips_defs[] =
         .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
                     (1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) |
                     (0x0 << FCR0_REV),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 42,
         /* The architectural limit is 59, but we have hardcoded 36 bit
            in some places...
@@ -771,6 +795,8 @@ static const mips_def_t mips_defs[] =
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0x35D0FFFF,
         .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 40,
         .PABITS = 40,
         .insn_flags = CPU_LOONGSON2E,
@@ -789,6 +815,8 @@ static const mips_def_t mips_defs[] =
         .CCRes = 2,
         .CP0_Status_rw_bitmask = 0xF5D0FF1F,   /* Bits 7:5 not writable.  */
         .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 40,
         .PABITS = 40,
         .insn_flags = CPU_LOONGSON2F,
@@ -816,6 +844,8 @@ static const mips_def_t mips_defs[] =
         .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |
                     (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
                     (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .CP1_fcr31 = 0,
         .SEGBITS = 42,
         /* The architectural limit is 59, but we have hardcoded 36 bit
            in some places...
@@ -966,6 +996,7 @@ static void msa_reset(CPUMIPSState *env)
     set_flush_to_zero(0, &env->active_tc.msa_fp_status);
     set_flush_inputs_to_zero(0, &env->active_tc.msa_fp_status);
 
-    /* clear float_status nan mode */
+    /* set float_status nan modes */
     set_default_nan_mode(0, &env->active_tc.msa_fp_status);
+    set_nan2008_mode(1, &env->active_tc.msa_fp_status);
 }

Reply via email to