]> git.proxmox.com Git - qemu.git/blobdiff - target-mips/op_helper.c
xen: fix xen-mapcache build on non-Xen capable targets
[qemu.git] / target-mips / op_helper.c
index d2a81f08b4819128f88ef39105183a8b1bd74e58..01315ef0dc306f7d92ce662fef24bed71ce649e4 100644 (file)
 #include "host-utils.h"
 
 #include "helper.h"
+
+#ifndef CONFIG_USER_ONLY
+static inline void cpu_mips_tlb_flush (CPUState *env, int flush_global);
+#endif
+
 /*****************************************************************************/
 /* Exceptions processing helpers */
 
@@ -33,7 +38,7 @@ void helper_raise_exception_err (uint32_t exception, int error_code)
 #endif
     env->exception_index = exception;
     env->error_code = error_code;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 void helper_raise_exception (uint32_t exception)
@@ -41,18 +46,6 @@ void helper_raise_exception (uint32_t exception)
     helper_raise_exception_err(exception, 0);
 }
 
-void helper_interrupt_restart (void)
-{
-    if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
-        !(env->CP0_Status & (1 << CP0St_ERL)) &&
-        !(env->hflags & MIPS_HFLAG_DM) &&
-        (env->CP0_Status & (1 << CP0St_IE)) &&
-        (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
-        env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
-        helper_raise_exception(EXCP_EXT_INTERRUPT);
-    }
-}
-
 #if !defined(CONFIG_USER_ONLY)
 static void do_restore_state (void *pc_ptr)
 {
@@ -61,11 +54,63 @@ static void do_restore_state (void *pc_ptr)
     
     tb = tb_find_pc (pc);
     if (tb) {
-        cpu_restore_state (tb, env, pc, NULL);
+        cpu_restore_state(tb, env, pc);
     }
 }
 #endif
 
+#if defined(CONFIG_USER_ONLY)
+#define HELPER_LD(name, insn, type)                                     \
+static inline type do_##name(target_ulong addr, int mem_idx)            \
+{                                                                       \
+    return (type) insn##_raw(addr);                                     \
+}
+#else
+#define HELPER_LD(name, insn, type)                                     \
+static inline type do_##name(target_ulong addr, int mem_idx)            \
+{                                                                       \
+    switch (mem_idx)                                                    \
+    {                                                                   \
+    case 0: return (type) insn##_kernel(addr); break;                   \
+    case 1: return (type) insn##_super(addr); break;                    \
+    default:                                                            \
+    case 2: return (type) insn##_user(addr); break;                     \
+    }                                                                   \
+}
+#endif
+HELPER_LD(lbu, ldub, uint8_t)
+HELPER_LD(lw, ldl, int32_t)
+#ifdef TARGET_MIPS64
+HELPER_LD(ld, ldq, int64_t)
+#endif
+#undef HELPER_LD
+
+#if defined(CONFIG_USER_ONLY)
+#define HELPER_ST(name, insn, type)                                     \
+static inline void do_##name(target_ulong addr, type val, int mem_idx)  \
+{                                                                       \
+    insn##_raw(addr, val);                                              \
+}
+#else
+#define HELPER_ST(name, insn, type)                                     \
+static inline void do_##name(target_ulong addr, type val, int mem_idx)  \
+{                                                                       \
+    switch (mem_idx)                                                    \
+    {                                                                   \
+    case 0: insn##_kernel(addr, val); break;                            \
+    case 1: insn##_super(addr, val); break;                             \
+    default:                                                            \
+    case 2: insn##_user(addr, val); break;                              \
+    }                                                                   \
+}
+#endif
+HELPER_ST(sb, stb, uint8_t)
+HELPER_ST(sw, stl, uint32_t)
+#ifdef TARGET_MIPS64
+HELPER_ST(sd, stq, uint64_t)
+#endif
+#undef HELPER_ST
+
 target_ulong helper_clo (target_ulong arg1)
 {
     return clo32(arg1);
@@ -223,6 +268,59 @@ void helper_dmultu (target_ulong arg1, target_ulong arg2)
 }
 #endif
 
