Dynamically translate MIPS mtc0 instructions.
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 6 Dec 2006 18:19:33 +0000 (18:19 +0000)
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 6 Dec 2006 18:19:33 +0000 (18:19 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2223 c046a42c-6fe2-441c-8c8c-71466251a162

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

index bc330c0295cda563ef37c6dceef2aa9069cc8592..e39f70f872fafaf599fced65fa040f5659e4d82a 100644 (file)
@@ -68,7 +68,8 @@ void do_msubu (void);
 #endif
 void do_mfc0_random(void);
 void do_mfc0_count(void);
-void do_mtc0(int reg, int sel);
+void do_mtc0_status_debug(uint32_t old, uint32_t val);
+void do_mtc0_status_irqraise_debug(void);
 void do_tlbwi (void);
 void do_tlbwr (void);
 void do_tlbp (void);
index 2597e2e3d3e784fb4b96cb409545a94f9d5fa23d..7a57728345d6bebbdf3f7a8d6f209c264b30cb42 100644 (file)
@@ -852,9 +852,185 @@ void op_mfc0_desave (void)
     RETURN();
 }
 
-void op_mtc0 (void)
+void op_mtc0_index (void)
 {
-    CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
+    env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
+    RETURN();
+}
+
+void op_mtc0_entrylo0 (void)
+{
+    env->CP0_EntryLo0 = T0 & 0x3FFFFFFF;
+    RETURN();
+}
+
+void op_mtc0_entrylo1 (void)
+{
+    env->CP0_EntryLo1 = T0 & 0x3FFFFFFF;
+    RETURN();
+}
+
+void op_mtc0_context (void)
+{
+    env->CP0_Context = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0);
+    RETURN();
+}
+
+void op_mtc0_pagemask (void)
+{
+    env->CP0_PageMask = T0 & 0x01FFE000;
+    RETURN();
+}
+
+void op_mtc0_wired (void)
+{
+    env->CP0_Wired = T0 & 0x0000000F;
+    RETURN();
+}
+
+void op_mtc0_count (void)
+{
+    CALL_FROM_TB2(cpu_mips_store_count, env, T0);
+    RETURN();
+}
+
+void op_mtc0_entryhi (void)
+{
+    uint32_t old, val;
+
+    val = T0 & 0xFFFFE0FF;
+    old = env->CP0_EntryHi;
+    env->CP0_EntryHi = val;
+    /* If the ASID changes, flush qemu's TLB.  */
+    if ((old & 0xFF) != (val & 0xFF))
+        CALL_FROM_TB2(cpu_mips_tlb_flush, env, 1);
+    RETURN();
+}
+
+void op_mtc0_compare (void)
+{
+    CALL_FROM_TB2(cpu_mips_store_compare, env, T0);
+    RETURN();
+}
+
+void op_mtc0_status (void)
+{
+    uint32_t val, old, mask;
+
+    val = T0 & 0xFA78FF01;
+    old = env->CP0_Status;
+    if (T0 & (1 << CP0St_UM))
+        env->hflags |= MIPS_HFLAG_UM;
+    else
+        env->hflags &= ~MIPS_HFLAG_UM;
+    if (T0 & (1 << CP0St_ERL))
+        env->hflags |= MIPS_HFLAG_ERL;
+    else
+        env->hflags &= ~MIPS_HFLAG_ERL;
+    if (T0 & (1 << CP0St_EXL))
+        env->hflags |= MIPS_HFLAG_EXL;
+    else
+        env->hflags &= ~MIPS_HFLAG_EXL;
+    env->CP0_Status = val;
+    /* If we unmasked an asserted IRQ, raise it */
+    mask = 0x0000FF00;
+    if (loglevel & CPU_LOG_TB_IN_ASM)
+       CALL_FROM_TB2(do_mtc0_status_debug, old, val);
+    if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
+        !(env->hflags & MIPS_HFLAG_EXL) &&
+        !(env->hflags & MIPS_HFLAG_ERL) &&
+        !(env->hflags & MIPS_HFLAG_DM) &&
+        (env->CP0_Status & env->CP0_Cause & mask)) {
+        env->interrupt_request |= CPU_INTERRUPT_HARD;
+       if (logfile)
+           CALL_FROM_TB0(do_mtc0_status_irqraise_debug);
+    } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
+        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+    }
+    RETURN();
+}
+
+void op_mtc0_cause (void)
+{
+    uint32_t val, old;
+
+    val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
+    old = env->CP0_Cause;
+    env->CP0_Cause = val;
+#if 0
+    {
+        int i, mask;
+
+       /* Check if we ever asserted a software IRQ */
+        for (i = 0; i < 2; i++) {
+            mask = 0x100 << i;
+            if ((val & mask) & !(old & mask))
+                CALL_FROM_TB1(mips_set_irq, i);
+        }
+    }
+#endif
+    RETURN();
+}
+
+void op_mtc0_epc (void)
+{
+    env->CP0_EPC = T0;
+    RETURN();
+}
+
+void op_mtc0_config0 (void)
+{
+#if defined(MIPS_USES_R4K_TLB)
+    env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
+#else
+    env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
+#endif
+    RETURN();
+}
+
+void op_mtc0_watchlo (void)
+{
+    env->CP0_WatchLo = T0;
+    RETURN();
+}
+
+void op_mtc0_watchhi (void)
+{
+    env->CP0_WatchHi = T0 & 0x40FF0FF8;
+    RETURN();
+}
+
+void op_mtc0_debug (void)
+{
+    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
+    if (T0 & (1 << CP0DB_DM))
+        env->hflags |= MIPS_HFLAG_DM;
+    else
+        env->hflags &= ~MIPS_HFLAG_DM;
+    RETURN();
+}
+
+void op_mtc0_depc (void)
+{
+    env->CP0_DEPC = T0;
+    RETURN();
+}
+
+void op_mtc0_taglo (void)
+{
+    env->CP0_TagLo = T0 & 0xFFFFFCF6;
+    RETURN();
+}
+
+void op_mtc0_errorepc (void)
+{
+    env->CP0_ErrorEPC = T0;
+    RETURN();
+}
+
+void op_mtc0_desave (void)
+{
+    env->CP0_DESAVE = T0;
     RETURN();
 }
 
