128-bit float support for user mode
authorblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 25 Nov 2007 18:40:20 +0000 (18:40 +0000)
committerblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 25 Nov 2007 18:40:20 +0000 (18:40 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3740 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-all.h
fpu/softfloat.c
fpu/softfloat.h
qemu-tech.texi
target-sparc/cpu.h
target-sparc/exec.h
target-sparc/fop_template.h
target-sparc/op.c
target-sparc/op_helper.c
target-sparc/op_mem.h
target-sparc/translate.c

index f4db592..6b78435 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -135,6 +135,36 @@ typedef union {
     uint64_t ll;
 } CPU_DoubleU;
 
+#ifdef TARGET_SPARC
+typedef union {
+    float128 q;
+#if defined(WORDS_BIGENDIAN) \
+    || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
+    struct {
+        uint32_t upmost;
+        uint32_t upper;
+        uint32_t lower;
+        uint32_t lowest;
+    } l;
+    struct {
+        uint64_t upper;
+        uint64_t lower;
+    } ll;
+#else
+    struct {
+        uint32_t lowest;
+        uint32_t lower;
+        uint32_t upper;
+        uint32_t upmost;
+    } l;
+    struct {
+        uint64_t lower;
+        uint64_t upper;
+    } ll;
+#endif
+} CPU_QuadU;
+#endif
+
 /* CPU memory access without any memory or io remapping */
 
 /*
index e30f22f..3ec1e0d 100644 (file)
@@ -5421,6 +5421,50 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM )  \
 COMPARE(32, 0xff)
 COMPARE(64, 0x7ff)
 
+INLINE int float128_compare_internal( float128 a, float128 b,
+                                      int is_quiet STATUS_PARAM )
+{
+    flag aSign, bSign;
+
+    if (( ( extractFloat128Exp( a ) == 0x7fff ) &&
+          ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) ||
+        ( ( extractFloat128Exp( b ) == 0x7fff ) &&
+          ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) {
+        if (!is_quiet ||
+            float128_is_signaling_nan( a ) ||
+            float128_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+        }
+        return float_relation_unordered;
+    }
+    aSign = extractFloat128Sign( a );
+    bSign = extractFloat128Sign( b );
+    if ( aSign != bSign ) {
+        if ( ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0 ) {
+            /* zero case */
+            return float_relation_equal;
+        } else {
+            return 1 - (2 * aSign);
+        }
+    } else {
+        if (a.low == b.low && a.high == b.high) {
+            return float_relation_equal;
+        } else {
+            return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) ));
+        }
+    }
+}
+
+int float128_compare( float128 a, float128 b STATUS_PARAM )
+{
+    return float128_compare_internal(a, b, 0 STATUS_VAR);
+}
+
+int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
+{
+    return float128_compare_internal(a, b, 1 STATUS_VAR);
+}
+
 /* Multiply A by 2 raised to the power N.  */
 float32 float32_scalbn( float32 a, int n STATUS_PARAM )
 {
index 84cffdd..5f95d06 100644 (file)
@@ -415,6 +415,8 @@ int float128_lt( float128, float128 STATUS_PARAM );
 int float128_eq_signaling( float128, float128 STATUS_PARAM );
 int float128_le_quiet( float128, float128 STATUS_PARAM );
 int float128_lt_quiet( float128, float128 STATUS_PARAM );
+int float128_compare( float128, float128 STATUS_PARAM );
+int float128_compare_quiet( float128, float128 STATUS_PARAM );
 int float128_is_nan( float128 );
 int float128_is_signaling_nan( float128 );
 float128 float128_scalbn( float128, int STATUS_PARAM );
index 9147096..cc027cf 100644 (file)
@@ -212,8 +212,7 @@ Current QEMU limitations:
 
 @item IPC syscalls are missing.
 
-@item 128-bit floating point operations are not supported, though none of the
-real CPUs implement them either.  Floating point exception support is untested.
+@item Floating point exception support is buggy.
 
 @item Atomic instructions are not correctly implemented.
 
index 319e6e8..783a850 100644 (file)
@@ -222,6 +222,9 @@ typedef struct CPUSPARCState {
     /* temporary float registers */
     float32 ft0, ft1;
     float64 dt0, dt1;
+#if defined(CONFIG_USER_ONLY)
+    float128 qt0, qt1;
+#endif
     float_status fp_status;
 #if defined(TARGET_SPARC64)
 #define MAXTL 4
index 81c4741..db19da6 100644 (file)
@@ -41,6 +41,10 @@ register uint32_t T2 asm(AREG3);
 #define FT1 (env->ft1)
 #define DT0 (env->dt0)
 #define DT1 (env->dt1)
+#if defined(CONFIG_USER_ONLY)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+#endif
 
 #include "cpu.h"
 #include "exec-all.h"
@@ -65,6 +69,13 @@ void do_fcmps(void);
 void do_fcmpd(void);
 void do_fcmpes(void);
 void do_fcmped(void);
+#if defined(CONFIG_USER_ONLY)
+void do_fitoq(void);
+void do_fabsq(void);
+void do_fsqrtq(void);
+void do_fcmpq(void);
+void do_fcmpeq(void);
+#endif
 #ifdef TARGET_SPARC64
 void do_fabsd(void);
 void do_fcmps_fcc1(void);
@@ -79,6 +90,14 @@ void do_fcmpes_fcc2(void);
 void do_fcmped_fcc2(void);
 void do_fcmpes_fcc3(void);
 void do_fcmped_fcc3(void);
+#if defined(CONFIG_USER_ONLY)
+void do_fcmpq_fcc1(void);
+void do_fcmpq_fcc2(void);
+void do_fcmpq_fcc3(void);
+void do_fcmpeq_fcc1(void);
+void do_fcmpeq_fcc2(void);
+void do_fcmpeq_fcc3(void);
+#endif
 void do_popc();
 void do_wrpstate();
 void do_done();
index 0598b30..0c045b8 100644 (file)
@@ -77,5 +77,52 @@ void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void)
     *p = u.l.upper;
 }
 