+#ifndef CONFIG_USER_ONLY
+
+static inline target_phys_addr_t do_translate_address(target_ulong address, int rw)
+{
+    target_phys_addr_t lladdr;
+
+    lladdr = cpu_mips_translate_address(env, address, rw);
+
+    if (lladdr == -1LL) {
+        cpu_loop_exit(env);
+    } else {
+        return lladdr;
+    }
+}
+
+#define HELPER_LD_ATOMIC(name, insn)                                          \
+target_ulong helper_##name(target_ulong arg, int mem_idx)                     \
+{                                                                             \
+    env->lladdr = do_translate_address(arg, 0);                               \
+    env->llval = do_##insn(arg, mem_idx);                                     \
+    return env->llval;                                                        \
+}
+HELPER_LD_ATOMIC(ll, lw)
+#ifdef TARGET_MIPS64
+HELPER_LD_ATOMIC(lld, ld)
+#endif
+#undef HELPER_LD_ATOMIC
+
+#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
+target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
+{                                                                             \
+    target_long tmp;                                                          \
+                                                                              \
+    if (arg2 & almask) {                                                      \
+        env->CP0_BadVAddr = arg2;                                             \
+        helper_raise_exception(EXCP_AdES);                                    \
+    }                                                                         \
+    if (do_translate_address(arg2, 1) == env->lladdr) {                       \
+        tmp = do_##ld_insn(arg2, mem_idx);                                    \
+        if (tmp == env->llval) {                                              \
+            do_##st_insn(arg2, arg1, mem_idx);                                \
+            return 1;                                                         \
+        }                                                                     \
+    }                                                                         \
+    return 0;                                                                 \
+}
+HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
+#ifdef TARGET_MIPS64
+HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
+#endif
+#undef HELPER_ST_ATOMIC
+#endif
+
 #ifdef TARGET_WORDS_BIGENDIAN
 #define GET_LMASK(v) ((v) & 3)
 #define GET_OFFSET(addr, offset) (addr + (offset))
@@ -235,34 +333,21 @@ target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
     target_ulong tmp;
 
-#ifdef CONFIG_USER_ONLY
-#define ldfun ldub_raw
-#else
-    int (*ldfun)(target_ulong);
-
-    switch (mem_idx)
-    {
-    case 0: ldfun = ldub_kernel; break;
-    case 1: ldfun = ldub_super; break;
-    default:
-    case 2: ldfun = ldub_user; break;
-    }
-#endif
-    tmp = ldfun(arg2);
+    tmp = do_lbu(arg2, mem_idx);
     arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
 
     if (GET_LMASK(arg2) <= 2) {
-        tmp = ldfun(GET_OFFSET(arg2, 1));
+        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
         arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
     }
 
     if (GET_LMASK(arg2) <= 1) {
-        tmp = ldfun(GET_OFFSET(arg2, 2));
+        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
         arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
     }
 
     if (GET_LMASK(arg2) == 0) {
-        tmp = ldfun(GET_OFFSET(arg2, 3));
+        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
         arg1 = (arg1 & 0xFFFFFF00) | tmp;
     }
     return (int32_t)arg1;
@@ -272,34 +357,21 @@ target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
     target_ulong tmp;
 
-#ifdef CONFIG_USER_ONLY
-#define ldfun ldub_raw
-#else
-    int (*ldfun)(target_ulong);
-
-    switch (mem_idx)
-    {
-    case 0: ldfun = ldub_kernel; break;
-    case 1: ldfun = ldub_super; break;
-    default:
-    case 2: ldfun = ldub_user; break;
-    }
-#endif
-    tmp = ldfun(arg2);
+    tmp = do_lbu(arg2, mem_idx);
     arg1 = (arg1 & 0xFFFFFF00) | tmp;
 
     if (GET_LMASK(arg2) >= 1) {
-        tmp = ldfun(GET_OFFSET(arg2, -1));
+        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
         arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
     }
 
     if (GET_LMASK(arg2) >= 2) {
-        tmp = ldfun(GET_OFFSET(arg2, -2));
+        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
         arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
     }
 
     if (GET_LMASK(arg2) == 3) {
-        tmp = ldfun(GET_OFFSET(arg2, -3));
+        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
         arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
     }
     return (int32_t)arg1;
@@ -307,56 +379,30 @@ target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
 
 void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
