]> Git Repo - qemu.git/blobdiff - target-sparc/translate.c
Support for executing 32 bit SPARC32PLUS files for Sparc64 user emulator
[qemu.git] / target-sparc / translate.c
index a52d6717a37e20a442d6ee3184988a1d8ef2f29f..1a6d56ac40ba62b68423da5aa15710100b54a413 100644 (file)
@@ -87,7 +87,7 @@ enum {
 #define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), ((b) - (a) + 1))
 
 #ifdef TARGET_SPARC64
-#define DFPREG(r) (((r & 1) << 6) | (r & 0x1e))
+#define DFPREG(r) (((r & 1) << 5) | (r & 0x1e))
 #else
 #define DFPREG(r) (r & 0x1e)
 #endif
@@ -353,112 +353,27 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf);
 #endif
 #endif
 
-#ifdef TARGET_SPARC64
-// 'a' versions allowed to user depending on asi
-#if defined(CONFIG_USER_ONLY)
+/* moves */
+#ifdef CONFIG_USER_ONLY
 #define supervisor(dc) 0
+#ifdef TARGET_SPARC64
 #define hypervisor(dc) 0
+#endif
 #define gen_op_ldst(name)        gen_op_##name##_raw()
-#define OP_LD_TABLE(width)                                              \
-    static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \
-    {                                                                   \
-        int asi, offset;                                                \
-                                                                        \
-        if (IS_IMM) {                                                   \
-            offset = GET_FIELD(insn, 25, 31);                           \
-            if (is_ld)                                                  \
-                gen_op_ld_asi_reg(offset, size, sign);                  \
-            else                                                        \
-                gen_op_st_asi_reg(offset, size, sign);                  \
-            return;                                                     \
-        }                                                               \
-        asi = GET_FIELD(insn, 19, 26);                                  \
-        switch (asi) {                                                  \
-        case 0x80: /* Primary address space */                          \
-            gen_op_##width##_raw();                                     \
-            break;                                                      \
-        case 0x82: /* Primary address space, non-faulting load */       \
-            gen_op_##width##_raw();                                     \
-            break;                                                      \
-        default:                                                        \
-            break;                                                      \
-        }                                                               \
-    }
-
 #else
+#define supervisor(dc) (dc->mem_idx == 1)
+#ifdef TARGET_SPARC64
+#define hypervisor(dc) (dc->mem_idx == 2)
+#endif
 #define gen_op_ldst(name)        (*gen_op_##name[dc->mem_idx])()
 #define OP_LD_TABLE(width)                                              \
     static GenOpFunc * const gen_op_##width[] = {                       \
         &gen_op_##width##_user,                                         \
         &gen_op_##width##_kernel,                                       \
-    };                                                                  \
-                                                                        \
-    static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \
-    {                                                                   \
-        int asi, offset;                                                \
-                                                                        \
-        if (IS_IMM) {                                                   \
-            offset = GET_FIELD(insn, 25, 31);                           \
-            if (is_ld)                                                  \
-                gen_op_ld_asi_reg(offset, size, sign);                  \
-            else                                                        \
-                gen_op_st_asi_reg(offset, size, sign);                  \
-            return;                                                     \
-        }                                                               \
-        asi = GET_FIELD(insn, 19, 26);                                  \
-        if (is_ld)                                                      \
-            gen_op_ld_asi(asi, size, sign);                             \
-        else                                                            \
-            gen_op_st_asi(asi, size, sign);                             \
-    }
-
-#define supervisor(dc) (dc->mem_idx == 1)
-#define hypervisor(dc) (dc->mem_idx == 2)
-#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-#define gen_op_ldst(name)        gen_op_##name##_raw()
-#define OP_LD_TABLE(width)
-#define supervisor(dc) 0
-#else
-#define gen_op_ldst(name)        (*gen_op_##name[dc->mem_idx])()
-#define OP_LD_TABLE(width)                                                    \
-static GenOpFunc * const gen_op_##width[] = {                                 \
-    &gen_op_##width##_user,                                                   \
-    &gen_op_##width##_kernel,                                                 \
-};                                                                            \
-                                                                              \
-static void gen_op_##width##a(int insn, int is_ld, int size, int sign)        \
-{                                                                             \
-    int asi;                                                                  \
-                                                                              \
-    asi = GET_FIELD(insn, 19, 26);                                            \
-    switch (asi) {                                                            \
-        case 10: /* User data access */                                       \
-            gen_op_##width##_user();                                          \
-            break;                                                            \
-        case 11: /* Supervisor data access */                                 \
-            gen_op_##width##_kernel();                                        \
-            break;                                                            \
-        case 0x20 ... 0x2f: /* MMU passthrough */                             \
-            if (is_ld)                                                        \
-                gen_op_ld_asi(asi, size, sign);                               \
-            else                                                              \
-                gen_op_st_asi(asi, size, sign);                               \
-            break;                                                            \
-        default:                                                              \
-            if (is_ld)                                                        \
-                gen_op_ld_asi(asi, size, sign);                               \
-            else                                                              \
-                gen_op_st_asi(asi, size, sign);                               \
-            break;                                                            \
-    }                                                                         \
-}
-
-#define supervisor(dc) (dc->mem_idx == 1)
-#endif
+    };
 #endif
 