+#if defined(CONFIG_USER_ONLY)
+/* quad floating point registers moves */
+void OPPROTO glue(op_load_fpr_QT0_fpr, REGNAME)(void)
+{
+    CPU_QuadU u;
+    uint32_t *p = (uint32_t *)&REG;
+    u.l.lowest = *(p + 3);
+    u.l.lower = *(p + 2);
+    u.l.upper = *(p + 1);
+    u.l.upmost = *p;
+    QT0 = u.q;
+}
+
+void OPPROTO glue(op_store_QT0_fpr_fpr, REGNAME)(void)
+{
+    CPU_QuadU u;
+    uint32_t *p = (uint32_t *)&REG;
+    u.q = QT0;
+    *(p + 3) = u.l.lowest;
+    *(p + 2) = u.l.lower;
+    *(p + 1) = u.l.upper;
+    *p = u.l.upmost;
+}
+
+void OPPROTO glue(op_load_fpr_QT1_fpr, REGNAME)(void)
+{
+    CPU_QuadU u;
+    uint32_t *p = (uint32_t *)&REG;
+    u.l.lowest = *(p + 3);
+    u.l.lower = *(p + 2);
+    u.l.upper = *(p + 1);
+    u.l.upmost = *p;
+    QT1 = u.q;
+}
+
+void OPPROTO glue(op_store_QT1_fpr_fpr, REGNAME)(void)
+{
+    CPU_QuadU u;
+    uint32_t *p = (uint32_t *)&REG;
+    u.q = QT1;
+    *(p + 3) = u.l.lowest;
+    *(p + 2) = u.l.lower;
+    *(p + 1) = u.l.upper;
+    *p = u.l.upmost;
+}
+#endif
+
 #undef REG
 #undef REGNAME
index 55ea2b9..1fb48cf 100644 (file)
@@ -1581,6 +1581,7 @@ void OPPROTO op_clear_ieee_excp_and_FTT(void)
 
 #define F_OP(name, p) void OPPROTO op_f##name##p(void)
 
+#if defined(CONFIG_USER_ONLY)
 #define F_BINOP(name)                                           \
     F_OP(name, s)                                               \
     {                                                           \
@@ -1593,7 +1594,28 @@ void OPPROTO op_clear_ieee_excp_and_FTT(void)
         set_float_exception_flags(0, &env->fp_status);          \
         DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
         check_ieee_exceptions();                                \
+    }                                                           \
+    F_OP(name, q)                                               \
+    {                                                           \
+        set_float_exception_flags(0, &env->fp_status);          \
+        QT0 = float128_ ## name (QT0, QT1, &env->fp_status);    \
+        check_ieee_exceptions();                                \
     }