index d3959f3801584ebe77fd177df08476dc315cde45..11e12c0d84b66f7ed9ed186946651a6fa5a70f66 100644 (file)
@@ -141,9 +141,24 @@ void do_mfc0_count (void)
     cpu_abort(env, "mfc0 count\n");
 }
 
-void do_mtc0 (int reg, int sel)
+void cpu_mips_store_count(CPUState *env, uint32_t value)
 {
-    cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
+    cpu_abort(env, "mtc0 count\n");
+}
+
+void cpu_mips_store_compare(CPUState *env, uint32_t value)
+{
+    cpu_abort(env, "mtc0 compare\n");
+}
+
+void do_mtc0_status_debug(uint32_t old, uint32_t val)
+{
+    cpu_abort(env, "mtc0 status\n");
+}
+
+void do_mtc0_status_irqraise_debug(void)
+{
+    cpu_abort(env, "mtc0 status\n");
 }
 
 void do_tlbwi (void)
@@ -166,6 +181,11 @@ void do_tlbr (void)
     cpu_abort(env, "tlbr\n");
 }
 
+void cpu_mips_tlb_flush (CPUState *env, int flush_global)
+{
+    cpu_abort(env, "mips_tlb_flush\n");
+}
+
 #else
 
 /* CP0 helpers */
@@ -179,222 +199,17 @@ void do_mfc0_count (void)
     T0 = cpu_mips_get_count(env);
 }
 
-void do_mtc0 (int reg, int sel)
+void do_mtc0_status_debug(uint32_t old, uint32_t val)
 {
-    const unsigned char *rn;
-    uint32_t val, old, mask;
+    const uint32_t mask = 0x0000FF00;
+    fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
+            old, val, env->CP0_Cause, old & mask, val & mask,
+            env->CP0_Cause & mask);
+}
 