-#ifdef CONFIG_USER_ONLY
-#define stfun stb_raw
-#else
-    void (*stfun)(target_ulong, int);
-
-    switch (mem_idx)
-    {
-    case 0: stfun = stb_kernel; break;
-    case 1: stfun = stb_super; break;
-    default:
-    case 2: stfun = stb_user; break;
-    }
-#endif
-    stfun(arg2, (uint8_t)(arg1 >> 24));
+    do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx);
 
     if (GET_LMASK(arg2) <= 2)
-        stfun(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16));
+        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
 
     if (GET_LMASK(arg2) <= 1)
-        stfun(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8));
+        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
 
     if (GET_LMASK(arg2) == 0)
-        stfun(GET_OFFSET(arg2, 3), (uint8_t)arg1);
+        do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
 }
 
 void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
-#ifdef CONFIG_USER_ONLY
-#define stfun stb_raw
-#else
-    void (*stfun)(target_ulong, int);
-
-    switch (mem_idx)
-    {
-    case 0: stfun = stb_kernel; break;
-    case 1: stfun = stb_super; break;
-    default:
-    case 2: stfun = stb_user; break;
-    }
-#endif
-    stfun(arg2, (uint8_t)arg1);
+    do_sb(arg2, (uint8_t)arg1, mem_idx);
 
     if (GET_LMASK(arg2) >= 1)
-        stfun(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8));
+        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
 
     if (GET_LMASK(arg2) >= 2)
-        stfun(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16));
+        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
 
     if (GET_LMASK(arg2) == 3)
-        stfun(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24));
+        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
 }
 
 #if defined(TARGET_MIPS64)
@@ -373,54 +419,41 @@ target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
     uint64_t tmp;
 
-#ifdef CONFIG_USER_ONLY
-#define ldfun ldub_raw
-#else
-    int (*ldfun)(target_ulong);
-
-    switch (mem_idx)
-    {
-    case 0: ldfun = ldub_kernel; break;
-    case 1: ldfun = ldub_super; break;
-    default:
-    case 2: ldfun = ldub_user; break;
-    }
-#endif
-    tmp = ldfun(arg2);
+    tmp = do_lbu(arg2, mem_idx);
     arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
 
     if (GET_LMASK64(arg2) <= 6) {
-        tmp = ldfun(GET_OFFSET(arg2, 1));
+        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
         arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
     }
 
     if (GET_LMASK64(arg2) <= 5) {
-        tmp = ldfun(GET_OFFSET(arg2, 2));
+        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
         arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
     }
 
     if (GET_LMASK64(arg2) <= 4) {
-        tmp = ldfun(GET_OFFSET(arg2, 3));
+        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
         arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
     }
 
     if (GET_LMASK64(arg2) <= 3) {
-        tmp = ldfun(GET_OFFSET(arg2, 4));
+        tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
     }
 
     if (GET_LMASK64(arg2) <= 2) {
-        tmp = ldfun(GET_OFFSET(arg2, 5));
+        tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
     }
 
     if (GET_LMASK64(arg2) <= 1) {
-        tmp = ldfun(GET_OFFSET(arg2, 6));
+        tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
     }
 
     if (GET_LMASK64(arg2) == 0) {
-        tmp = ldfun(GET_OFFSET(arg2, 7));
+        tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
     }
 
@@ -431,54 +464,41 @@ target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
     uint64_t tmp;
 
-#ifdef CONFIG_USER_ONLY
-#define ldfun ldub_raw
-#else
-    int (*ldfun)(target_ulong);
-
-    switch (mem_idx)
-    {
-    case 0: ldfun = ldub_kernel; break;
-    case 1: ldfun = ldub_super; break;
-    default:
-    case 2: ldfun = ldub_user; break;
-    }
-#endif
-    tmp = ldfun(arg2);
+    tmp = do_lbu(arg2, mem_idx);
     arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
 
     if (GET_LMASK64(arg2) >= 1) {
-        tmp = ldfun(GET_OFFSET(arg2, -1));
+        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
     }
 
     if (GET_LMASK64(arg2) >= 2) {
-        tmp = ldfun(GET_OFFSET(arg2, -2));
+        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
     }
 
     if (GET_LMASK64(arg2) >= 3) {
-        tmp = ldfun(GET_OFFSET(arg2, -3));
+        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
     }
 
     if (GET_LMASK64(arg2) >= 4) {
-        tmp = ldfun(GET_OFFSET(arg2, -4));
+        tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx);
         arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
     }
 
     if (GET_LMASK64(arg2) >= 5) {
-        tmp = ldfun(GET_OFFSET(arg2, -5));
+        tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx);
         arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
     }
 
     if (GET_LMASK64(arg2) >= 6) {
-        tmp = ldfun(GET_OFFSET(arg2, -6));
+        tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx);
         arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
     }
 
     if (GET_LMASK64(arg2) == 7) {
-        tmp = ldfun(GET_OFFSET(arg2, -7));
+        tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx);
         arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
     }
 