+#else
+#define F_BINOP(name)                                           \
+    F_OP(name, s)                                               \
+    {                                                           \
+        set_float_exception_flags(0, &env->fp_status);          \
+        FT0 = float32_ ## name (FT0, FT1, &env->fp_status);     \
+        check_ieee_exceptions();                                \
+    }                                                           \
+    F_OP(name, d)                                               \
+    {                                                           \
+        set_float_exception_flags(0, &env->fp_status);          \
+        DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
+        check_ieee_exceptions();                                \
+    }
+#endif
 
 F_BINOP(add);
 F_BINOP(sub);
@@ -1610,6 +1632,18 @@ void OPPROTO op_fsmuld(void)
     check_ieee_exceptions();
 }
 
+#if defined(CONFIG_USER_ONLY)
+void OPPROTO op_fdmulq(void)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
+                       float64_to_float128(DT1, &env->fp_status),
+                       &env->fp_status);
+    check_ieee_exceptions();
+}
+#endif
+
+#if defined(CONFIG_USER_ONLY)
 #define F_HELPER(name)    \
     F_OP(name, s)         \
     {                     \
@@ -1618,7 +1652,22 @@ void OPPROTO op_fsmuld(void)
     F_OP(name, d)         \
     {                     \
         do_f##name##d();  \
+    }                     \
+    F_OP(name, q)         \
+    {                     \
+        do_f##name##q();  \
     }
+#else
+#define F_HELPER(name)    \
+    F_OP(name, s)         \
+    {                     \
+        do_f##name##s();  \
+    }                     \
+    F_OP(name, d)         \
+    {                     \
+        do_f##name##d();  \
+    }
+#endif
 
 F_HELPER(sqrt);
 
@@ -1646,6 +1695,18 @@ F_OP(abs, d)
     do_fabsd();
 }
 
+#if defined(CONFIG_USER_ONLY)
+F_OP(neg, q)
+{
+    QT0 = float128_chs(QT1);
+}
+
+F_OP(abs, q)
+{
+    do_fabsd();
+}
+#endif
+
 void OPPROTO op_fcmps_fcc1(void)
 {
     do_fcmps_fcc1();
@@ -1706,6 +1767,38 @@ void OPPROTO op_fcmped_fcc3(void)
     do_fcmped_fcc3();
 }
 
+#if defined(CONFIG_USER_ONLY)
+void OPPROTO op_fcmpq_fcc1(void)
+{
+    do_fcmpq_fcc1();
+}
+
+void OPPROTO op_fcmpq_fcc2(void)
+{
+    do_fcmpq_fcc2();
+}
+
+void OPPROTO op_fcmpq_fcc3(void)
+{
+    do_fcmpq_fcc3();
+}
+
+void OPPROTO op_fcmpeq_fcc1(void)
+{
+    do_fcmpeq_fcc1();
+}
+
+void OPPROTO op_fcmpeq_fcc2(void)
+{
+    do_fcmpeq_fcc2();
+}
+
+void OPPROTO op_fcmpeq_fcc3(void)
+{
+    do_fcmpeq_fcc3();
+}
+#endif
+
 #endif
 
 /* Integer to float conversion.  */
@@ -1729,6 +1822,15 @@ F_OP(ito, d)
     check_ieee_exceptions();
 }
 
+#if defined(CONFIG_USER_ONLY)
+F_OP(ito, q)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    QT0 = int32_to_float128(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
+}
+#endif
+
 #ifdef TARGET_SPARC64
 F_OP(xto, s)
 {
@@ -1743,6 +1845,14 @@ F_OP(xto, d)
     DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
     check_ieee_exceptions();
 }
+#if defined(CONFIG_USER_ONLY)
+F_OP(xto, q)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
+    check_ieee_exceptions();
+}
+#endif
 #endif
 #endif
 #undef F_HELPER
@@ -1762,6 +1872,36 @@ void OPPROTO op_fstod(void)
     check_ieee_exceptions();
 }
 