-    if (sel != 0 && reg != 16 && reg != 28) {
-        val = -1;
-        old = -1;
-        rn = "invalid";
-        goto print;
-    }
-    switch (reg) {
-    case 0:
-        val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
-        old = env->CP0_index;
-        env->CP0_index = val;
-        rn = "Index";
-        break;
-    case 2:
-        val = T0 & 0x3FFFFFFF;
-        old = env->CP0_EntryLo0;
-        env->CP0_EntryLo0 = val;
-        rn = "EntryLo0";
-        break;
-    case 3:
-        val = T0 & 0x3FFFFFFF;
-        old = env->CP0_EntryLo1;
-        env->CP0_EntryLo1 = val;
-        rn = "EntryLo1";
-        break;
-    case 4:
-        val = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0);
-        old = env->CP0_Context;
-        env->CP0_Context = val;
-        rn = "Context";
-        break;
-    case 5:
-        val = T0 & 0x01FFE000;
-        old = env->CP0_PageMask;
-        env->CP0_PageMask = val;
-        rn = "PageMask";
-        break;
-    case 6:
-        val = T0 & 0x0000000F;
-        old = env->CP0_Wired;
-        env->CP0_Wired = val;
-        rn = "Wired";
-        break;
-    case 9:
-        val = T0;
-        old = cpu_mips_get_count(env);
-        cpu_mips_store_count(env, val);
-        rn = "Count";
-        break;
-    case 10:
-        val = T0 & 0xFFFFE0FF;
-        old = env->CP0_EntryHi;
-        env->CP0_EntryHi = val;
-       /* If the ASID changes, flush qemu's TLB.  */
-       if ((old & 0xFF) != (val & 0xFF))
-         cpu_mips_tlb_flush (env, 1);
-        rn = "EntryHi";
-        break;
-    case 11:
-        val = T0;
-        old = env->CP0_Compare;
-        cpu_mips_store_compare(env, val);
-        rn = "Compare";
-        break;
-    case 12:
-        val = T0 & 0xFA78FF01;
-        if (T0 & (1 << CP0St_UM))
-            env->hflags |= MIPS_HFLAG_UM;
-        else
-            env->hflags &= ~MIPS_HFLAG_UM;
-        if (T0 & (1 << CP0St_ERL))
-            env->hflags |= MIPS_HFLAG_ERL;
-        else
-            env->hflags &= ~MIPS_HFLAG_ERL;
-        if (T0 & (1 << CP0St_EXL))
-            env->hflags |= MIPS_HFLAG_EXL;
-        else
-            env->hflags &= ~MIPS_HFLAG_EXL;
-        old = env->CP0_Status;
-        env->CP0_Status = val;
-        /* If we unmasked an asserted IRQ, raise it */
-        mask = 0x0000FF00;
-        if (loglevel & CPU_LOG_TB_IN_ASM) {
-            fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
-                    old, val, env->CP0_Cause, old & mask, val & mask,
-                    env->CP0_Cause & mask);
-        }
-        if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
-            !(env->hflags & MIPS_HFLAG_EXL) &&
-            !(env->hflags & MIPS_HFLAG_ERL) &&
-            !(env->hflags & MIPS_HFLAG_DM) &&
-            (env->CP0_Status & env->CP0_Cause & mask)) {
-            if (logfile)
-                fprintf(logfile, "Raise pending IRQs\n");
-            env->interrupt_request |= CPU_INTERRUPT_HARD;
-        } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
-            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-        }
-        rn = "Status";
-        break;
-    case 13:
-        val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
-        old = env->CP0_Cause;
-        env->CP0_Cause = val;
-#if 0
-        {
-            int i;
-            /* Check if we ever asserted a software IRQ */
-            for (i = 0; i < 2; i++) {
-                mask = 0x100 << i;
-                if ((val & mask) & !(old & mask))
-                    mips_set_irq(i);
-            }
-        }
-#endif
-        rn = "Cause";
-        break;
-    case 14:
-        val = T0;
-        old = env->CP0_EPC;
-        env->CP0_EPC = val;
-        rn = "EPC";
-        break;
-    case 16:
-        switch (sel) {
-        case 0:
-#if defined(MIPS_USES_R4K_TLB)
-            val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
-#else
-            val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
-#endif
-            old = env->CP0_Config0;
-            env->CP0_Config0 = val;
-            rn = "Config0";
-            break;
-        default:
-            val = -1;
-            old = -1;
-            rn = "bad config selector";
-            break;
-        }
-        break;
-    case 18:
-        val = T0;
-        old = env->CP0_WatchLo;
-        env->CP0_WatchLo = val;
-        rn = "WatchLo";
-        break;
-    case 19:
-        val = T0 & 0x40FF0FF8;
-        old = env->CP0_WatchHi;
-        env->CP0_WatchHi = val;
-        rn = "WatchHi";
-        break;
-    case 23:
-        val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
-        if (T0 & (1 << CP0DB_DM))
-            env->hflags |= MIPS_HFLAG_DM;
-        else
-            env->hflags &= ~MIPS_HFLAG_DM;
-        old = env->CP0_Debug;
-        env->CP0_Debug = val;
-        rn = "Debug";
-        break;
-    case 24:
-        val = T0;
-        old = env->CP0_DEPC;
-        env->CP0_DEPC = val;
-        rn = "DEPC";
-        break;
-    case 28:
-        switch (sel) {
-        case 0:
-            val = T0 & 0xFFFFFCF6;
-            old = env->CP0_TagLo;
-            env->CP0_TagLo = val;
-            rn = "TagLo";
-            break;
-        default:
-            val = -1;
-            old = -1;
-            rn = "invalid sel";
-            break;
-        }
-        break;
-    case 30:
-        val = T0;
-        old = env->CP0_ErrorEPC;
-        env->CP0_ErrorEPC = val;
-        rn = "EPC";
-        break;
-    case 31:
-        val = T0;
-        old = env->CP0_DESAVE;
-        env->CP0_DESAVE = val;
-        rn = "DESAVE";
-        break;
-    default:
-        val = -1;
-        old = -1;
-        rn = "unknown";
-        break;
-    }
- print:
-#if defined MIPS_DEBUG_DISAS
-    if (loglevel & CPU_LOG_TB_IN_ASM) {
-        fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
-                env->PC, rn, T0, val, reg, sel, old);
-    }
-#endif
-    return;
+void do_mtc0_status_irqraise_debug(void)
+{
+    fprintf(logfile, "Raise pending IRQs\n");
 }
 
 #ifdef MIPS_USES_FPU
