]> git.proxmox.com Git - qemu.git/commitdiff
More MIPS 64-bit FPU support.
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 19 May 2007 20:29:41 +0000 (20:29 +0000)
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 19 May 2007 20:29:41 +0000 (20:29 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2834 c046a42c-6fe2-441c-8c8c-71466251a162

target-mips/exec.h
target-mips/op.c
target-mips/op_helper.c
target-mips/translate.c

index 7ebfd78e71dab66d9e234c71deebc5e537d2e6eb..6d004102bb5f82dc5e05168fc7761389a45833a7 100644 (file)
@@ -166,6 +166,36 @@ void cpu_mips_clock_init (CPUState *env);
 void cpu_mips_tlb_flush (CPUState *env, int flush_global);
 
 void do_ctc1 (void);
+
+#define FOP_PROTO(op)              \
+void do_float_ ## op ## _s(void);  \
+void do_float_ ## op ## _d(void);
+FOP_PROTO(roundl)
+FOP_PROTO(roundw)
+FOP_PROTO(truncl)
+FOP_PROTO(truncw)
+FOP_PROTO(ceill)
+FOP_PROTO(ceilw)
+FOP_PROTO(floorl)
+FOP_PROTO(floorw)
+FOP_PROTO(rsqrt)
+FOP_PROTO(recip)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op)              \
+void do_float_ ## op ## _s(void);  \
+void do_float_ ## op ## _d(void);  \
+void do_float_ ## op ## _ps(void);
+FOP_PROTO(add)
+FOP_PROTO(sub)
+FOP_PROTO(mul)
+FOP_PROTO(div)
+FOP_PROTO(recip1)
+FOP_PROTO(recip2)
+FOP_PROTO(rsqrt1)
+FOP_PROTO(rsqrt2)
+#undef FOP_PROTO
+
 void do_float_cvtd_s(void);
 void do_float_cvtd_w(void);
 void do_float_cvtd_l(void);
@@ -180,37 +210,11 @@ void do_float_cvts_pl(void);
 void do_float_cvts_pu(void);
 void do_float_cvtw_s(void);
 void do_float_cvtw_d(void);
-void do_float_roundl_d(void);
-void do_float_roundl_s(void);
-void do_float_roundw_d(void);
-void do_float_roundw_s(void);
-void do_float_truncl_d(void);
-void do_float_truncl_s(void);
-void do_float_truncw_d(void);
-void do_float_truncw_s(void);
-void do_float_ceill_d(void);
-void do_float_ceill_s(void);
-void do_float_ceilw_d(void);
-void do_float_ceilw_s(void);
-void do_float_floorl_d(void);
-void do_float_floorl_s(void);
-void do_float_floorw_d(void);
-void do_float_floorw_s(void);
-void do_float_add_d(void);
-void do_float_add_s(void);
-void do_float_add_ps(void);
-void do_float_sub_d(void);
-void do_float_sub_s(void);
-void do_float_sub_ps(void);
-void do_float_mul_d(void);
-void do_float_mul_s(void);
-void do_float_mul_ps(void);
-void do_float_div_d(void);
-void do_float_div_s(void);
-void do_float_div_ps(void);
+
 void do_float_addr_ps(void);
+void do_float_mulr_ps(void);
 
-#define CMP_OPS(op)                        \
+#define FOP_PROTO(op)                      \
 void do_cmp_d_ ## op(long cc);             \
 void do_cmpabs_d_ ## op(long cc);          \
 void do_cmp_s_ ## op(long cc);             \
@@ -218,22 +222,22 @@ void do_cmpabs_s_ ## op(long cc);          \
 void do_cmp_ps_ ## op(long cc);            \
 void do_cmpabs_ps_ ## op(long cc);
 