+#if defined(CONFIG_USER_ONLY)
+void OPPROTO op_fqtos(void)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FT0 = float128_to_float32(QT1, &env->fp_status);
+    check_ieee_exceptions();
+}
+
+void OPPROTO op_fstoq(void)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    QT0 = float32_to_float128(FT1, &env->fp_status);
+    check_ieee_exceptions();
+}
+
+void OPPROTO op_fqtod(void)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    DT0 = float128_to_float64(QT1, &env->fp_status);
+    check_ieee_exceptions();
+}
+
+void OPPROTO op_fdtoq(void)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    QT0 = float64_to_float128(DT1, &env->fp_status);
+    check_ieee_exceptions();
+}
+#endif
+
 /* Float to integer conversion.  */
 void OPPROTO op_fstoi(void)
 {
@@ -1777,6 +1917,15 @@ void OPPROTO op_fdtoi(void)
     check_ieee_exceptions();
 }
 
+#if defined(CONFIG_USER_ONLY)
+void OPPROTO op_fqtoi(void)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    *((int32_t *)&FT0) = float128_to_int32_round_to_zero(QT1, &env->fp_status);
+    check_ieee_exceptions();
+}
+#endif
+
 #ifdef TARGET_SPARC64
 void OPPROTO op_fstox(void)
 {
@@ -1792,6 +1941,15 @@ void OPPROTO op_fdtox(void)
     check_ieee_exceptions();
 }
 
+#if defined(CONFIG_USER_ONLY)
+void OPPROTO op_fqtox(void)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
+    check_ieee_exceptions();
+}
+#endif
+
 void OPPROTO op_fmovs_cc(void)
 {
     if (T2)
@@ -1804,6 +1962,14 @@ void OPPROTO op_fmovd_cc(void)
         DT0 = DT1;
 }
 
+#if defined(CONFIG_USER_ONLY)
+void OPPROTO op_fmovq_cc(void)
+{
+    if (T2)
+        QT0 = QT1;
+}
+#endif
+
 void OPPROTO op_mov_cc(void)
 {
     if (T2)
index c643bdb..48f5fc6 100644 (file)
@@ -97,6 +97,13 @@ void do_fabsd(void)
 {
     DT0 = float64_abs(DT1);
 }
+
+#if defined(CONFIG_USER_ONLY)
+void do_fabsq(void)
+{
+    QT0 = float128_abs(QT1);
+}
+#endif
 #endif
 
 void do_fsqrts(void)
@@ -113,6 +120,15 @@ void do_fsqrtd(void)
     check_ieee_exceptions();
 }
 
+#if defined(CONFIG_USER_ONLY)
+void do_fsqrtq(void)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    QT0 = float128_sqrt(QT1, &env->fp_status);
+    check_ieee_exceptions();
+}
+#endif
+
 #define GEN_FCMP(name, size, reg1, reg2, FS, TRAP)                      \
     void glue(do_, name) (void)                                         \
     {                                                                   \
@@ -148,6 +164,11 @@ GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
 GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
 GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
 
+#ifdef CONFIG_USER_ONLY
+GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
+GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
+#endif
+
 #ifdef TARGET_SPARC64
 GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
 GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
@@ -166,6 +187,14 @@ GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
 
 GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
 GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
+#ifdef CONFIG_USER_ONLY
+GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
+GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
+GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
+GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
+GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
+GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
+#endif
 #endif
 
 #ifndef TARGET_SPARC64
@@ -1374,6 +1403,11 @@ void helper_ldf_asi(int asi, int size, int rd)
     case 8:
         *((int64_t *)&DT0) = T1;
         break;
+#if defined(CONFIG_USER_ONLY)
+    case 16:
+        // XXX
+        break;
+#endif
     }
     T1 = tmp_T1;
 }
@@ -1417,6 +1451,11 @@ void helper_stf_asi(int asi, int size, int rd)
     case 8:
         T1 = *((int64_t *)&DT0);
         break;
+#if defined(CONFIG_USER_ONLY)
+    case 16:
+        // XXX
+        break;
+#endif
     }
     helper_st_asi(asi, size);
     T1 = tmp_T1;
index 4af00b3..894fc36 100644 (file)
@@ -85,6 +85,28 @@ void OPPROTO glue(op_lddf, MEMSUFFIX) (void)
     DT0 = glue(ldfq, MEMSUFFIX)(ADDR(T0));
 }
 