+#ifndef CONFIG_USER_ONLY
 OP_LD_TABLE(ld);
 OP_LD_TABLE(st);
 OP_LD_TABLE(ldub);
@@ -481,8 +396,192 @@ OP_LD_TABLE(lduw);
 OP_LD_TABLE(ldsw);
 OP_LD_TABLE(ldx);
 OP_LD_TABLE(stx);
-OP_LD_TABLE(cas);
-OP_LD_TABLE(casx);
+#endif
+#endif
+
+/* asi moves */
+#ifdef TARGET_SPARC64
+static inline void gen_ld_asi(int insn, int size, int sign)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ld_asi_reg(offset, size, sign);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ld_asi(asi, size, sign);
+    }
+}
+
+static inline void gen_st_asi(int insn, int size)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_st_asi_reg(offset, size);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_st_asi(asi, size);
+    }
+}
+
+static inline void gen_ldf_asi(int insn, int size)
+{
+    int asi, offset, rd;
+
+    rd = DFPREG(GET_FIELD(insn, 2, 6));
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ldf_asi_reg(offset, size, rd);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ldf_asi(asi, size, rd);
+    }
+}
+
+static inline void gen_stf_asi(int insn, int size)
+{
+    int asi, offset, rd;
+
+    rd = DFPREG(GET_FIELD(insn, 2, 6));
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_stf_asi_reg(offset, size, rd);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_stf_asi(asi, size, rd);
+    }
+}
+
+static inline void gen_swap_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_swap_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_swap_asi(asi);
+    }
+}
+
+static inline void gen_ldstub_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ldstub_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ldstub_asi(asi);
+    }
+}
+
+static inline void gen_ldda_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ldda_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ldda_asi(asi);
+    }
+}
+
+static inline void gen_stda_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_stda_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_stda_asi(asi);
+    }
+}
+
+static inline void gen_cas_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_cas_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_cas_asi(asi);
+    }
+}
+
+static inline void gen_casx_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_casx_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_casx_asi(asi);
+    }
+}
+
+#elif !defined(CONFIG_USER_ONLY)
+
+static inline void gen_ld_asi(int insn, int size, int sign)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_ld_asi(asi, size, sign);
+}
+
+static inline void gen_st_asi(int insn, int size)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_st_asi(asi, size);
+}
+
+static inline void gen_ldstub_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_ldstub_asi(asi);
+}
+
+static inline void gen_swap_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_swap_asi(asi);
+}
+
+static inline void gen_ldda_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_ld_asi(asi, 8, 0);
+}
+
+static inline void gen_stda_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_st_asi(asi, 8);
+}
 #endif
 
 static inline void gen_movl_imm_TN(int reg, uint32_t imm)