@@ -487,83 +507,193 @@ target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
 
 void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
-#ifdef CONFIG_USER_ONLY
-#define stfun stb_raw
-#else
-    void (*stfun)(target_ulong, int);
-
-    switch (mem_idx)
-    {
-    case 0: stfun = stb_kernel; break;
-    case 1: stfun = stb_super; break;
-    default:
-    case 2: stfun = stb_user; break;
-    }
-#endif
-    stfun(arg2, (uint8_t)(arg1 >> 56));
+    do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx);
 
     if (GET_LMASK64(arg2) <= 6)
-        stfun(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48));
+        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
 
     if (GET_LMASK64(arg2) <= 5)
-        stfun(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40));
+        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
 
     if (GET_LMASK64(arg2) <= 4)
-        stfun(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32));
+        do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
 
     if (GET_LMASK64(arg2) <= 3)
-        stfun(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24));
+        do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
 
     if (GET_LMASK64(arg2) <= 2)
-        stfun(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16));
+        do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
 
     if (GET_LMASK64(arg2) <= 1)
-        stfun(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8));
+        do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
 
     if (GET_LMASK64(arg2) <= 0)
-        stfun(GET_OFFSET(arg2, 7), (uint8_t)arg1);
+        do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
 }
 
 void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
-#ifdef CONFIG_USER_ONLY
-#define stfun stb_raw
-#else
-    void (*stfun)(target_ulong, int);
-
-    switch (mem_idx)
-    {
-    case 0: stfun = stb_kernel; break;
-    case 1: stfun = stb_super; break;
-     default:
-    case 2: stfun = stb_user; break;
-    }
-#endif
-    stfun(arg2, (uint8_t)arg1);
+    do_sb(arg2, (uint8_t)arg1, mem_idx);
 
     if (GET_LMASK64(arg2) >= 1)
-        stfun(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8));
+        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
 
     if (GET_LMASK64(arg2) >= 2)
-        stfun(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16));
+        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
 
     if (GET_LMASK64(arg2) >= 3)
-        stfun(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24));
+        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
 
     if (GET_LMASK64(arg2) >= 4)
-        stfun(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32));
+        do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
 
     if (GET_LMASK64(arg2) >= 5)
-        stfun(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40));
+        do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
 
     if (GET_LMASK64(arg2) >= 6)
-        stfun(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48));
+        do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
 
     if (GET_LMASK64(arg2) == 7)
-        stfun(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56));
+        do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
 }
 #endif /* TARGET_MIPS64 */
 