+#if defined(CONFIG_USER_ONLY)
+void OPPROTO glue(op_ldqf, MEMSUFFIX) (void)
+{
+    // XXX add 128 bit load
+    CPU_QuadU u;
+
+    u.ll.upper = glue(ldq, MEMSUFFIX)(ADDR(T0));
+    u.ll.lower = glue(ldq, MEMSUFFIX)(ADDR(T0 + 8));
+    QT0 = u.q;
+}
+
+void OPPROTO glue(op_stqf, MEMSUFFIX) (void)
+{
+    // XXX add 128 bit store
+    CPU_QuadU u;
+
+    u.q = QT0;
+    glue(stq, MEMSUFFIX)(ADDR(T0), u.ll.upper);
+    glue(stq, MEMSUFFIX)(ADDR(T0 + 8), u.ll.lower);
+}
+#endif
+
 #ifdef TARGET_SPARC64
 void OPPROTO glue(op_lduw, MEMSUFFIX)(void)
 {
index 1e373ce..7dee0ad 100644 (file)
@@ -25,7 +25,6 @@
    Rest of V9 instructions, VIS instructions
    NPC/PC static optimisations (use JUMP_TB when possible)
    Optimize synthetic instructions
-   128-bit float
 */
 
 #include <stdarg.h>
@@ -93,8 +92,10 @@ enum {
 
 #ifdef TARGET_SPARC64
 #define DFPREG(r) (((r & 1) << 5) | (r & 0x1e))
+#define QFPREG(r) (((r & 1) << 5) | (r & 0x1c))
 #else
 #define DFPREG(r) (r & 0x1e)
+#define QFPREG(r) (r & 0x1c)
 #endif
 
 #ifdef USE_DIRECT_JUMP
@@ -351,6 +352,13 @@ GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf);
 GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf);
 GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf);
 
+#if defined(CONFIG_USER_ONLY)
+GEN32(gen_op_load_fpr_QT0, gen_op_load_fpr_QT0_fprf);
+GEN32(gen_op_load_fpr_QT1, gen_op_load_fpr_QT1_fprf);
+GEN32(gen_op_store_QT0_fpr, gen_op_store_QT0_fpr_fprf);
+GEN32(gen_op_store_QT1_fpr, gen_op_store_QT1_fpr_fprf);
+#endif
+
 /* moves */
 #ifdef CONFIG_USER_ONLY
 #define supervisor(dc) 0