index e1c8bd4c70a8ba7b51b3ebc9b5b27982c904b239..688066710960c29159fd80a6f1445308d8274a69 100644 (file)
@@ -1371,6 +1371,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
         rn = "EntryLo0";
         break;
     case 3:
+       /* also CONF */
         gen_op_mfc0_entrylo1();
         rn = "EntryLo1";
         break;
@@ -1386,6 +1387,10 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
         gen_op_mfc0_wired();
         rn = "Wired";
         break;
+    case 7:
+//        gen_op_mfc0_info();
+        rn = "Info";
+        break;
     case 8:
         gen_op_mfc0_badvaddr();
         rn = "BadVaddr";
@@ -1445,6 +1450,19 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
         gen_op_mfc0_watchhi();
         rn = "WatchHi";
         break;
+    case 20:
+       /* 64 bit only */
+//        gen_op_mfc0_xcontext();
+        rn = "XContext";
+        break;
+    case 21:
+//        gen_op_mfc0_framemask();
+        rn = "Framemask";
+        break;
+    case 22:
+//        gen_op_mfc0_diagnostic();
+        rn = "'Diagnostic";
+        break;
     case 23:
         gen_op_mfc0_debug();
         rn = "Debug";
@@ -1453,6 +1471,18 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
         gen_op_mfc0_depc();
         rn = "DEPC";
         break;
+    case 25:
+//        gen_op_mfc0_performance();
+        rn = "Performance";
+        break;
+    case 26:
+//        gen_op_mfc0_ecc();
+        rn = "ECC";
+        break;
+    case 27:
+//        gen_op_mfc0_cacheerr();
+        rn = "CacheErr";
+        break;
     case 28:
         switch (sel) {
         case 0:
@@ -1468,6 +1498,10 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
             goto die;
         }
         break;
+    case 29:
+//        gen_op_mfc0_taghi();
+        rn = "TagHi";
+        break;
     case 30:
         gen_op_mfc0_errorepc();
         rn = "ErrorEPC";
@@ -1498,6 +1532,183 @@ die:
     generate_exception(ctx, EXCP_RI);
 }
 