+static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
+
+void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef ldfun
+#define ldfun ldl_raw
+#else
+    uint32_t (*ldfun)(target_ulong);
+
+    switch (mem_idx)
+    {
+    case 0: ldfun = ldl_kernel; break;
+    case 1: ldfun = ldl_super; break;
+    default:
+    case 2: ldfun = ldl_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr);
+            addr += 4;
+        }
+    }
+
+    if (do_r31) {
+        env->active_tc.gpr[31] = (target_long) ldfun(addr);
+    }
+}
+
+void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef stfun
+#define stfun stl_raw
+#else
+    void (*stfun)(target_ulong, uint32_t);
+
+    switch (mem_idx)
+    {
+    case 0: stfun = stl_kernel; break;
+    case 1: stfun = stl_super; break;
+     default:
+    case 2: stfun = stl_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
+            addr += 4;
+        }
+    }
+
+    if (do_r31) {
+        stfun(addr, env->active_tc.gpr[31]);
+    }
+}
+
+#if defined(TARGET_MIPS64)
+void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef ldfun
+#define ldfun ldq_raw
+#else
+    uint64_t (*ldfun)(target_ulong);
+
+    switch (mem_idx)
+    {
+    case 0: ldfun = ldq_kernel; break;
+    case 1: ldfun = ldq_super; break;
+    default:
+    case 2: ldfun = ldq_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            env->active_tc.gpr[multiple_regs[i]] = ldfun(addr);
+            addr += 8;
+        }
+    }
+
+    if (do_r31) {
+        env->active_tc.gpr[31] = ldfun(addr);
+    }
+}
+
+void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+    target_ulong base_reglist = reglist & 0xf;
+    target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef stfun
+#define stfun stq_raw
+#else
+    void (*stfun)(target_ulong, uint64_t);
+
+    switch (mem_idx)
+    {
+    case 0: stfun = stq_kernel; break;
+    case 1: stfun = stq_super; break;
+     default:
+    case 2: stfun = stq_user; break;
+    }
+#endif
+
+    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+        target_ulong i;
+
+        for (i = 0; i < base_reglist; i++) {
+            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
+            addr += 8;
+        }
+    }
+
+    if (do_r31) {
+        stfun(addr, env->active_tc.gpr[31]);
+    }
+}
+#endif
+
 #ifndef CONFIG_USER_ONLY
 /* CP0 helpers */
 target_ulong helper_mfc0_mvpcontrol (void)
@@ -730,7 +860,7 @@ target_ulong helper_mftc0_status(void)
 
 target_ulong helper_mfc0_lladdr (void)
 {
-    return (int32_t)env->lladdr >> 4;
+    return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
 }
 
 target_ulong helper_mfc0_watchlo (uint32_t sel)
@@ -795,7 +925,7 @@ target_ulong helper_dmfc0_tcschefback (void)
 
 target_ulong helper_dmfc0_lladdr (void)
 {
-    return env->lladdr >> 4;
+    return env->lladdr >> env->CP0_LLAddr_shift;
 }
 
 target_ulong helper_dmfc0_watchlo (uint32_t sel)
@@ -1171,7 +1301,6 @@ void helper_mtc0_status (target_ulong arg1)
         default: cpu_abort(env, "Invalid MMU mode!\n"); break;
         }
     }
-    cpu_mips_update_irq(env);
 }
 
 void helper_mttc0_status(target_ulong arg1)
@@ -1205,6 +1334,7 @@ void helper_mtc0_cause (target_ulong arg1)
 {
     uint32_t mask = 0x00C00300;
     uint32_t old = env->CP0_Cause;
+    int i;
 
     if (env->insn_flags & ISA_MIPS32R2)
         mask |= 1 << CP0Ca_DC;
@@ -1218,18 +1348,18 @@ void helper_mtc0_cause (target_ulong arg1)
             cpu_mips_start_count(env);
     }
 
-    /* Handle the software interrupt as an hardware one, as they
-       are very similar */
-    if (arg1 & CP0Ca_IP_mask) {
-        cpu_mips_update_irq(env);
+    /* Set/reset software interrupts */
+    for (i = 0 ; i < 2 ; i++) {
+        if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
+            cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
+        }
     }
 }
 
 void helper_mtc0_ebase (target_ulong arg1)
 {
     /* vectored interrupts not implemented */
-    /* Multi-CPU not implemented */
-    env->CP0_EBase = 0x80000000 | (arg1 & 0x3FFFF000);
+    env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
 }
 
 void helper_mtc0_config0 (target_ulong arg1)
@@ -1243,6 +1373,13 @@ void helper_mtc0_config2 (target_ulong arg1)
     env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
 }
 