@@ -1060,6 +1068,15 @@ static GenOpFunc * const gen_fcmpd[4] = {
     gen_op_fcmpd_fcc3,
 };
 
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc * const gen_fcmpq[4] = {
+    gen_op_fcmpq,
+    gen_op_fcmpq_fcc1,
+    gen_op_fcmpq_fcc2,
+    gen_op_fcmpq_fcc3,
+};
+#endif
+
 static GenOpFunc * const gen_fcmpes[4] = {
     gen_op_fcmpes,
     gen_op_fcmpes_fcc1,
@@ -1074,6 +1091,14 @@ static GenOpFunc * const gen_fcmped[4] = {
     gen_op_fcmped_fcc3,
 };
 
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc * const gen_fcmpeq[4] = {
+    gen_op_fcmpeq,
+    gen_op_fcmpeq_fcc1,
+    gen_op_fcmpeq_fcc2,
+    gen_op_fcmpeq_fcc3,
+};
+#endif
 #endif
 
 static int gen_trap_ifnofpu(DisasContext * dc)
@@ -1484,7 +1509,14 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
                     case 0x2b: /* fsqrtq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fsqrtq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0x41:
                         gen_op_load_fpr_FT0(rs1);
                         gen_op_load_fpr_FT1(rs2);
@@ -1498,7 +1530,15 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
                     case 0x43: /* faddq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT0(QFPREG(rs1));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_faddq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0x45:
                         gen_op_load_fpr_FT0(rs1);
                         gen_op_load_fpr_FT1(rs2);
@@ -1512,7 +1552,15 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
                     case 0x47: /* fsubq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT0(QFPREG(rs1));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fsubq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0x49:
                         gen_op_load_fpr_FT0(rs1);
                         gen_op_load_fpr_FT1(rs2);
@@ -1526,7 +1574,15 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(rd);
                         break;
                     case 0x4b: /* fmulq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT0(QFPREG(rs1));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fmulq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0x4d:
                         gen_op_load_fpr_FT0(rs1);
                         gen_op_load_fpr_FT1(rs2);
@@ -1540,7 +1596,15 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
                     case 0x4f: /* fdivq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT0(QFPREG(rs1));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fdivq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0x69:
                         gen_op_load_fpr_FT0(rs1);
                         gen_op_load_fpr_FT1(rs2);
@@ -1548,7 +1612,15 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
                     case 0x6e: /* fdmulq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_DT0(DFPREG(rs1));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fdmulq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0xc4:
                         gen_op_load_fpr_FT1(rs2);
                         gen_op_fitos();
@@ -1560,7 +1632,14 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_FT0_fpr(rd);
                         break;
                     case 0xc7: /* fqtos */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fqtos();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0xc8:
                         gen_op_load_fpr_FT1(rs2);
                         gen_op_fitod();
@@ -1572,13 +1651,41 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
                     case 0xcb: /* fqtod */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fqtod();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0xcc: /* fitoq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fitoq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0xcd: /* fstoq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fstoq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0xce: /* fdtoq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fdtoq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0xd1:
                         gen_op_load_fpr_FT1(rs2);
                         gen_op_fstoi();
@@ -1590,22 +1697,55 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_FT0_fpr(rd);
                         break;
                     case 0xd3: /* fqtoi */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fqtoi();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+#else
                         goto nfpu_insn;
+#endif
 #ifdef TARGET_SPARC64
                     case 0x2: /* V9 fmovd */
                         gen_op_load_fpr_DT0(DFPREG(rs2));
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
+                    case 0x3: /* V9 fmovq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT0(QFPREG(rs2));
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
+                        goto nfpu_insn;
+#endif
                     case 0x6: /* V9 fnegd */
                         gen_op_load_fpr_DT1(DFPREG(rs2));
                         gen_op_fnegd();
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
+                    case 0x7: /* V9 fnegq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fnegq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
+                        goto nfpu_insn;
+#endif
                     case 0xa: /* V9 fabsd */
                         gen_op_load_fpr_DT1(DFPREG(rs2));
                         gen_op_fabsd();
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
+                    case 0xb: /* V9 fabsq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fabsq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
+                        goto nfpu_insn;
+#endif
                     case 0x81: /* V9 fstox */
                         gen_op_load_fpr_FT1(rs2);
                         gen_op_fstox();
@@ -1616,6 +1756,15 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_fdtox();
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
+                    case 0x83: /* V9 fqtox */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        gen_op_fqtox();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+#else
+                        goto nfpu_insn;
+#endif
                     case 0x84: /* V9 fxtos */
                         gen_op_load_fpr_DT1(DFPREG(rs2));
                         gen_op_fxtos();
@@ -1626,13 +1775,16 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_fxtod();
                         gen_op_store_DT0_fpr(DFPREG(rd));
                         break;
-                    case 0x3: /* V9 fmovq */
-                    case 0x7: /* V9 fnegq */
-                    case 0xb: /* V9 fabsq */
-                    case 0x83: /* V9 fqtox */
                     case 0x8c: /* V9 fxtoq */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fxtoq();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
 #endif
+#endif
                     default:
                         goto illegal_insn;
                 }
@@ -1670,7 +1822,20 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_DT0_fpr(rd);
                     break;
                 } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr
+#if defined(CONFIG_USER_ONLY)
+                    cond = GET_FIELD_SP(insn, 14, 17);
+                    gen_op_load_fpr_QT0(QFPREG(rd));
+                    gen_op_load_fpr_QT1(QFPREG(rs2));
+                    flush_T2(dc);
+                    rs1 = GET_FIELD(insn, 13, 17);
+                    gen_movl_reg_T0(rs1);
+                    gen_cond_reg(cond);
+                    gen_op_fmovq_cc();
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+#else
                     goto nfpu_insn;
