Handle cpu_model in copy_cpu(), by Kirill A. Shutemov.
[qemu] / target-sparc / translate.c
index cc8402c..ecec372 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>
@@ -54,6 +53,8 @@ typedef struct DisasContext {
     struct TranslationBlock *tb;
 } DisasContext;
 
+typedef struct sparc_def_t sparc_def_t;
+
 struct sparc_def_t {
     const unsigned char *name;
     target_ulong iu_version;
@@ -62,6 +63,8 @@ struct sparc_def_t {
     uint32_t mmu_bm;
 };
 
+static const sparc_def_t *cpu_sparc_find_by_name(const unsigned char *name);
+
 static uint16_t *gen_opc_ptr;
 static uint32_t *gen_opparam_ptr;
 extern FILE *logfile;
@@ -89,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
@@ -347,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
@@ -428,11 +440,10 @@ static inline void gen_st_asi(int insn, int size)
     }
 }
 
-static inline void gen_ldf_asi(int insn, int size)
+static inline void gen_ldf_asi(int insn, int size, int rd)
 {
-    int asi, offset, rd;
+    int asi, offset;
 
-    rd = DFPREG(GET_FIELD(insn, 2, 6));
     if (IS_IMM) {
         offset = GET_FIELD(insn, 25, 31);
         gen_op_ldf_asi_reg(offset, size, rd);
@@ -442,11 +453,10 @@ static inline void gen_ldf_asi(int insn, int size)
     }
 }
 
-static inline void gen_stf_asi(int insn, int size)
+static inline void gen_stf_asi(int insn, int size, int rd)
 {
-    int asi, offset, rd;
+    int asi, offset;
 
-    rd = DFPREG(GET_FIELD(insn, 2, 6));
     if (IS_IMM) {
         offset = GET_FIELD(insn, 25, 31);
         gen_op_stf_asi_reg(offset, size, rd);
@@ -1056,6 +1066,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,
@@ -1070,6 +1089,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)
@@ -1480,7 +1507,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);
@@ -1494,7 +1528,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);
@@ -1508,7 +1550,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);
@@ -1519,10 +1569,18 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_load_fpr_DT0(DFPREG(rs1));
                         gen_op_load_fpr_DT1(DFPREG(rs2));
                         gen_op_fmuld();
-                        gen_op_store_DT0_fpr(rd);
+                        gen_op_store_DT0_fpr(DFPREG(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);
@@ -1536,7 +1594,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);
@@ -1544,7 +1610,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();
@@ -1556,7 +1630,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();
@@ -1568,40 +1649,101 @@ 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();
                         gen_op_store_FT0_fpr(rd);
                         break;
                     case 0xd2:
-                        gen_op_load_fpr_DT1(rs2);
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
                         gen_op_fdtoi();
                         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();
@@ -1612,6 +1754,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();
@@ -1622,13 +1773,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;
                 }
@@ -1656,17 +1810,30 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr
                     cond = GET_FIELD_SP(insn, 14, 17);