-CMP_OPS(f)
-CMP_OPS(un)
-CMP_OPS(eq)
-CMP_OPS(ueq)
-CMP_OPS(olt)
-CMP_OPS(ult)
-CMP_OPS(ole)
-CMP_OPS(ule)
-CMP_OPS(sf)
-CMP_OPS(ngle)
-CMP_OPS(seq)
-CMP_OPS(ngl)
-CMP_OPS(lt)
-CMP_OPS(nge)
-CMP_OPS(le)
-CMP_OPS(ngt)
-#undef CMP_OPS
+FOP_PROTO(f)
+FOP_PROTO(un)
+FOP_PROTO(eq)
+FOP_PROTO(ueq)
+FOP_PROTO(olt)
+FOP_PROTO(ult)
+FOP_PROTO(ole)
+FOP_PROTO(ule)
+FOP_PROTO(sf)
+FOP_PROTO(ngle)
+FOP_PROTO(seq)
+FOP_PROTO(ngl)
+FOP_PROTO(lt)
+FOP_PROTO(nge)
+FOP_PROTO(le)
+FOP_PROTO(ngt)
+#undef FOP_PROTO
 
 #endif /* !defined(__QEMU_MIPS_EXEC_H__) */
index c60871afeab948517a64b10ea10b67cf4dfb1d09..8c0c687a832d7d54704e744edb5c81168c9526f7 100644 (file)
@@ -1609,6 +1609,14 @@ void op_cp1_enabled(void)
     RETURN();
 }
 
+void op_cp1_64bitmode(void)
+{
+    if (!(env->CP0_Status & (1 << CP0St_FR))) {
+        CALL_FROM_TB1(do_raise_exception, EXCP_RI);
+    }
+    RETURN();
+}
+
 /*
  * Verify if floating point register is valid; an operation is not defined
  * if bit 0 of any register specification is set and the FR bit in the
@@ -1946,8 +1954,8 @@ FLOAT_OP(movn, ps)
     RETURN();
 }
 
-/* binary operations */
-#define FLOAT_BINOP(name) \
+/* operations calling helpers, for s, d and ps */
+#define FLOAT_HOP(name) \
 FLOAT_OP(name, d)         \
 {                         \
     CALL_FROM_TB0(do_float_ ## name ## _d);  \
@@ -1966,18 +1974,45 @@ FLOAT_OP(name, ps)        \
     DEBUG_FPU_STATE();    \
     RETURN();             \
 }
-FLOAT_BINOP(add)
-FLOAT_BINOP(sub)
-FLOAT_BINOP(mul)
-FLOAT_BINOP(div)
-#undef FLOAT_BINOP
+FLOAT_HOP(add)
+FLOAT_HOP(sub)
+FLOAT_HOP(mul)
+FLOAT_HOP(div)
+FLOAT_HOP(recip2)
+FLOAT_HOP(rsqrt2)
+FLOAT_HOP(rsqrt1)
+FLOAT_HOP(recip1)
+#undef FLOAT_HOP
+
+/* operations calling helpers, for s and d */
+#define FLOAT_HOP(name)   \
+FLOAT_OP(name, d)         \
+{                         \
+    CALL_FROM_TB0(do_float_ ## name ## _d);  \
+    DEBUG_FPU_STATE();    \
+    RETURN();             \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    CALL_FROM_TB0(do_float_ ## name ## _s);  \
+    DEBUG_FPU_STATE();    \
+    RETURN();             \
+}
+FLOAT_HOP(rsqrt)
+FLOAT_HOP(recip)
+#undef FLOAT_HOP
 
-FLOAT_OP(addr, ps)
-{
-    CALL_FROM_TB0(do_float_addr_ps);
-    DEBUG_FPU_STATE();
-    RETURN();
+/* operations calling helpers, for ps */
+#define FLOAT_HOP(name)   \
+FLOAT_OP(name, ps)        \
+{                         \
+    CALL_FROM_TB0(do_float_ ## name ## _ps); \
+    DEBUG_FPU_STATE();    \
+    RETURN();             \
 }
+FLOAT_HOP(addr)
+FLOAT_HOP(mulr)
+#undef FLOAT_HOP
 
 /* ternary operations */
 #define FLOAT_TERNOP(name1, name2) \
@@ -2053,14 +2088,7 @@ FLOAT_OP(name, s)         \
 {                         \
     FST2 = float32_ ## name(FST0, &env->fp_status);   \
     DEBUG_FPU_STATE();    \
-    RETURN();                      \
-}                         \
-FLOAT_OP(name, ps)        \
-{                         \
-    FST2 = float32_ ## name(FST0, &env->fp_status);   \
-    FSTH2 = float32_ ## name(FSTH0, &env->fp_status); \
-    DEBUG_FPU_STATE();    \
-    RETURN();                      \
+    RETURN();             \
 }
 FLOAT_UNOP(sqrt)
 #undef FLOAT_UNOP
index 85ad33355af24d2d6915ef3eba0d12088cbac768..9a0ffee9af26d762ceb7359e0e7fe036abce2efe 100644 (file)
@@ -916,6 +916,59 @@ FLOAT_OP(floorw, s)
         WT2 = 0x7fffffff;
 }
 
+/* unary operations, MIPS specific, s and d */
+#define FLOAT_UNOP(name)  \
+FLOAT_OP(name, d)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FDT2 = float64_ ## name (FDT0, &env->fp_status);*/          \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}
+FLOAT_UNOP(rsqrt)
+FLOAT_UNOP(recip)
+#undef FLOAT_UNOP
+
+/* unary operations, MIPS specific, s, d and ps */
+#define FLOAT_UNOP(name)  \
+FLOAT_OP(name, d)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FDT2 = float64_ ## name (FDT0, &env->fp_status);*/          \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}                         \
+FLOAT_OP(name, ps)        \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
+/*    FSTH2 = float32_ ## name (FSTH0, &env->fp_status);*/        \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}
+FLOAT_UNOP(rsqrt1)
+FLOAT_UNOP(recip1)
+#undef FLOAT_UNOP
+
 /* binary operations */
 #define FLOAT_BINOP(name) \
 FLOAT_OP(name, d)         \
@@ -943,6 +996,37 @@ FLOAT_BINOP(mul)
 FLOAT_BINOP(div)
 #undef FLOAT_BINOP
 
+/* binary operations, MIPS specific */
+#define FLOAT_BINOP(name) \
+FLOAT_OP(name, d)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);*/    \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/    \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}                         \
+FLOAT_OP(name, ps)        \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/    \
+/*    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status);*/ \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}
+FLOAT_BINOP(rsqrt2)
+FLOAT_BINOP(recip2)
+#undef FLOAT_BINOP
+
 FLOAT_OP(addr, ps)
 {
     set_float_exception_flags(0, &env->fp_status);
@@ -951,6 +1035,14 @@ FLOAT_OP(addr, ps)
     update_fcr31();
 }
 