+void helper_mtc0_lladdr (target_ulong arg1)
+{
+    target_long mask = env->CP0_LLAddr_rw_bitmask;
+    arg1 = arg1 << env->CP0_LLAddr_shift;
+    env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
+}
+
 void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
 {
     /* Watch exceptions for instructions, data loads, data stores
@@ -1417,40 +1554,28 @@ void helper_mttdsp(target_ulong arg1)
 }
 
 /* MIPS MT functions */
-target_ulong helper_dmt(target_ulong arg1)
+target_ulong helper_dmt(void)
 {
     // TODO
-    arg1 = 0;
-    // rt = arg1
-
-    return arg1;
+     return 0;
 }
 
-target_ulong helper_emt(target_ulong arg1)
+target_ulong helper_emt(void)
 {
     // TODO
-    arg1 = 0;
-    // rt = arg1
-
-    return arg1;
+    return 0;
 }
 
-target_ulong helper_dvpe(target_ulong arg1)
+target_ulong helper_dvpe(void)
 {
     // TODO
-    arg1 = 0;
-    // rt = arg1
-
-    return arg1;
+    return 0;
 }
 
-target_ulong helper_evpe(target_ulong arg1)
+target_ulong helper_evpe(void)
 {
     // TODO
-    arg1 = 0;
-    // rt = arg1
-
-    return arg1;
+    return 0;
 }
 #endif /* !CONFIG_USER_ONLY */
 
@@ -1461,8 +1586,10 @@ void helper_fork(target_ulong arg1, target_ulong arg2)
     // TODO: store to TC register
 }
 
-target_ulong helper_yield(target_ulong arg1)
+target_ulong helper_yield(target_ulong arg)
 {
+    target_long arg1 = arg;
+
     if (arg1 < 0) {
         /* No scheduling policy implemented. */
         if (arg1 != -2) {
@@ -1491,7 +1618,7 @@ target_ulong helper_yield(target_ulong arg1)
 
 #ifndef CONFIG_USER_ONLY
 /* TLB management */
-void cpu_mips_tlb_flush (CPUState *env, int flush_global)
+static void cpu_mips_tlb_flush (CPUState *env, int flush_global)
 {
     /* Flush qemu's TLB and discard all shadowed entries.  */
     tlb_flush (env, flush_global);
@@ -1644,8 +1771,6 @@ target_ulong helper_di (void)
     target_ulong t0 = env->CP0_Status;
 
     env->CP0_Status = t0 & ~(1 << CP0St_IE);
-    cpu_mips_update_irq(env);
-
     return t0;
 }
 
@@ -1654,8 +1779,6 @@ target_ulong helper_ei (void)
     target_ulong t0 = env->CP0_Status;
 
     env->CP0_Status = t0 | (1 << CP0St_IE);
-    cpu_mips_update_irq(env);
-
     return t0;
 }
 
@@ -1690,14 +1813,24 @@ static void debug_post_eret (void)
     }
 }
 