+#endif
                 }
 #endif
                 switch (xop) {
@@ -1694,7 +1859,18 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(rd);
                         break;
                     case 0x003: /* V9 fmovqcc %fcc0 */
+#if defined(CONFIG_USER_ONLY)
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_QT0(QFPREG(rd));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        flush_T2(dc);
+                        gen_fcond[0][cond]();
+                        gen_op_fmovq_cc();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0x041: /* V9 fmovscc %fcc1 */
                         cond = GET_FIELD_SP(insn, 14, 17);
                         gen_op_load_fpr_FT0(rd);
@@ -1714,7 +1890,18 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(rd);
                         break;
                     case 0x043: /* V9 fmovqcc %fcc1 */
+#if defined(CONFIG_USER_ONLY)
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_QT0(QFPREG(rd));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        flush_T2(dc);
+                        gen_fcond[1][cond]();
+                        gen_op_fmovq_cc();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0x081: /* V9 fmovscc %fcc2 */
                         cond = GET_FIELD_SP(insn, 14, 17);
                         gen_op_load_fpr_FT0(rd);
@@ -1734,7 +1921,18 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(rd);
                         break;
                     case 0x083: /* V9 fmovqcc %fcc2 */
+#if defined(CONFIG_USER_ONLY)
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_QT0(rd);
+                        gen_op_load_fpr_QT1(rs2);
+                        flush_T2(dc);
+                        gen_fcond[2][cond]();
+                        gen_op_fmovq_cc();
+                        gen_op_store_QT0_fpr(rd);
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0x0c1: /* V9 fmovscc %fcc3 */
                         cond = GET_FIELD_SP(insn, 14, 17);
                         gen_op_load_fpr_FT0(rd);
@@ -1754,7 +1952,18 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(rd);
                         break;
                     case 0x0c3: /* V9 fmovqcc %fcc3 */
+#if defined(CONFIG_USER_ONLY)
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_QT0(QFPREG(rd));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+                        flush_T2(dc);
+                        gen_fcond[3][cond]();
+                        gen_op_fmovq_cc();
+                        gen_op_store_QT0_fpr(QFPREG(rd));
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0x101: /* V9 fmovscc %icc */
                         cond = GET_FIELD_SP(insn, 14, 17);
                         gen_op_load_fpr_FT0(rd);
@@ -1774,7 +1983,18 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(rd);
                         break;
                     case 0x103: /* V9 fmovqcc %icc */
+#if defined(CONFIG_USER_ONLY)
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_QT0(rd);
+                        gen_op_load_fpr_QT1(rs2);
+                        flush_T2(dc);
+                        gen_cond[0][cond]();
+                        gen_op_fmovq_cc();
+                        gen_op_store_QT0_fpr(rd);
+                        break;
+#else
                         goto nfpu_insn;
+#endif
                     case 0x181: /* V9 fmovscc %xcc */
                         cond = GET_FIELD_SP(insn, 14, 17);
                         gen_op_load_fpr_FT0(rd);
@@ -1794,9 +2014,20 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_store_DT0_fpr(rd);
                         break;
                     case 0x183: /* V9 fmovqcc %xcc */
+#if defined(CONFIG_USER_ONLY)
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_QT0(rd);
+                        gen_op_load_fpr_QT1(rs2);
+                        flush_T2(dc);
+                        gen_cond[1][cond]();
+                        gen_op_fmovq_cc();
+                        gen_op_store_QT0_fpr(rd);
+                        break;
+#else
                         goto nfpu_insn;
 #endif
-                    case 0x51: /* V9 %fcc */
+#endif
+                    case 0x51: /* fcmps, V9 %fcc */
                         gen_op_load_fpr_FT0(rs1);
                         gen_op_load_fpr_FT1(rs2);
 #ifdef TARGET_SPARC64
@@ -1805,7 +2036,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_fcmps();
 #endif
                         break;
-                    case 0x52: /* V9 %fcc */
+                    case 0x52: /* fcmpd, V9 %fcc */
                         gen_op_load_fpr_DT0(DFPREG(rs1));
                         gen_op_load_fpr_DT1(DFPREG(rs2));
 #ifdef TARGET_SPARC64
@@ -1814,8 +2045,19 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_fcmpd();
 #endif
                         break;
-                    case 0x53: /* fcmpq */
+                    case 0x53: /* fcmpq, V9 %fcc */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT0(QFPREG(rs1));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+#ifdef TARGET_SPARC64
+                        gen_fcmpq[rd & 3]();
+#else
+                        gen_op_fcmpq();
+#endif
+                        break;
+#else /* !defined(CONFIG_USER_ONLY) */
                         goto nfpu_insn;
+#endif
                     case 0x55: /* fcmpes, V9 %fcc */
                         gen_op_load_fpr_FT0(rs1);
                         gen_op_load_fpr_FT1(rs2);
@@ -1834,8 +2076,19 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_fcmped();
 #endif
                         break;
-                    case 0x57: /* fcmpeq */
+                    case 0x57: /* fcmpeq, V9 %fcc */
+#if defined(CONFIG_USER_ONLY)
+                        gen_op_load_fpr_QT0(QFPREG(rs1));
+                        gen_op_load_fpr_QT1(QFPREG(rs2));
+#ifdef TARGET_SPARC64
+                        gen_fcmpeq[rd & 3]();
+#else
+                        gen_op_fcmpeq();
+#endif
+                        break;
+#else/* !defined(CONFIG_USER_ONLY) */
                         goto nfpu_insn;
+#endif
                     default:
                         goto illegal_insn;
                 }