+FLOAT_OP(mulr, ps)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_mul (FST0, FSTH0, &env->fp_status);
+    FSTH2 = float32_mul (FST1, FSTH1, &env->fp_status);
+    update_fcr31();
+}
+
 #define FOP_COND_D(op, cond)                   \
 void do_cmp_d_ ## op (long cc)                 \
 {                                              \
index 0396ac396dddc9ef8ec4307c31290903d59047fa..075be1ed05b6e9315cc3c47e598297ddbe9b36a6 100644 (file)
@@ -4378,14 +4378,12 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
         opn = "dmtc1";
         break;
     case OPC_MFHC1:
-        gen_op_cp1_registers(fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_mfhc1();
         GEN_STORE_TN_REG(rt, T0);
         opn = "mfhc1";
         break;
     case OPC_MTHC1:
-        gen_op_cp1_registers(fs);
         GEN_LOAD_REG_TN(T0, rt);
         gen_op_mthc1();
         GEN_STORE_FTN_FREG(fs, WTH0);
@@ -4405,9 +4403,9 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
 
     GEN_LOAD_REG_TN(T0, rd);
     GEN_LOAD_REG_TN(T1, rs);
-    if (cc)
+    if (cc) {
         ccbit = 1 << (24 + cc);
-    else
+    else
         ccbit = 1 << 23;
     if (!tf)
         gen_op_movf(ccbit);
@@ -4421,9 +4419,9 @@ static void glue(gen_movcf_, fmt) (DisasContext *ctx, int cc, int tf) \
 {                                                                     \
     uint32_t ccbit;                                                   \
                                                                       \
-    if (cc)                                                           \
+    if (cc) {                                                         \
         ccbit = 1 << (24 + cc);                                       \
-    else                                                              \
+    } else                                                            \
         ccbit = 1 << 23;                                              \
     if (!tf)                                                          \
         glue(gen_op_float_movf_, fmt)(ccbit);                         \
@@ -4536,28 +4534,28 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "neg.s";
         break;
     case FOP(8, 16):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_roundl_s();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "round.l.s";
         break;
     case FOP(9, 16):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_truncl_s();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "trunc.l.s";
         break;
     case FOP(10, 16):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_ceill_s();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "ceil.l.s";
         break;
     case FOP(11, 16):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_floorl_s();
         GEN_STORE_FTN_FREG(fd, DT2);
@@ -4611,6 +4609,48 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "movn.s";
         break;
+    case FOP(21, 16):
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_recip_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "recip.s";
+        break;
+    case FOP(22, 16):
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_rsqrt_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "rsqrt.s";
+        break;
+    case FOP(28, 16):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        gen_op_float_recip2_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "recip2.s";
+        break;
+    case FOP(29, 16):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_recip1_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "recip1.s";
+        break;
+    case FOP(30, 16):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_rsqrt1_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "rsqrt1.s";
+        break;
+    case FOP(31, 16):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        gen_op_float_rsqrt2_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "rsqrt2.s";
+        break;
     case FOP(33, 16):
         gen_op_cp1_registers(fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
@@ -4625,14 +4665,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "cvt.w.s";
         break;
     case FOP(37, 16):
-        gen_op_cp1_registers(fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_cvtl_s();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "cvt.l.s";
         break;
     case FOP(38, 16):
-        gen_op_cp1_registers(fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT1, fs);
         GEN_LOAD_FREG_FTN(WT0, ft);
         gen_op_float_cvtps_s();
@@ -4658,6 +4698,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         if (ctx->opcode & (1 << 6)) {
+            gen_op_cp1_64bitmode();
             gen_cmpabs_s(func-48, cc);
             opn = condnames_abs[func-48];
         } else {
@@ -4730,28 +4771,28 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "neg.d";
         break;
     case FOP(8, 17):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_roundl_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "round.l.d";
         break;
     case FOP(9, 17):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_truncl_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "trunc.l.d";
         break;
     case FOP(10, 17):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_ceill_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "ceil.l.d";
         break;
     case FOP(11, 17):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_floorl_d();
         GEN_STORE_FTN_FREG(fd, DT2);
@@ -4809,6 +4850,50 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "movn.d";
         break;
+    case FOP(21, 17):
+        gen_op_cp1_registers(fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_recip_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "recip.d";
+        break;
+    case FOP(22, 17):
+        gen_op_cp1_registers(fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_rsqrt_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "rsqrt.d";
+        break;
+    case FOP(28, 17):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT2, ft);
+        gen_op_float_recip2_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "recip2.d";
+        break;
+    case FOP(29, 17):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_recip1_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "recip1.d";
+        break;
+    case FOP(30, 17):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_rsqrt1_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "rsqrt1.d";
+        break;
+    case FOP(31, 17):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT2, ft);
+        gen_op_float_rsqrt2_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "rsqrt2.d";
+        break;
     case FOP(48, 17):
     case FOP(49, 17):
     case FOP(50, 17):
@@ -4825,13 +4910,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
     case FOP(61, 17):
     case FOP(62, 17):
     case FOP(63, 17):
-        gen_op_cp1_registers(fs | ft);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         if (ctx->opcode & (1 << 6)) {
+            gen_op_cp1_64bitmode();
             gen_cmpabs_d(func-48, cc);
             opn = condnames_abs[func-48];
         } else {
+            gen_op_cp1_registers(fs | ft);
             gen_cmp_d(func-48, cc);
             opn = condnames[func-48];
         }
@@ -4851,7 +4937,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "cvt.w.d";
         break;
     case FOP(37, 17):
-        gen_op_cp1_registers(fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_cvtl_d();
         GEN_STORE_FTN_FREG(fd, DT2);
@@ -4871,14 +4957,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "cvt.d.w";
         break;
     case FOP(32, 21):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_cvts_l();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "cvt.s.l";
         break;
     case FOP(33, 21):
-        gen_op_cp1_registers(fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_cvtd_l();
         GEN_STORE_FTN_FREG(fd, DT2);
@@ -4886,7 +4972,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         break;
     case FOP(38, 20):
     case FOP(38, 21):
-        gen_op_cp1_registers(fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_cvtps_pw();
@@ -4895,7 +4981,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "cvt.ps.pw";
         break;
     case FOP(0, 22):
-        gen_op_cp1_registers(fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -4906,7 +4992,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "add.ps";
         break;
     case FOP(1, 22):
-        gen_op_cp1_registers(fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -4917,7 +5003,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "sub.ps";
         break;
     case FOP(2, 22):
-        gen_op_cp1_registers(fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -4928,7 +5014,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "mul.ps";
         break;
     case FOP(5, 22):
-        gen_op_cp1_registers(fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_abs_ps();
@@ -4937,7 +5023,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "abs.ps";
         break;
     case FOP(6, 22):
-        gen_op_cp1_registers(fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_mov_ps();
@@ -4946,7 +5032,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "mov.ps";
         break;
     case FOP(7, 22):
-        gen_op_cp1_registers(fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_chs_ps();
@@ -4955,6 +5041,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "neg.ps";
         break;
     case FOP(17, 22):
+        gen_op_cp1_64bitmode();
         GEN_LOAD_REG_TN(T0, ft);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
@@ -4966,6 +5053,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "movcf.ps";
         break;
     case FOP(18, 22):
+        gen_op_cp1_64bitmode();
         GEN_LOAD_REG_TN(T0, ft);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
@@ -4977,6 +5065,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "movz.ps";
         break;
     case FOP(19, 22):
+        gen_op_cp1_64bitmode();
         GEN_LOAD_REG_TN(T0, ft);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
@@ -4988,7 +5077,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "movn.ps";
         break;
     case FOP(24, 22):
-        gen_op_cp1_registers(fs | fd | ft);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -4998,15 +5087,66 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         GEN_STORE_FTN_FREG(fd, WTH2);
         opn = "addr.ps";
         break;
+    case FOP(26, 22):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        GEN_LOAD_FREG_FTN(WTH1, ft);
+        gen_op_float_mulr_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "mulr.ps";
+        break;
+    case FOP(28, 22):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        GEN_LOAD_FREG_FTN(WTH2, fd);
+        gen_op_float_recip2_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "recip2.ps";
+        break;
+    case FOP(29, 22):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        gen_op_float_recip1_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "recip1.ps";
+        break;
+    case FOP(30, 22):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        gen_op_float_rsqrt1_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "rsqrt1.ps";
+        break;
+    case FOP(31, 22):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        GEN_LOAD_FREG_FTN(WTH2, fd);
+        gen_op_float_rsqrt2_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "rsqrt2.ps";
+        break;
     case FOP(32, 22):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_cvts_pu();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "cvt.s.pu";
         break;
     case FOP(36, 22):
-        gen_op_cp1_registers(fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_cvtpw_ps();
@@ -5015,14 +5155,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "cvt.pw.ps";
         break;
     case FOP(40, 22):
-        gen_op_cp1_registers(fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_cvts_pl();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "cvt.s.pl";
         break;
     case FOP(44, 22):
-        gen_op_cp1_registers(fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         gen_op_float_pll_ps();
@@ -5030,7 +5170,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "pll.ps";
         break;
     case FOP(45, 22):
-        gen_op_cp1_registers(fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH1, ft);
         gen_op_float_plu_ps();
@@ -5038,7 +5178,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "plu.ps";
         break;
     case FOP(46, 22):
-        gen_op_cp1_registers(fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         gen_op_float_pul_ps();
@@ -5046,7 +5186,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
         opn = "pul.ps";
         break;
     case FOP(47, 22):
-        gen_op_cp1_registers(fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WTH1, ft);
         gen_op_float_puu_ps();
@@ -5069,7 +5209,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
     case FOP(61, 22):
     case FOP(62, 22):
     case FOP(63, 22):
-        gen_op_cp1_registers(fs | ft);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -5106,6 +5246,8 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd,
 {
     const char *opn = "extended float load/store";
 
+    /* All of those work only on 64bit FPUs. */
+    gen_op_cp1_64bitmode();
     GEN_LOAD_REG_TN(T0, base);
     GEN_LOAD_REG_TN(T1, index);
     /* Don't do NOP if destination is zero: we must perform the actual
@@ -5156,7 +5298,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd,
     const char *opn = "flt3_arith";
 
     /* All of those work only on 64bit FPUs. */
-    gen_op_cp1_registers(fd | fr | fs | ft);
+    gen_op_cp1_64bitmode();
     switch (opc) {
     case OPC_ALNV_PS:
         GEN_LOAD_REG_TN(T0, fr);