-                    gen_op_load_fpr_DT0(rd);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rd));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     flush_T2(dc);
                     rs1 = GET_FIELD(insn, 13, 17);
                     gen_movl_reg_T0(rs1);
                     gen_cond_reg(cond);
                     gen_op_fmovs_cc();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(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) {
@@ -1682,15 +1849,26 @@ static void disas_sparc_insn(DisasContext * dc)
                         break;
                     case 0x002: /* V9 fmovdcc %fcc0 */
                         cond = GET_FIELD_SP(insn, 14, 17);
-                        gen_op_load_fpr_DT0(rd);
-                        gen_op_load_fpr_DT1(rs2);
+                        gen_op_load_fpr_DT0(DFPREG(rd));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
                         flush_T2(dc);
                         gen_fcond[0][cond]();
                         gen_op_fmovd_cc();
-                        gen_op_store_DT0_fpr(rd);
+                        gen_op_store_DT0_fpr(DFPREG(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);
@@ -1702,15 +1880,26 @@ static void disas_sparc_insn(DisasContext * dc)
                         break;
                     case 0x042: /* V9 fmovdcc %fcc1 */
                         cond = GET_FIELD_SP(insn, 14, 17);
-                        gen_op_load_fpr_DT0(rd);
-                        gen_op_load_fpr_DT1(rs2);
+                        gen_op_load_fpr_DT0(DFPREG(rd));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
                         flush_T2(dc);
                         gen_fcond[1][cond]();
                         gen_op_fmovd_cc();
-                        gen_op_store_DT0_fpr(rd);
+                        gen_op_store_DT0_fpr(DFPREG(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);
@@ -1722,15 +1911,26 @@ static void disas_sparc_insn(DisasContext * dc)
                         break;
                     case 0x082: /* V9 fmovdcc %fcc2 */
                         cond = GET_FIELD_SP(insn, 14, 17);
-                        gen_op_load_fpr_DT0(rd);
-                        gen_op_load_fpr_DT1(rs2);
+                        gen_op_load_fpr_DT0(DFPREG(rd));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
                         flush_T2(dc);
                         gen_fcond[2][cond]();
                         gen_op_fmovd_cc();
-                        gen_op_store_DT0_fpr(rd);
+                        gen_op_store_DT0_fpr(DFPREG(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);
@@ -1742,15 +1942,26 @@ static void disas_sparc_insn(DisasContext * dc)
                         break;
                     case 0x0c2: /* V9 fmovdcc %fcc3 */
                         cond = GET_FIELD_SP(insn, 14, 17);
-                        gen_op_load_fpr_DT0(rd);
-                        gen_op_load_fpr_DT1(rs2);
+                        gen_op_load_fpr_DT0(DFPREG(rd));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
                         flush_T2(dc);
                         gen_fcond[3][cond]();
                         gen_op_fmovd_cc();
-                        gen_op_store_DT0_fpr(rd);
+                        gen_op_store_DT0_fpr(DFPREG(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);
@@ -1762,15 +1973,26 @@ static void disas_sparc_insn(DisasContext * dc)
                         break;
                     case 0x102: /* V9 fmovdcc %icc */
                         cond = GET_FIELD_SP(insn, 14, 17);
-                        gen_op_load_fpr_DT0(rd);
-                        gen_op_load_fpr_DT1(rs2);
+                        gen_op_load_fpr_DT0(DFPREG(rd));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
                         flush_T2(dc);
                         gen_cond[0][cond]();
                         gen_op_fmovd_cc();
-                        gen_op_store_DT0_fpr(rd);
+                        gen_op_store_DT0_fpr(DFPREG(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);
@@ -1782,17 +2004,28 @@ static void disas_sparc_insn(DisasContext * dc)
                         break;
                     case 0x182: /* V9 fmovdcc %xcc */
                         cond = GET_FIELD_SP(insn, 14, 17);
-                        gen_op_load_fpr_DT0(rd);
-                        gen_op_load_fpr_DT1(rs2);
+                        gen_op_load_fpr_DT0(DFPREG(rd));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
                         flush_T2(dc);
                         gen_cond[1][cond]();
                         gen_op_fmovd_cc();
-                        gen_op_store_DT0_fpr(rd);
+                        gen_op_store_DT0_fpr(DFPREG(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
@@ -1801,7 +2034,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
@@ -1810,8 +2043,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);
@@ -1830,8 +2074,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;
                 }
@@ -2411,94 +2666,94 @@ static void disas_sparc_insn(DisasContext * dc)
                     // XXX
                     goto illegal_insn;
                 case 0x020: /* VIS I fcmple16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fcmple16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x022: /* VIS I fcmpne16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fcmpne16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x024: /* VIS I fcmple32 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fcmple32();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x026: /* VIS I fcmpne32 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fcmpne32();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x028: /* VIS I fcmpgt16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fcmpgt16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x02a: /* VIS I fcmpeq16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fcmpeq16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x02c: /* VIS I fcmpgt32 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fcmpgt32();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x02e: /* VIS I fcmpeq32 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fcmpeq32();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x031: /* VIS I fmul8x16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fmul8x16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x033: /* VIS I fmul8x16au */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fmul8x16au();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x035: /* VIS I fmul8x16al */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fmul8x16al();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x036: /* VIS I fmul8sux16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fmul8sux16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x037: /* VIS I fmul8ulx16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fmul8ulx16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x038: /* VIS I fmuld8sux16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fmuld8sux16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x039: /* VIS I fmuld8ulx16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fmuld8ulx16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x03a: /* VIS I fpack32 */
                 case 0x03b: /* VIS I fpack16 */
@@ -2507,31 +2762,31 @@ static void disas_sparc_insn(DisasContext * dc)
                     // XXX
                     goto illegal_insn;
                 case 0x048: /* VIS I faligndata */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_faligndata();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x04b: /* VIS I fpmerge */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fpmerge();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x04c: /* VIS II bshuffle */
                     // XXX
                     goto illegal_insn;
                 case 0x04d: /* VIS I fexpand */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fexpand();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x050: /* VIS I fpadd16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fpadd16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x051: /* VIS I fpadd16s */
                     gen_op_load_fpr_FT0(rs1);
@@ -2540,10 +2795,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x052: /* VIS I fpadd32 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fpadd32();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x053: /* VIS I fpadd32s */
                     gen_op_load_fpr_FT0(rs1);
@@ -2552,10 +2807,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x054: /* VIS I fpsub16 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fpsub16();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x055: /* VIS I fpsub16s */
                     gen_op_load_fpr_FT0(rs1);
@@ -2564,10 +2819,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x056: /* VIS I fpsub32 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fpadd32();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x057: /* VIS I fpsub32s */
                     gen_op_load_fpr_FT0(rs1);
@@ -2577,17 +2832,17 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x060: /* VIS I fzero */
                     gen_op_movl_DT0_0();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x061: /* VIS I fzeros */
                     gen_op_movl_FT0_0();
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x062: /* VIS I fnor */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fnor();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x063: /* VIS I fnors */
                     gen_op_load_fpr_FT0(rs1);
@@ -2596,10 +2851,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x064: /* VIS I fandnot2 */
-                    gen_op_load_fpr_DT1(rs1);
-                    gen_op_load_fpr_DT0(rs2);
+                    gen_op_load_fpr_DT1(DFPREG(rs1));
+                    gen_op_load_fpr_DT0(DFPREG(rs2));
                     gen_op_fandnot();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x065: /* VIS I fandnot2s */
                     gen_op_load_fpr_FT1(rs1);
@@ -2608,9 +2863,9 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x066: /* VIS I fnot2 */
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fnot();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x067: /* VIS I fnot2s */
                     gen_op_load_fpr_FT1(rs2);
@@ -2618,10 +2873,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x068: /* VIS I fandnot1 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fandnot();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x069: /* VIS I fandnot1s */
                     gen_op_load_fpr_FT0(rs1);
@@ -2630,9 +2885,9 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x06a: /* VIS I fnot1 */
-                    gen_op_load_fpr_DT1(rs1);
+                    gen_op_load_fpr_DT1(DFPREG(rs1));
                     gen_op_fnot();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x06b: /* VIS I fnot1s */
                     gen_op_load_fpr_FT1(rs1);
@@ -2640,10 +2895,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x06c: /* VIS I fxor */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fxor();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x06d: /* VIS I fxors */
                     gen_op_load_fpr_FT0(rs1);
@@ -2652,10 +2907,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x06e: /* VIS I fnand */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fnand();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x06f: /* VIS I fnands */
                     gen_op_load_fpr_FT0(rs1);
@@ -2664,10 +2919,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x070: /* VIS I fand */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fand();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x071: /* VIS I fands */
                     gen_op_load_fpr_FT0(rs1);
@@ -2676,10 +2931,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x072: /* VIS I fxnor */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fxnor();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x073: /* VIS I fxnors */
                     gen_op_load_fpr_FT0(rs1);
@@ -2688,18 +2943,18 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x074: /* VIS I fsrc1 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x075: /* VIS I fsrc1s */
                     gen_op_load_fpr_FT0(rs1);
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x076: /* VIS I fornot2 */
-                    gen_op_load_fpr_DT1(rs1);
-                    gen_op_load_fpr_DT0(rs2);
+                    gen_op_load_fpr_DT1(DFPREG(rs1));
+                    gen_op_load_fpr_DT0(DFPREG(rs2));
                     gen_op_fornot();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x077: /* VIS I fornot2s */
                     gen_op_load_fpr_FT1(rs1);
@@ -2708,18 +2963,18 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x078: /* VIS I fsrc2 */
-                    gen_op_load_fpr_DT0(rs2);
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_load_fpr_DT0(DFPREG(rs2));
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x079: /* VIS I fsrc2s */
                     gen_op_load_fpr_FT0(rs2);
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x07a: /* VIS I fornot1 */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_fornot();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x07b: /* VIS I fornot1s */
                     gen_op_load_fpr_FT0(rs1);
@@ -2728,10 +2983,10 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_store_FT0_fpr(rd);
                     break;
                 case 0x07c: /* VIS I for */
-                    gen_op_load_fpr_DT0(rs1);
-                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_load_fpr_DT0(DFPREG(rs1));
+                    gen_op_load_fpr_DT1(DFPREG(rs2));
                     gen_op_for();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x07d: /* VIS I fors */
                     gen_op_load_fpr_FT0(rs1);
@@ -2741,7 +2996,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x07e: /* VIS I fone */
                     gen_op_movl_DT0_1();
-                    gen_op_store_DT0_fpr(rd);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
                     break;
                 case 0x07f: /* VIS I fones */
                     gen_op_movl_FT0_1();
@@ -3082,17 +3337,23 @@ static void disas_sparc_insn(DisasContext * dc)
                     goto skip_move;
                 case 0x30: /* V9 ldfa */
                     gen_op_check_align_T0_3();
-                    gen_ldf_asi(insn, 4);
+                    gen_ldf_asi(insn, 4, rd);
                     goto skip_move;
                 case 0x33: /* V9 lddfa */
                     gen_op_check_align_T0_3();
-                    gen_ldf_asi(insn, 8);
+                    gen_ldf_asi(insn, 8, DFPREG(rd));
                     goto skip_move;
                 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, QFPREG(rd));
+                    goto skip_move;
+#else
                     goto nfpu_insn;
 #endif
+#endif
                 default:
                     goto illegal_insn;
                 }
@@ -3115,7 +3376,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);
@@ -3221,14 +3489,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));
@@ -3243,12 +3526,21 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x34: /* V9 stfa */
                     gen_op_check_align_T0_3();
                     gen_op_load_fpr_FT0(rd);
-                    gen_stf_asi(insn, 4);
+                    gen_stf_asi(insn, 4, rd);
+                    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, QFPREG(rd));
                     break;
