Rework PowerPC 440 TLB management (thanks to Hollis Blanchard)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3200 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 9e26deb..07b336b 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -2607,95 +2607,79 @@
 #endif
 }
 
-/* BookE TLB management */
-void do_booke_tlbwe0 (void)
+/* PowerPC 440 TLB management */
+void do_440_tlbwe (int word)
 {
     ppcemb_tlb_t *tlb;
-    target_ulong EPN, size;
+    target_ulong EPN, RPN, size;
     int do_flush_tlbs;
 
 #if defined (DEBUG_SOFTWARE_TLB)
     if (loglevel != 0) {
-        fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
+        fprintf(logfile, "%s word %d T0 " REGX " T1 " REGX "\n",
+                __func__, word, T0, T1);
     }
 #endif
     do_flush_tlbs = 0;
     T0 &= 0x3F;
     tlb = &env->tlb[T0].tlbe;
-    EPN = T1 & 0xFFFFFC00;
-    if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
-        do_flush_tlbs = 1;
-    tlb->EPN = EPN;
-    size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
-    if ((tlb->prot & PAGE_VALID) && tlb->size < size)
-        do_flush_tlbs = 1;
-    tlb->size = size;
-    tlb->attr &= ~0x1;
-    tlb->attr |= (T1 >> 8) & 1;
-    if (T1 & 0x200) {
-        tlb->prot |= PAGE_VALID;
-    } else {
-        if (tlb->prot & PAGE_VALID) {
-            tlb->prot &= ~PAGE_VALID;
+    switch (word) {
+    default:
+        /* Just here to please gcc */
+    case 0:
+        EPN = T1 & 0xFFFFFC00;
+        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
             do_flush_tlbs = 1;
+        tlb->EPN = EPN;
+        size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
+        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
+            do_flush_tlbs = 1;
+        tlb->size = size;
+        tlb->attr &= ~0x1;
+        tlb->attr |= (T1 >> 8) & 1;
+        if (T1 & 0x200) {
+            tlb->prot |= PAGE_VALID;
+        } else {
+            if (tlb->prot & PAGE_VALID) {
+                tlb->prot &= ~PAGE_VALID;
+                do_flush_tlbs = 1;
+            }
         }
+        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
+        if (do_flush_tlbs)
+            tlb_flush(env, 1);
+        break;
+    case 1:
+        RPN = T1 & 0xFFFFFC0F;
+        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
+            tlb_flush(env, 1);
+        tlb->RPN = RPN;
+        break;
+    case 2:
+        tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
+        tlb->prot = tlb->prot & PAGE_VALID;
+        if (T1 & 0x1)
+            tlb->prot |= PAGE_READ << 4;
+        if (T1 & 0x2)
+            tlb->prot |= PAGE_WRITE << 4;
+        if (T1 & 0x4)
+            tlb->prot |= PAGE_EXEC << 4;
+        if (T1 & 0x8)
+            tlb->prot |= PAGE_READ;
+        if (T1 & 0x10)
+            tlb->prot |= PAGE_WRITE;
+        if (T1 & 0x20)
+            tlb->prot |= PAGE_EXEC;
+        break;
     }
-    tlb->PID = env->spr[SPR_BOOKE_PID];
-    if (do_flush_tlbs)
-        tlb_flush(env, 1);
 }
 
-void do_booke_tlbwe1 (void)
-{
-    ppcemb_tlb_t *tlb;
-    target_phys_addr_t RPN;
-
-#if defined (DEBUG_SOFTWARE_TLB)
-    if (loglevel != 0) {
-        fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
-    }
-#endif
-    T0 &= 0x3F;
-    tlb = &env->tlb[T0].tlbe;
-    RPN = T1 & 0xFFFFFC0F;
-    if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
-        tlb_flush(env, 1);
-    tlb->RPN = RPN;
-}
-
-void do_booke_tlbwe2 (void)
-{
-    ppcemb_tlb_t *tlb;
-
-#if defined (DEBUG_SOFTWARE_TLB)
-    if (loglevel != 0) {
-        fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
-    }
-#endif
-    T0 &= 0x3F;
-    tlb = &env->tlb[T0].tlbe;
-    tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
-    tlb->prot = tlb->prot & PAGE_VALID;
-    if (T1 & 0x1)
-        tlb->prot |= PAGE_READ << 4;
-    if (T1 & 0x2)
-        tlb->prot |= PAGE_WRITE << 4;
-    if (T1 & 0x4)
-        tlb->prot |= PAGE_EXEC << 4;
-    if (T1 & 0x8)
-        tlb->prot |= PAGE_READ;
-    if (T1 & 0x10)
-        tlb->prot |= PAGE_WRITE;
-    if (T1 & 0x20)
-        tlb->prot |= PAGE_EXEC;
-}
-
-void do_booke_tlbsx (void)
+void do_440_tlbsx (void)
 {
     T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]);
 }
 
