aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/op_helper.c
diff options
context:
space:
mode:
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>2007-03-31 11:33:48 +0000
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>2007-03-31 11:33:48 +0000
commita8dea12f453851d68c968d23faff2f1b9205d811 (patch)
tree3e7e6fe8e7e1560ec918a033de62aea0acaefc02 /target-ppc/op_helper.c
parent1d0a48fb920cdd038aa1238740032e27aa460677 (diff)
Merge PowerPC 405 MMU model.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2554 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-ppc/op_helper.c')
-rw-r--r--target-ppc/op_helper.c134
1 files changed, 101 insertions, 33 deletions
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index c21a38aea4..e1fff7f497 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -2365,65 +2365,139 @@ void do_load_6xx_tlb (int is_code)
way, is_code, CMP, RPN);
}
+static target_ulong booke_tlb_to_page_size (int size)
+{
+ return 1024 << (2 * size);
+}
+
+static int booke_page_size_to_tlb (target_ulong page_size)
+{
+ int size;
+
+ switch (page_size) {
+ case 0x00000400UL:
+ size = 0x0;
+ break;
+ case 0x00001000UL:
+ size = 0x1;
+ break;
+ case 0x00004000UL:
+ size = 0x2;
+ break;
+ case 0x00010000UL:
+ size = 0x3;
+ break;
+ case 0x00040000UL:
+ size = 0x4;
+ break;
+ case 0x00100000UL:
+ size = 0x5;
+ break;
+ case 0x00400000UL:
+ size = 0x6;
+ break;
+ case 0x01000000UL:
+ size = 0x7;
+ break;
+ case 0x04000000UL:
+ size = 0x8;
+ break;
+ case 0x10000000UL:
+ size = 0x9;
+ break;
+ case 0x40000000UL:
+ size = 0xA;
+ break;
+#if defined (TARGET_PPC64)
+ case 0x000100000000ULL:
+ size = 0xB;
+ break;
+ case 0x000400000000ULL:
+ size = 0xC;
+ break;
+ case 0x001000000000ULL:
+ size = 0xD;
+ break;
+ case 0x004000000000ULL:
+ size = 0xE;
+ break;
+ case 0x010000000000ULL:
+ size = 0xF;
+ break;
+#endif
+ default:
+ size = -1;
+ break;
+ }
+
+ return size;
+}
+
/* Helpers for 4xx TLB management */
void do_4xx_tlbia (void)
{
-#if 0
- ppc_tlb_t *tlb;
- target_ulong page, end;
+ ppcemb_tlb_t *tlb;
int i;
for (i = 0; i < 64; i++) {
- tlb = &env->tlb[i];
+ tlb = &env->tlb[i].tlbe;
if (tlb->prot & PAGE_VALID) {
+#if 0
end = tlb->EPN + tlb->size;
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
tlb_flush_page(env, page);
+#endif
tlb->prot &= ~PAGE_VALID;
}
}
-#endif
+ tlb_flush(env, 1);
}
void do_4xx_tlbre_lo (void)
{
-#if 0
- ppc_tlb_t *tlb;
+ ppcemb_tlb_t *tlb;
+ int size;
T0 &= 0x3F;
- tlb = &env->tlb[T0];
- T0 = tlb->stor[0];
- env->spr[SPR_40x_PID] = tlb->pid;
-#endif
+ tlb = &env->tlb[T0].tlbe;
+ T0 = tlb->EPN;
+ if (tlb->prot & PAGE_VALID)
+ T0 |= 0x400;
+ size = booke_page_size_to_tlb(tlb->size);
+ if (size < 0 || size > 0x7)
+ size = 1;
+ T0 |= size << 7;
+ env->spr[SPR_40x_PID] = tlb->PID;
}
void do_4xx_tlbre_hi (void)
{
-#if 0
- ppc_tlb_t *tlb;
+ ppcemb_tlb_t *tlb;
T0 &= 0x3F;
- tlb = &env->tlb[T0];
- T0 = tlb->stor[1];
-#endif
+ tlb = &env->tlb[T0].tlbe;
+ T0 = tlb->RPN;
+ if (tlb->prot & PAGE_EXEC)
+ T0 |= 0x200;
+ if (tlb->prot & PAGE_WRITE)
+ T0 |= 0x100;
}
static int tlb_4xx_search (target_ulong virtual)
{
-#if 0
- ppc_tlb_t *tlb;
+ ppcemb_tlb_t *tlb;
target_ulong base, mask;
int i, ret;
/* Default return value is no match */
ret = -1;
for (i = 0; i < 64; i++) {
- tlb = &env->tlb[i];
+ tlb = &env->tlb[i].tlbe;
/* Check TLB validity */
if (!(tlb->prot & PAGE_VALID))
continue;
/* Check TLB PID vs current PID */
- if (tlb->pid != 0 && tlb->pid != env->spr[SPR_40x_PID])
+ if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
continue;
/* Check TLB address vs virtual address */
base = tlb->EPN;
@@ -2435,9 +2509,6 @@ static int tlb_4xx_search (target_ulong virtual)
}
return ret;
-#else
- return -1;
-#endif
}
void do_4xx_tlbsx (void)
@@ -2457,47 +2528,44 @@ void do_4xx_tlbsx_ (void)
void do_4xx_tlbwe_lo (void)
{
-#if 0
- ppc_tlb_t *tlb;
+ ppcemb_tlb_t *tlb;
target_ulong page, end;
T0 &= 0x3F;
- tlb = &env->tlb[T0];
+ tlb = &env->tlb[T0].tlbe;
/* Invalidate previous TLB (if it's valid) */
if (tlb->prot & PAGE_VALID) {
end = tlb->EPN + tlb->size;
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
tlb_flush_page(env, page);
}
- tlb->size = 1024 << (2 * ((T1 >> 7) & 0x7));
+ tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1);
if (T1 & 0x400)
tlb->prot |= PAGE_VALID;
else
tlb->prot &= ~PAGE_VALID;
- tlb->pid = env->spr[SPR_BOOKE_PID]; /* PID */
+ tlb->PID = env->spr[SPR_BOOKE_PID]; /* PID */
+ tlb->attr = T1 & 0xFF;
/* Invalidate new TLB (if valid) */
if (tlb->prot & PAGE_VALID) {
end = tlb->EPN + tlb->size;
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
tlb_flush_page(env, page);
}
-#endif
}
void do_4xx_tlbwe_hi (void)
{
-#if 0
- ppc_tlb_t *tlb;
+ ppcemb_tlb_t *tlb;
T0 &= 0x3F;
- tlb = &env->tlb[T0];
+ tlb = &env->tlb[T0].tlbe;
tlb->RPN = T1 & 0xFFFFFC00;
tlb->prot = PAGE_READ;
if (T1 & 0x200)
tlb->prot |= PAGE_EXEC;
if (T1 & 0x100)
tlb->prot |= PAGE_WRITE;
-#endif
}
#endif /* !CONFIG_USER_ONLY */