+#else
+                    goto nfpu_insn;
+#endif
                 case 0x37: /* V9 stdfa */
                     gen_op_check_align_T0_3();
                     gen_op_load_fpr_DT0(DFPREG(rd));
-                    gen_stf_asi(insn, 8);
+                    gen_stf_asi(insn, 8, DFPREG(rd));
                     break;
                 case 0x3c: /* V9 casa */
                     gen_op_check_align_T0_3();
@@ -3264,8 +3556,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 */
@@ -3307,19 +3597,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);
@@ -3489,28 +3779,155 @@ void cpu_reset(CPUSPARCState *env)
 #endif
 }
 
-CPUSPARCState *cpu_sparc_init(void)
+CPUSPARCState *cpu_sparc_init(const char *cpu_model)
 {
     CPUSPARCState *env;
+    const sparc_def_t *def;
+
+    def = cpu_sparc_find_by_name(cpu_model);
+    if (!def)
+        return NULL;
 
     env = qemu_mallocz(sizeof(CPUSPARCState));
     if (!env)
         return NULL;
     cpu_exec_init(env);
-    return (env);
+    env->cpu_model_str = cpu_model;
+    env->version = def->iu_version;
+    env->fsr = def->fpu_version;
+#if !defined(TARGET_SPARC64)
+    env->mmu_bm = def->mmu_bm;
+    env->mmuregs[0] |= def->mmu_version;
+    cpu_sparc_set_id(env, 0);
+#endif
+    cpu_reset(env);
+    
+    return env;
+}
+
+void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
+{
+#if !defined(TARGET_SPARC64)
+    env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
+#endif
 }
 
 static const sparc_def_t sparc_defs[] = {
 #ifdef TARGET_SPARC64
     {
+        .name = "Fujitsu Sparc64",
+        .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "Fujitsu Sparc64 III",
+        .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "Fujitsu Sparc64 IV",
+        .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "Fujitsu Sparc64 V",
+        .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "TI UltraSparc I",
+        .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
         .name = "TI UltraSparc II",
-        .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0 << 24)
+        .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "TI UltraSparc IIi",
+        .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "TI UltraSparc IIe",
+        .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "Sun UltraSparc III",
+        .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "Sun UltraSparc III Cu",
+        .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "Sun UltraSparc IIIi",
+        .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "Sun UltraSparc IV",
+        .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "Sun UltraSparc IV+",
+        .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "Sun UltraSparc IIIi+",
+        .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+    {
+        .name = "NEC UltraSparc I",
+        .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)
                        | (MAXTL << 8) | (NWINDOWS - 1)),
         .fpu_version = 0x00000000,
         .mmu_version = 0,
     },
 #else
     {
+        .name = "Fujitsu MB86900",
+        .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
+        .mmu_bm = 0x00004000,
+    },
+    {
         .name = "Fujitsu MB86904",
         .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
@@ -3525,6 +3942,34 @@ static const sparc_def_t sparc_defs[] = {
         .mmu_bm = 0x00004000,
     },
     {
+        .name = "LSI L64811",
+        .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
+        .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "Cypress CY7C601",
+        .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "Cypress CY7C611",
+        .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "TI SuperSparc II",
+        .iu_version = 0x40000000,
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x04000000,
+        .mmu_bm = 0x00002000,
+    },
+    {
         .name = "TI MicroSparc I",
         .iu_version = 0x41000000,
         .fpu_version = 4 << 17,
@@ -3532,38 +3977,95 @@ static const sparc_def_t sparc_defs[] = {
         .mmu_bm = 0x00004000,
     },
     {
-        .name = "TI SuperSparc II",
-        .iu_version = 0x40000000,
+        .name = "TI MicroSparc II",
+        .iu_version = 0x42000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x02000000,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "TI MicroSparc IIep",
+        .iu_version = 0x42000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x04000000,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "TI SuperSparc 51",
+        .iu_version = 0x43000000,
         .fpu_version = 0 << 17,
         .mmu_version = 0x04000000,
         .mmu_bm = 0x00002000,
     },
     {
-        .name = "Ross RT620",
+        .name = "TI SuperSparc 61",
+        .iu_version = 0x44000000,
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x04000000,
+        .mmu_bm = 0x00002000,
+    },
+    {
+        .name = "Ross RT625",
         .iu_version = 0x1e000000,
         .fpu_version = 1 << 17,
-        .mmu_version = 0x17000000,
+        .mmu_version = 0x1e000000,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "Ross RT620",
+        .iu_version = 0x1f000000,
+        .fpu_version = 1 << 17,
+        .mmu_version = 0x1f000000,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "BIT B5010",
+        .iu_version = 0x20000000,
+        .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
+        .mmu_version = 0x20000000,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "Matsushita MN10501",
+        .iu_version = 0x50000000,
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x50000000,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "Weitek W8601",
+        .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
+        .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
+        .mmu_version = 0x10 << 24,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "LEON2",
+        .iu_version = 0xf2000000,
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0xf2000000,
+        .mmu_bm = 0x00004000,
+    },
+    {
+        .name = "LEON3",
+        .iu_version = 0xf3000000,
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0xf3000000,
         .mmu_bm = 0x00004000,
     },
 #endif
 };
 
-int sparc_find_by_name(const unsigned char *name, const sparc_def_t **def)
+static const sparc_def_t *cpu_sparc_find_by_name(const unsigned char *name)
 {
-    int ret;
     unsigned int i;
 
-    ret = -1;
-    *def = NULL;
     for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) {
         if (strcasecmp(name, sparc_defs[i].name) == 0) {
-            *def = &sparc_defs[i];
-            ret = 0;
-            break;
+            return &sparc_defs[i];
         }
     }
-
-    return ret;
+    return NULL;
 }
 
 void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
@@ -3579,19 +4081,6 @@ void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
     }
 }
 
-int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def, unsigned int cpu)
-{
-    env->version = def->iu_version;
-    env->fsr = def->fpu_version;
-#if !defined(TARGET_SPARC64)
-    env->mmu_bm = def->mmu_bm;
-    env->mmuregs[0] |= def->mmu_version;
-    env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
-#endif
-    cpu_reset(env);
-    return 0;
-}
-
 #define GET_FLAG(a,b) ((env->psr & a)?b:'-')
 
 void cpu_dump_state(CPUState *env, FILE *f,