@@ -1972,9 +2071,11 @@ static void disas_sparc_insn(DisasContext * dc)
                                 break;
 #else
                             case 0x2: /* V9 wrccr */
+                                gen_op_xor_T1_T0();
                                 gen_op_wrccr();
                                 break;
                             case 0x3: /* V9 wrasi */
+                                gen_op_xor_T1_T0();
                                 gen_op_movl_env_T0(offsetof(CPUSPARCState, asi));
                                 break;
                             case 0x6: /* V9 wrfprs */
@@ -1995,6 +2096,7 @@ static void disas_sparc_insn(DisasContext * dc)
                             case 0x13: /* Graphics Status */
                                 if (gen_trap_ifnofpu(dc))
                                     goto jmp_insn;
+                                gen_op_xor_T1_T0();
                                 gen_op_movtl_env_T0(offsetof(CPUSPARCState, gsr));
                                 break;
                             case 0x17: /* Tick compare */
@@ -2002,6 +2104,7 @@ static void disas_sparc_insn(DisasContext * dc)
                                 if (!supervisor(dc))
                                     goto illegal_insn;
 #endif
+                                gen_op_xor_T1_T0();
                                 gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr));
                                 gen_op_wrtick_cmpr();
                                 break;
@@ -2010,6 +2113,7 @@ static void disas_sparc_insn(DisasContext * dc)
                                 if (!supervisor(dc))
                                     goto illegal_insn;
 #endif
+                                gen_op_xor_T1_T0();
                                 gen_op_wrstick();
                                 break;
                             case 0x19: /* System tick compare */
@@ -2017,6 +2121,7 @@ static void disas_sparc_insn(DisasContext * dc)
                                 if (!supervisor(dc))
                                     goto illegal_insn;
 #endif
+                                gen_op_xor_T1_T0();
                                 gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr));
                                 gen_op_wrstick_cmpr();
                                 break;
@@ -2796,7 +2901,12 @@ static void disas_sparc_insn(DisasContext * dc)
             rs1 = GET_FIELD(insn, 13, 17);
             save_state(dc);
             gen_movl_reg_T0(rs1);