+static void gen_mtc0 (DisasContext *ctx, int reg, int sel)
+{
+    const unsigned char *rn;
+    uint32_t val, old;
+
+    if (sel != 0 && reg != 16 && reg != 28) {
+        val = -1;
+        old = -1;
+        rn = "invalid";
+        goto die;
+    }
+    switch (reg) {
+    case 0:
+        gen_op_mtc0_index();
+        rn = "Index";
+        break;
+    case 1:
+// ignore or except?
+        rn = "Random";
+        break;
+    case 2:
+        gen_op_mtc0_entrylo0();
+        rn = "EntryLo0";
+        break;
+    case 3:
+        gen_op_mtc0_entrylo1();
+        rn = "EntryLo1";
+        break;
+    case 4:
+        gen_op_mtc0_context();
+        rn = "Context";
+        break;
+    case 5:
+        gen_op_mtc0_pagemask();
+        rn = "PageMask";
+        break;
+    case 6:
+        gen_op_mtc0_wired();
+        rn = "Wired";
+        break;
+    case 7:
+// ignore or except?
+        rn = "Info";
+        break;
+    case 8:
+// ignore or except?
+        rn = "BadVaddr";
+        break;
+    case 9:
+        gen_op_mtc0_count();
+        rn = "Count";
+        break;
+    case 10:
+        gen_op_mtc0_entryhi();
+        rn = "EntryHi";
+        break;
+    case 11:
+        gen_op_mtc0_compare();
+        rn = "Compare";
+        break;
+    case 12:
+        gen_op_mtc0_status();
+        rn = "Status";
+        break;
+    case 13:
+        gen_op_mtc0_cause();
+        rn = "Cause";
+        break;
+    case 14:
+        gen_op_mtc0_epc();
+        rn = "EPC";
+        break;
+    case 15:
+// ignore or except?
+        rn = "PRid";
+        break;
+    case 16:
+        switch (sel) {
+        case 0:
+           gen_op_mtc0_config0();
+            rn = "Config0";
+            break;
+        default:
+            rn = "Invalid config selector";
+            goto die;
+        }
+        break;
+    case 17:
+// ignore or except?
+        rn = "LLaddr";
+        break;
+    case 18:
+        gen_op_mtc0_watchlo();
+        rn = "WatchLo";
+        break;
+    case 19:
+        gen_op_mtc0_watchhi();
+        rn = "WatchHi";
+        break;
+    case 20:
+       /* 64 bit only */
+//     gen_op_mtc0_xcontext();
+        rn = "XContext";
+        break;
+    case 21:
+//        gen_op_mtc0_framemask();
+        rn = "Framemask";
+       break;
+    case 22:
+// ignore or except?
+        rn = "Diagnostic";
+       break;
+    case 23:
+        gen_op_mtc0_debug();
+        rn = "Debug";
+        break;
+    case 24:
+        gen_op_mtc0_depc();
+        rn = "DEPC";
+        break;
+    case 25:
+// ignore or except?
+        rn = "Performance";
+       break;
+    case 26:
+// ignore or except?
+        rn = "ECC";
+       break;
+    case 27:
+// ignore or except?
+        rn = "CacheErr";
+       break;
+    case 28:
+        switch (sel) {
+        case 0:
+            gen_op_mtc0_taglo();
+            rn = "TagLo";
+            break;
+        default:
+            rn = "invalid sel";
+            goto die;
+        }
+        break;
+    case 29:
+//     gen_op_mtc0_taghi();
+        rn = "TagHi";
+       break;
+    case 30:
+        gen_op_mtc0_errorepc();
+        rn = "ErrorEPC";
+        break;
+    case 31:
+        gen_op_mtc0_desave();
+        rn = "DESAVE";
+        break;
+    default:
+        rn = "unknown";
+       goto die;
+    }
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "%08x mtc0 %s => %08x (%d %d)\n",
+                env->PC, rn, T0, reg, sel);
+    }
+#endif
+    return;
+
+die:
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "%08x mtc0 %s => %08x (%d %d)\n",
+                env->PC, rn, T0, reg, sel);
+    }
+#endif
+    generate_exception(ctx, EXCP_RI);
+}
+
 static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
 {
     const unsigned char *opn = "unk";
@@ -1529,7 +1740,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
         save_cpu_state(ctx, 1);
         ctx->pc -= 4;
         GEN_LOAD_REG_TN(T0, rt);
-        gen_op_mtc0(rd, ctx->opcode & 0x7);
+        gen_mtc0(ctx, rd, ctx->opcode & 0x7);
         /* Stop translation as we may have switched the execution mode */
         ctx->bstate = BS_STOP;
         opn = "mtc0";