halt state support for ppc
[qemu] / target-ppc / translate.c
index 70f8863..3bc6aa3 100644 (file)
 //#define DO_SINGLE_STEP
 //#define PPC_DEBUG_DISAS
 
+#ifdef USE_DIRECT_JUMP
+#define TBPARAM(x)
+#else
+#define TBPARAM(x) (long)(x)
+#endif
+
 enum {
 #define DEF(s, n, copy_size) INDEX_op_ ## s,
 #include "opc.h"
@@ -171,17 +177,16 @@ RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
 #define RET_PRIVREG(ctx)                                                      \
 RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
 
-#define RET_MTMSR(ctx)                                                        \
-RET_EXCP((ctx), EXCP_MTMSR, 0)
-
+/* Stop translation */
 static inline void RET_STOP (DisasContext *ctx)
 {
-    RET_EXCP(ctx, EXCP_MTMSR, 0);
+    gen_op_update_nip((ctx)->nip);
+    ctx->exception = EXCP_MTMSR;
 }
 
+/* No need to update nip here, as execution flow will change */
 static inline void RET_CHG_FLOW (DisasContext *ctx)
 {
-    gen_op_raise_exception_err(EXCP_MTMSR, 0);
     ctx->exception = EXCP_MTMSR;
 }
 
@@ -1721,6 +1726,27 @@ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
 
 /***                                Branch                                 ***/
 
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+    tb = ctx->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+        if (n == 0)
+            gen_op_goto_tb0(TBPARAM(tb));
+        else
+            gen_op_goto_tb1(TBPARAM(tb));
+        gen_op_set_T1(dest);
+        gen_op_b_T1();
+        gen_op_set_T0((long)tb + n);
+        gen_op_exit_tb();
+    } else {
+        gen_op_set_T1(dest);
+        gen_op_b_T1();
+        gen_op_set_T0(0);
+        gen_op_exit_tb();
+    }
+}
+
 /* b ba bl bla */
 GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
 {
@@ -1736,7 +1762,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
     if (LK(ctx->opcode)) {
         gen_op_setlr(ctx->nip);
     }
-    gen_op_b((long)ctx->tb, target);
+    gen_goto_tb(ctx, 0, target);
     ctx->exception = EXCP_BRANCH;
 }
 
@@ -1787,7 +1813,7 @@ static inline void gen_bcond(DisasContext *ctx, int type)
         case 4:                                                               
         case 6:                                                               
             if (type == BCOND_IM) {
-                gen_op_b((long)ctx->tb, target);
+                gen_goto_tb(ctx, 0, target);
             } else {
                 gen_op_b_T1();
             }
@@ -1827,7 +1853,11 @@ static inline void gen_bcond(DisasContext *ctx, int type)
         }                                                                     
     }                                                                         
     if (type == BCOND_IM) {
-        gen_op_btest((long)ctx->tb, target, ctx->nip);
+        int l1 = gen_new_label();
+        gen_op_jz_T0(l1);
+        gen_goto_tb(ctx, 0, target);
+        gen_set_label(l1);
+        gen_goto_tb(ctx, 1, ctx->nip);
     } else {
         gen_op_btest_T1(ctx->nip);
     }
@@ -2020,11 +2050,19 @@ static inline void gen_op_mfspr (DisasContext *ctx)
             gen_op_store_T0_gpr(rD(ctx->opcode));
         } else {
             /* Privilege exception */
+            if (loglevel) {
+                fprintf(logfile, "Trying to read priviledged spr %d %03x\n",
+                        sprn, sprn);
+            }
             printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
         RET_PRIVREG(ctx);
         }
     } else {
         /* Not defined */
+        if (loglevel) {
+            fprintf(logfile, "Trying to read invalid spr %d %03x\n",
+                    sprn, sprn);
+        }
         printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
         RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
     }
@@ -2059,10 +2097,11 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
         RET_PRIVREG(ctx);
         return;
     }
+    gen_op_update_nip((ctx)->nip);
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_store_msr();
     /* Must stop the translation as machine state (may have) changed */
-    RET_MTMSR(ctx);
+    RET_CHG_FLOW(ctx);
 #endif
 }
 
@@ -2084,11 +2123,19 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
             (*write_cb)(ctx, sprn);
         } else {
             /* Privilege exception */
+            if (loglevel) {
+                fprintf(logfile, "Trying to write priviledged spr %d %03x\n",
+                        sprn, sprn);
+            }
             printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
         RET_PRIVREG(ctx);
     }
     } else {
         /* Not defined */
+        if (loglevel) {
+            fprintf(logfile, "Trying to write invalid spr %d %03x\n",
+                    sprn, sprn);
+        }
         printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
         RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
     }
@@ -2247,6 +2294,7 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_store_sr(SR(ctx->opcode));
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2263,6 +2311,7 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_load_gpr_T1(rB(ctx->opcode));
     gen_op_store_srin();
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2281,7 +2330,7 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
         return;
     }
     gen_op_tlbia();
-    RET_MTMSR(ctx);
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2297,7 +2346,7 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
     }
     gen_op_load_gpr_T0(rB(ctx->opcode));
     gen_op_tlbie();
-    RET_MTMSR(ctx);
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2314,7 +2363,7 @@ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
     /* This has no effect: it should ensure that all previous
      * tlbie have completed
      */
-    RET_MTMSR(ctx);
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2459,6 +2508,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     gen_opc_ptr = gen_opc_buf;
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
     gen_opparam_ptr = gen_opparam_buf;
+    nb_gen_labels = 0;
     ctx.nip = pc_start;
     ctx.tb = tb;
     ctx.exception = EXCP_NONE;
@@ -2575,7 +2625,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
 #endif
     }
     if (ctx.exception == EXCP_NONE) {
-        gen_op_b((unsigned long)ctx.tb, ctx.nip);
+        gen_goto_tb(&ctx, 0, ctx.nip);
     } else if (ctx.exception != EXCP_BRANCH) {
         gen_op_set_T0(0);
     }
@@ -2609,7 +2659,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     }
     if (loglevel & CPU_LOG_TB_IN_ASM) {
         fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
-       target_disas(logfile, pc_start, ctx.nip - pc_start, 0);
+       target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le);
         fprintf(logfile, "\n");
     }
     if (loglevel & CPU_LOG_TB_OP) {