-            if (IS_IMM) {       /* immediate */
+            if (xop == 0x3c || xop == 0x3e)
+            {
+                rs2 = GET_FIELD(insn, 27, 31);
+                gen_movl_reg_T1(rs2);
+            }
+            else if (IS_IMM) {       /* immediate */
                 rs2 = GET_FIELDs(insn, 19, 31);
 #if defined(OPTIM)
                 if (rs2 != 0) {
@@ -2873,16 +2983,10 @@ static void disas_sparc_insn(DisasContext * dc)
                         goto illegal_insn;
                     if (!supervisor(dc))
                         goto priv_insn;
-#ifdef CONFIG_USER_ONLY
-                    gen_op_check_align_T0_3();
-#endif
-                    gen_op_lda(insn, 1, 4, 0);
-#else
-#ifdef CONFIG_USER_ONLY
+#elif CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_lduwa(insn, 1, 4, 0);
-#endif
+                    gen_ld_asi(insn, 4, 0);
                     break;
                 case 0x11:      /* load unsigned byte alternate */
 #ifndef TARGET_SPARC64
@@ -2891,7 +2995,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     if (!supervisor(dc))
                         goto priv_insn;
 #endif
-                    gen_op_lduba(insn, 1, 1, 0);
+                    gen_ld_asi(insn, 1, 0);
                     break;
                 case 0x12:      /* load unsigned halfword alternate */
 #ifndef TARGET_SPARC64
@@ -2899,11 +3003,10 @@ static void disas_sparc_insn(DisasContext * dc)
                         goto illegal_insn;
                     if (!supervisor(dc))
                         goto priv_insn;
-#endif
-#ifdef CONFIG_USER_ONLY
+#elif CONFIG_USER_ONLY
                     gen_op_check_align_T0_1();
 #endif
-                    gen_op_lduha(insn, 1, 2, 0);
+                    gen_ld_asi(insn, 2, 0);
                     break;
                 case 0x13:      /* load double word alternate */
 #ifndef TARGET_SPARC64
@@ -2915,7 +3018,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     if (rd & 1)
                         goto illegal_insn;
                     gen_op_check_align_T0_7();
-                    gen_op_ldda(insn, 1, 8, 0);
+                    gen_ldda_asi(insn);
                     gen_movl_T0_reg(rd + 1);
                     break;
                 case 0x19:      /* load signed byte alternate */
@@ -2925,7 +3028,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     if (!supervisor(dc))
                         goto priv_insn;
 #endif
-                    gen_op_ldsba(insn, 1, 1, 1);
+                    gen_ld_asi(insn, 1, 1);
                     break;
                 case 0x1a:      /* load signed halfword alternate */
 #ifndef TARGET_SPARC64
@@ -2933,11 +3036,10 @@ static void disas_sparc_insn(DisasContext * dc)
                         goto illegal_insn;
                     if (!supervisor(dc))
                         goto priv_insn;
-#endif
-#ifdef CONFIG_USER_ONLY
+#elif CONFIG_USER_ONLY
                     gen_op_check_align_T0_1();
 #endif
-                    gen_op_ldsha(insn, 1, 2 ,1);
+                    gen_ld_asi(insn, 2, 1);
                     break;
                 case 0x1d:      /* ldstuba -- XXX: should be atomically */
 #ifndef TARGET_SPARC64
@@ -2946,7 +3048,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     if (!supervisor(dc))
                         goto priv_insn;
 #endif
-                    gen_op_ldstuba(insn, 1, 1, 0);
+                    gen_ldstub_asi(insn);
                     break;
                 case 0x1f:      /* swap reg with alt. memory. Also atomically */
 #ifndef TARGET_SPARC64
@@ -2954,12 +3056,11 @@ static void disas_sparc_insn(DisasContext * dc)
                         goto illegal_insn;
                     if (!supervisor(dc))
                         goto priv_insn;
-#endif
-                    gen_movl_reg_T1(rd);
-#ifdef CONFIG_USER_ONLY
+#elif CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_swapa(insn, 1, 4, 0);
+                    gen_movl_reg_T1(rd);
+                    gen_swap_asi(insn);
                     break;
 
 #ifndef TARGET_SPARC64
@@ -2967,17 +3068,6 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x31: /* ldcsr */
                 case 0x33: /* lddc */
                     goto ncp_insn;
-                    /* avoid warnings */
-                    (void) &gen_op_stfa;
-                    (void) &gen_op_stdfa;
-                    (void) &gen_op_ldfa;
-                    (void) &gen_op_lddfa;
-#else
-                    (void) &gen_op_lda;
-#if !defined(CONFIG_USER_ONLY)
-                    (void) &gen_op_cas;
-                    (void) &gen_op_casx;
-#endif
 #endif
 #endif
 #ifdef TARGET_SPARC64
@@ -2995,11 +3085,11 @@ static void disas_sparc_insn(DisasContext * dc)
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_ldswa(insn, 1, 4, 1);
+                    gen_ld_asi(insn, 4, 1);
                     break;
                 case 0x1b: /* V9 ldxa */
                     gen_op_check_align_T0_7();
-                    gen_op_ldxa(insn, 1, 8, 0);
+                    gen_ld_asi(insn, 8, 0);
                     break;
                 case 0x2d: /* V9 prefetch, no effect */
                     goto skip_move;
@@ -3007,13 +3097,12 @@ static void disas_sparc_insn(DisasContext * dc)
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_ldfa(insn, 1, 8, 0); // XXX
-                    break;
+                    gen_ldf_asi(insn, 4);
+                    goto skip_move;
                 case 0x33: /* V9 lddfa */
-                    gen_op_check_align_T0_7();
-                    gen_op_lddfa(insn, 1, 8, 0); // XXX
-
-                    break;
+                    gen_op_check_align_T0_3();
+                    gen_ldf_asi(insn, 8);
+                    goto skip_move;
                 case 0x3d: /* V9 prefetcha, no effect */
                     goto skip_move;
                 case 0x32: /* V9 ldqfa */
@@ -3092,7 +3181,7 @@ static void disas_sparc_insn(DisasContext * dc)
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_sta(insn, 0, 4, 0);
+                    gen_st_asi(insn, 4);
                     break;
                 case 0x15:
 #ifndef TARGET_SPARC64
@@ -3101,7 +3190,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     if (!supervisor(dc))
                         goto priv_insn;
 #endif
-                    gen_op_stba(insn, 0, 1, 0);
+                    gen_st_asi(insn, 1);
                     break;
                 case 0x16:
 #ifndef TARGET_SPARC64
@@ -3113,7 +3202,7 @@ static void disas_sparc_insn(DisasContext * dc)
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_1();
 #endif
-                    gen_op_stha(insn, 0, 2, 0);
+                    gen_st_asi(insn, 2);
                     break;
                 case 0x17:
 #ifndef TARGET_SPARC64
@@ -3127,7 +3216,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     gen_op_check_align_T0_7();
                     flush_T2(dc);
                     gen_movl_reg_T2(rd + 1);
-                    gen_op_stda(insn, 0, 8, 0);
+                    gen_stda_asi(insn);
                     break;
 #endif
 #ifdef TARGET_SPARC64
@@ -3137,7 +3226,7 @@ static void disas_sparc_insn(DisasContext * dc)
                     break;
                 case 0x1e: /* V9 stxa */
                     gen_op_check_align_T0_7();
-                    gen_op_stxa(insn, 0, 8, 0); // XXX
+                    gen_st_asi(insn, 8);
                     break;
 #endif
                 default:
@@ -3184,21 +3273,29 @@ static void disas_sparc_insn(DisasContext * dc)
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_stfa(insn, 0, 0, 0); // XXX
+                    gen_op_load_fpr_FT0(rd);
+                    gen_stf_asi(insn, 4);
                     break;
                 case 0x37: /* V9 stdfa */
-                    gen_op_check_align_T0_7();
-                    gen_op_stdfa(insn, 0, 0, 0); // XXX
+                    gen_op_check_align_T0_3();
+                    gen_op_load_fpr_DT0(DFPREG(rd));
+                    gen_stf_asi(insn, 8);
                     break;
                 case 0x3c: /* V9 casa */
 #ifdef CONFIG_USER_ONLY
                     gen_op_check_align_T0_3();
 #endif
-                    gen_op_casa(insn, 0, 4, 0); // XXX
+                    flush_T2(dc);
+                    gen_movl_reg_T2(rd);
+                    gen_cas_asi(insn);
+                    gen_movl_T1_reg(rd);
                     break;
                 case 0x3e: /* V9 casxa */
                     gen_op_check_align_T0_7();
-                    gen_op_casxa(insn, 0, 8, 0); // XXX
+                    flush_T2(dc);
+                    gen_movl_reg_T2(rd);
+                    gen_casx_asi(insn);
+                    gen_movl_T1_reg(rd);
                     break;
                 case 0x36: /* V9 stqfa */
                     goto nfpu_insn;
@@ -3425,8 +3522,9 @@ void cpu_reset(CPUSPARCState *env)
     env->pstate = PS_PRIV;
     env->pc = 0x1fff0000000ULL;
 #else
-    env->pc = 0xffd00000;
+    env->pc = 0;
     env->mmuregs[0] &= ~(MMU_E | MMU_NF);
+    env->mmuregs[0] |= MMU_BM;
 #endif
     env->npc = env->pc + 4;
 #endif
@@ -3523,7 +3621,7 @@ int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def)
     env->version = def->iu_version;
     env->fsr = def->fpu_version;
 #if !defined(TARGET_SPARC64)
-    env->mmuregs[0] = def->mmu_version;
+    env->mmuregs[0] |= def->mmu_version;
 #endif
     return 0;
 }
This page took 0.0435 seconds and 4 git commands to generate.