@@ -3095,8 +3348,14 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x3d: /* V9 prefetcha, no effect */
                     goto skip_move;
                 case 0x32: /* V9 ldqfa */
+#if defined(CONFIG_USER_ONLY)
+                    gen_op_check_align_T0_3();
+                    gen_ldf_asi(insn, 16);
+                    goto skip_move;
+#else
                     goto nfpu_insn;
 #endif
+#endif
                 default:
                     goto illegal_insn;
                 }
@@ -3119,7 +3378,14 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_ldfsr();
                     break;
                 case 0x22:      /* load quad fpreg */
+#if defined(CONFIG_USER_ONLY)
+                    gen_op_check_align_T0_7();
+                    gen_op_ldst(ldqf);
+                    gen_op_store_QT0_fpr(QFPREG(rd));
+                    break;
+#else
                     goto nfpu_insn;
+#endif
                 case 0x23:      /* load double fpreg */
                     gen_op_check_align_T0_7();
                     gen_op_ldst(lddf);
@@ -3225,14 +3491,29 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_stfsr();
                     gen_op_ldst(stf);
                     break;
-#if !defined(CONFIG_USER_ONLY)
-                case 0x26: /* stdfq */
+                case 0x26:
+#ifdef TARGET_SPARC64
+#if defined(CONFIG_USER_ONLY)
+                    /* V9 stqf, store quad fpreg */
+                    gen_op_check_align_T0_7();
+                    gen_op_load_fpr_QT0(QFPREG(rd));
+                    gen_op_ldst(stqf);
+                    break;
+#else
+                    goto nfpu_insn;
+#endif
+#else /* !TARGET_SPARC64 */
+                    /* stdfq, store floating point queue */
+#if defined(CONFIG_USER_ONLY)
+                    goto illegal_insn;
+#else
                     if (!supervisor(dc))
                         goto priv_insn;
                     if (gen_trap_ifnofpu(dc))
                         goto jmp_insn;
                     goto nfq_insn;
 #endif
+#endif
                 case 0x27:
                     gen_op_check_align_T0_7();
                     gen_op_load_fpr_DT0(DFPREG(rd));
@@ -3249,6 +3530,15 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_load_fpr_FT0(rd);
                     gen_stf_asi(insn, 4);
                     break;
+                case 0x36: /* V9 stqfa */
+#if defined(CONFIG_USER_ONLY)
+                    gen_op_check_align_T0_7();
+                    gen_op_load_fpr_QT0(QFPREG(rd));
+                    gen_stf_asi(insn, 16);
+                    break;
+#else
+                    goto nfpu_insn;
+#endif
                 case 0x37: /* V9 stdfa */
                     gen_op_check_align_T0_3();
                     gen_op_load_fpr_DT0(DFPREG(rd));
@@ -3268,8 +3558,6 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_casx_asi(insn);
                     gen_movl_T1_reg(rd);
                     break;
-                case 0x36: /* V9 stqfa */
-                    goto nfpu_insn;
 #else
                 case 0x34: /* stc */
                 case 0x35: /* stcsr */
@@ -3311,19 +3599,19 @@ static void disas_sparc_insn(DisasContext * dc)
     gen_op_exception(TT_PRIV_INSN);
     dc->is_br = 1;
     return;
-#endif
  nfpu_insn:
     save_state(dc);
     gen_op_fpexception_im(FSR_FTT_UNIMPFPOP);
     dc->is_br = 1;
     return;
-#if !defined(CONFIG_USER_ONLY)
+#ifndef TARGET_SPARC64
  nfq_insn:
     save_state(dc);
     gen_op_fpexception_im(FSR_FTT_SEQ_ERROR);
     dc->is_br = 1;
     return;
 #endif
+#endif
 #ifndef TARGET_SPARC64
  ncp_insn:
     save_state(dc);