-void do_booke_tlbsx_ (void)
+void do_440_tlbsx_ (void)
 {
     int tmp = xer_so;
 
@@ -2705,52 +2689,47 @@
     env->crf[0] = tmp;
 }
 
-void do_booke_tlbre0 (void)
+void do_440_tlbre (int word)
 {
     ppcemb_tlb_t *tlb;
     int size;
 
     T0 &= 0x3F;
     tlb = &env->tlb[T0].tlbe;
-    T0 = tlb->EPN;
-    size = booke_page_size_to_tlb(tlb->size);
-    if (size < 0 || size > 0xF)
-        size = 1;
-    T0 |= size << 4;
-    if (tlb->attr & 0x1)
-        T0 |= 0x100;
-    if (tlb->prot & PAGE_VALID)
-        T0 |= 0x200;
-    env->spr[SPR_BOOKE_PID] = tlb->PID;
-}
-
-void do_booke_tlbre1 (void)
-{
-    ppcemb_tlb_t *tlb;
-
-    T0 &= 0x3F;
-    tlb = &env->tlb[T0].tlbe;
-    T0 = tlb->RPN;
-}
-
-void do_booke_tlbre2 (void)
-{
-    ppcemb_tlb_t *tlb;
-
-    T0 &= 0x3F;
-    tlb = &env->tlb[T0].tlbe;
-    T0 = tlb->attr & ~0x1;
-    if (tlb->prot & (PAGE_READ << 4))
-        T0 |= 0x1;
-    if (tlb->prot & (PAGE_WRITE << 4))
-        T0 |= 0x2;
-    if (tlb->prot & (PAGE_EXEC << 4))
-        T0 |= 0x4;
-    if (tlb->prot & PAGE_READ)
-        T0 |= 0x8;
-    if (tlb->prot & PAGE_WRITE)
-        T0 |= 0x10;
-    if (tlb->prot & PAGE_EXEC)
-        T0 |= 0x20;
+    switch (word) {
+    default:
+        /* Just here to please gcc */
+    case 0:
+        T0 = tlb->EPN;
+        size = booke_page_size_to_tlb(tlb->size);
+        if (size < 0 || size > 0xF)
+            size = 1;
+        T0 |= size << 4;
+        if (tlb->attr & 0x1)
+            T0 |= 0x100;
+        if (tlb->prot & PAGE_VALID)
+            T0 |= 0x200;
+        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
+        env->spr[SPR_440_MMUCR] |= tlb->PID;
+        break;
+    case 1:
+        T0 = tlb->RPN;
+        break;
+    case 2:
+        T0 = tlb->attr & ~0x1;
+        if (tlb->prot & (PAGE_READ << 4))
+            T0 |= 0x1;
+        if (tlb->prot & (PAGE_WRITE << 4))
+            T0 |= 0x2;
+        if (tlb->prot & (PAGE_EXEC << 4))
+            T0 |= 0x4;
+        if (tlb->prot & PAGE_READ)
+            T0 |= 0x8;
+        if (tlb->prot & PAGE_WRITE)
+            T0 |= 0x10;
+        if (tlb->prot & PAGE_EXEC)
+            T0 |= 0x20;
+        break;
+    }
 }
 #endif /* !CONFIG_USER_ONLY */