+static void set_pc (target_ulong error_pc)
+{
+    env->active_tc.PC = error_pc & ~(target_ulong)1;
+    if (error_pc & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    } else {
+        env->hflags &= ~(MIPS_HFLAG_M16);
+    }
+}
+
 void helper_eret (void)
 {
     debug_pre_eret();
     if (env->CP0_Status & (1 << CP0St_ERL)) {
-        env->active_tc.PC = env->CP0_ErrorEPC;
+        set_pc(env->CP0_ErrorEPC);
         env->CP0_Status &= ~(1 << CP0St_ERL);
     } else {
-        env->active_tc.PC = env->CP0_EPC;
+        set_pc(env->CP0_EPC);
         env->CP0_Status &= ~(1 << CP0St_EXL);
     }
     compute_hflags(env);
@@ -1708,7 +1841,8 @@ void helper_eret (void)
 void helper_deret (void)
 {
     debug_pre_eret();
-    env->active_tc.PC = env->CP0_DEPC;
+    set_pc(env->CP0_DEPC);
+
     env->hflags &= MIPS_HFLAG_DM;
     compute_hflags(env);
     debug_post_eret();
@@ -1838,7 +1972,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
             if (tb) {
                 /* the PC is inside the translated code. It means that we have
                    a virtual CPU fault */
-                cpu_restore_state(tb, env, pc, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         helper_raise_exception_err(env->exception_index, env->error_code);
@@ -1846,9 +1980,11 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
     env = saved_env;
 }
 
-void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
-                          int unused, int size)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+                           int is_write, int is_exec, int unused, int size)
 {
+    env = env1;
+
     if (is_exec)
         helper_raise_exception(EXCP_IBE);
     else
@@ -1943,22 +2079,27 @@ void helper_ctc1 (target_ulong arg1, uint32_t reg)
         helper_raise_exception(EXCP_FPE);
 }
 
-static inline char ieee_ex_to_mips(char xcpt)
+static inline int ieee_ex_to_mips(int xcpt)
 {
-    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;
-}
-
-static inline char mips_ex_to_ieee(char xcpt)
-{
-    return (xcpt & FP_INEXACT) << 5 |
-           (xcpt & FP_UNDERFLOW) << 3 |
-           (xcpt & FP_OVERFLOW) << 1 |
-           (xcpt & FP_DIV0) >> 1 |
-           (xcpt & FP_INVALID) >> 4;
+    int ret = 0;
+    if (xcpt) {
+        if (xcpt & float_flag_invalid) {
+            ret |= FP_INVALID;
+        }
+        if (xcpt & float_flag_overflow) {
+            ret |= FP_OVERFLOW;
+        }
+        if (xcpt & float_flag_underflow) {
+            ret |= FP_UNDERFLOW;
+        }
+        if (xcpt & float_flag_divbyzero) {
+            ret |= FP_DIV0;
+        }
+        if (xcpt & float_flag_inexact) {
+            ret |= FP_INEXACT;
+        }
+    }
+    return ret;
 }
 
 static inline void update_fcr31(void)
@@ -2148,6 +2289,7 @@ uint64_t helper_float_roundl_d(uint64_t fdt0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2161,6 +2303,7 @@ uint64_t helper_float_roundl_s(uint32_t fst0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2174,6 +2317,7 @@ uint32_t helper_float_roundw_d(uint64_t fdt0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2187,6 +2331,7 @@ uint32_t helper_float_roundw_s(uint32_t fst0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2200,6 +2345,7 @@ uint64_t helper_float_truncl_d(uint64_t fdt0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
     update_fcr31();
     if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
@@ -2211,6 +2357,7 @@ uint64_t helper_float_truncl_s(uint32_t fst0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
     update_fcr31();
     if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
@@ -2222,6 +2369,7 @@ uint32_t helper_float_truncw_d(uint64_t fdt0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
     update_fcr31();
     if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
@@ -2233,6 +2381,7 @@ uint32_t helper_float_truncw_s(uint32_t fst0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
     update_fcr31();
     if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
@@ -2244,6 +2393,7 @@ uint64_t helper_float_ceill_d(uint64_t fdt0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2257,6 +2407,7 @@ uint64_t helper_float_ceill_s(uint32_t fst0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2270,6 +2421,7 @@ uint32_t helper_float_ceilw_d(uint64_t fdt0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2283,6 +2435,7 @@ uint32_t helper_float_ceilw_s(uint32_t fst0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2296,6 +2449,7 @@ uint64_t helper_float_floorl_d(uint64_t fdt0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2309,6 +2463,7 @@ uint64_t helper_float_floorl_s(uint32_t fst0)
 {
     uint64_t dt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2322,6 +2477,7 @@ uint32_t helper_float_floorw_d(uint64_t fdt0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2335,6 +2491,7 @@ uint32_t helper_float_floorw_s(uint32_t fst0)
 {
     uint32_t wt2;
 
+    set_float_exception_flags(0, &env->active_fpu.fp_status);
     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
     RESTORE_ROUNDING_MODE;
@@ -2719,7 +2876,9 @@ uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
 #define FOP_COND_D(op, cond)                                   \
 void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
 {                                                              \
-    int c = cond;                                              \
+    int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
+    c = cond;                                                  \
     update_fcr31();                                            \
     if (c)                                                     \
         SET_FP_COND(cc, env->active_fpu);                      \
@@ -2729,6 +2888,7 @@ void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
 void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
 {                                                              \
     int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
     fdt0 = float64_abs(fdt0);                                  \
     fdt1 = float64_abs(fdt1);                                  \
     c = cond;                                                  \
@@ -2739,45 +2899,33 @@ void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
         CLEAR_FP_COND(cc, env->active_fpu);                    \
 }
 
-static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
-{
-    if (float64_is_signaling_nan(a) ||
-        float64_is_signaling_nan(b) ||
-        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
-        float_raise(float_flag_invalid, status);
-        return 1;
-    } else if (float64_is_nan(a) || float64_is_nan(b)) {
-        return 1;
-    } else {
-        return 0;
-    }
-}
-
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_D(f,   (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0))
-FOP_COND_D(un,  float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status))
-FOP_COND_D(eq,  !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
+ * but float64_unordered_quiet() is still called. */
+FOP_COND_D(f,   (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
+FOP_COND_D(un,  float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
+FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_D(sf,  (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0))
-FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status))
-FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(lt,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(le,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
-FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
+ * but float64_unordered() is still called. */
+FOP_COND_D(sf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
+FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
+FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(lt,  float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
+FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
 
 #define FOP_COND_S(op, cond)                                   \
 void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
 {                                                              \
-    int c = cond;                                              \
+    int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
+    c = cond;                                                  \
     update_fcr31();                                            \
     if (c)                                                     \
         SET_FP_COND(cc, env->active_fpu);                      \
@@ -2787,6 +2935,7 @@ void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
 void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
 {                                                              \
     int c;                                                     \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);  \
     fst0 = float32_abs(fst0);                                  \
     fst1 = float32_abs(fst1);                                  \
     c = cond;                                                  \
@@ -2797,51 +2946,39 @@ void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
         CLEAR_FP_COND(cc, env->active_fpu);                    \
 }
 
-static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
-{
-    if (float32_is_signaling_nan(a) ||
-        float32_is_signaling_nan(b) ||
-        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
-        float_raise(float_flag_invalid, status);
-        return 1;
-    } else if (float32_is_nan(a) || float32_is_nan(b)) {
-        return 1;
-    } else {
-        return 0;
-    }
-}
-
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_S(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0))
-FOP_COND_S(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status))
-FOP_COND_S(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
+ * but float32_unordered_quiet() is still called. */
+FOP_COND_S(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
+FOP_COND_S(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
+FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_S(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0))
-FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status))
-FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
-FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
+ * but float32_unordered() is still called. */
+FOP_COND_S(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
+FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
+FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
+FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
 
 #define FOP_COND_PS(op, condl, condh)                           \
 void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
 {                                                               \
-    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
-    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
-    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
-    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
-    int cl = condl;                                             \
-    int ch = condh;                                             \
-                                                                \
+    uint32_t fst0, fsth0, fst1, fsth1;                          \
+    int ch, cl;                                                 \
+    set_float_exception_flags(0, &env->active_fpu.fp_status);   \
+    fst0 = fdt0 & 0XFFFFFFFF;                                   \
+    fsth0 = fdt0 >> 32;                                         \
+    fst1 = fdt1 & 0XFFFFFFFF;                                   \
+    fsth1 = fdt1 >> 32;                                         \
+    cl = condl;                                                 \
+    ch = condh;                                                 \
     update_fcr31();                                             \
     if (cl)                                                     \
         SET_FP_COND(cc, env->active_fpu);                       \
@@ -2854,13 +2991,14 @@ void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
 }                                                               \
 void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
 {                                                               \
-    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
-    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
-    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
-    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
-    int cl = condl;                                             \
-    int ch = condh;                                             \
-                                                                \
+    uint32_t fst0, fsth0, fst1, fsth1;                          \
+    int ch, cl;                                                 \
+    fst0 = float32_abs(fdt0 & 0XFFFFFFFF);                      \
+    fsth0 = float32_abs(fdt0 >> 32);                            \
+    fst1 = float32_abs(fdt1 & 0XFFFFFFFF);                      \
+    fsth1 = float32_abs(fdt1 >> 32);                            \
+    cl = condl;                                                 \
+    ch = condh;                                                 \
     update_fcr31();                                             \
     if (cl)                                                     \
         SET_FP_COND(cc, env->active_fpu);                       \
@@ -2873,38 +3011,38 @@ void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
 }
 
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_PS(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0),
-                 (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0))
-FOP_COND_PS(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status),
-                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status))
-FOP_COND_PS(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
+ * but float32_unordered_quiet() is still called. */
+FOP_COND_PS(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
+                 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
+FOP_COND_PS(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
+FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
 /* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_PS(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0),
-                 (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0))
-FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status),
-                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status))
-FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
-                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
-FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
-                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
+ * but float32_unordered() is still called. */
+FOP_COND_PS(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
+                 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
+FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
+FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
+FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
+                 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))