aboutsummaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/helper.c107
-rw-r--r--target-ppc/op.c15
-rw-r--r--target-ppc/op_helper.c21
-rw-r--r--target-ppc/op_helper.h1
-rw-r--r--target-ppc/translate.c35
5 files changed, 169 insertions, 10 deletions
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 66dc7b22a8..5b0fd09b9c 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -664,7 +664,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
int ret, ret2;
#if defined(TARGET_PPC64)
- if (env->mmu_model == POWERPC_MMU_64B) {
+ if (env->mmu_model == POWERPC_MMU_64B ||
+ env->mmu_model == POWERPC_MMU_64BRIDGE) {
ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr);
if (ret < 0)
return ret;
@@ -730,7 +731,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
}
/* Initialize real address with an invalid value */
ctx->raddr = (target_ulong)-1;
- if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) {
+ if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
+ env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
/* Software TLB search */
ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
} else {
@@ -1092,9 +1094,11 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
switch (env->mmu_model) {
case POWERPC_MMU_32B:
case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
case POWERPC_MMU_601:
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_REAL_4xx:
+ case POWERPC_MMU_BOOKE:
ctx->prot |= PAGE_WRITE;
break;
#if defined(TARGET_PPC64)
@@ -1129,9 +1133,6 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
}
}
break;
- case POWERPC_MMU_BOOKE:
- ctx->prot |= PAGE_WRITE;
- break;
case POWERPC_MMU_BOOKE_FSL:
/* XXX: TODO */
cpu_abort(env, "BookE FSL MMU model not implemented\n");
@@ -1162,6 +1163,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
switch (env->mmu_model) {
case POWERPC_MMU_32B:
case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
/* Try to find a BAT */
if (check_BATs)
ret = get_bat(env, ctx, eaddr, rw, access_type);
@@ -1262,6 +1264,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
error_code = 1 << 18;
goto tlb_miss;
+ case POWERPC_MMU_SOFT_74xx:
+ exception = POWERPC_EXCP_IFTLB;
+ goto tlb_miss_74xx;
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_SOFT_4xx_Z:
exception = POWERPC_EXCP_ITLB;
@@ -1346,6 +1351,19 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
env->spr[SPR_HASH2] = ctx.pg_addr[1];
/* Do not alter DAR nor DSISR */
goto out;
+ case POWERPC_MMU_SOFT_74xx:
+ if (rw == 1) {
+ exception = POWERPC_EXCP_DSTLB;
+ } else {
+ exception = POWERPC_EXCP_DLTLB;
+ }
+ tlb_miss_74xx:
+ /* Implement LRU algorithm */
+ env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
+ ((env->last_way + 1) & (env->nb_ways - 1));
+ env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
+ error_code = ctx.key << 19;
+ break;
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_SOFT_4xx_Z:
exception = POWERPC_EXCP_DTLB;
@@ -1571,13 +1589,31 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
{
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
ppc6xx_tlb_invalidate_all(env);
break;
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_SOFT_4xx_Z:
ppc4xx_tlb_invalidate_all(env);
break;
- default:
+ case POWERPC_MMU_REAL_4xx:
+ cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+ break;
+ case POWERPC_MMU_BOOKE:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_BOOKE_FSL:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_601:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_64BRIDGE:
tlb_flush(env, 1);
break;
}
@@ -1589,6 +1625,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
addr &= TARGET_PAGE_MASK;
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
ppc6xx_tlb_invalidate_virt(env, addr, 0);
if (env->id_tlbs == 1)
ppc6xx_tlb_invalidate_virt(env, addr, 1);
@@ -1597,7 +1634,22 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
case POWERPC_MMU_SOFT_4xx_Z:
ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
break;
- default:
+ case POWERPC_MMU_REAL_4xx:
+ cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+ break;
+ case POWERPC_MMU_BOOKE:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_BOOKE_FSL:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_601:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ break;
+ case POWERPC_MMU_32B:
/* tlbie invalidate TLBs for all segments */
addr &= ~((target_ulong)-1 << 28);
/* XXX: this case should be optimized,
@@ -1619,6 +1671,15 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
tlb_flush_page(env, addr | (0xD << 28));
tlb_flush_page(env, addr | (0xE << 28));
tlb_flush_page(env, addr | (0xF << 28));
+ break;
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_64BRIDGE:
+ /* tlbie invalidate TLBs for all segments */
+ /* XXX: given the fact that there are too many segments to invalidate,
+ * we just invalidate all TLBs
+ */
+ tlb_flush(env, 1);
+ break;
}
#else
ppc_tlb_invalidate_all(env);
@@ -2317,6 +2378,8 @@ static always_inline void powerpc_excp (CPUState *env,
goto tlb_miss_tgpr;
case POWERPC_EXCP_7x5:
goto tlb_miss;
+ case POWERPC_EXCP_74xx:
+ goto tlb_miss_74xx;
default:
cpu_abort(env, "Invalid instruction TLB miss exception\n");
break;
@@ -2336,6 +2399,8 @@ static always_inline void powerpc_excp (CPUState *env,
goto tlb_miss_tgpr;
case POWERPC_EXCP_7x5:
goto tlb_miss;
+ case POWERPC_EXCP_74xx:
+ goto tlb_miss_74xx;
default:
cpu_abort(env, "Invalid data load TLB miss exception\n");
break;
@@ -2390,6 +2455,34 @@ static always_inline void powerpc_excp (CPUState *env,
/* Set way using a LRU mechanism */
msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
break;
+ case POWERPC_EXCP_74xx:
+ tlb_miss_74xx:
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ const unsigned char *es;
+ target_ulong *miss, *cmp;
+ int en;
+ if (excp == POWERPC_EXCP_IFTLB) {
+ es = "I";
+ en = 'I';
+ miss = &env->spr[SPR_IMISS];
+ cmp = &env->spr[SPR_ICMP];
+ } else {
+ if (excp == POWERPC_EXCP_DLTLB)
+ es = "DL";
+ else
+ es = "DS";
+ en = 'D';
+ miss = &env->spr[SPR_TLBMISS];
+ cmp = &env->spr[SPR_PTEHI];
+ }
+ fprintf(logfile, "74xx %sTLB miss: %cM " ADDRX " %cC " ADDRX
+ " %08x\n",
+ es, en, *miss, en, *cmp, env->error_code);
+ }
+#endif
+ msr |= env->error_code; /* key bit */
+ break;
default:
cpu_abort(env, "Invalid data store TLB miss exception\n");
break;
diff --git a/target-ppc/op.c b/target-ppc/op.c
index 6ad68eabaa..822c267695 100644
--- a/target-ppc/op.c
+++ b/target-ppc/op.c
@@ -2025,8 +2025,8 @@ void OPPROTO op_slbie_64 (void)
#endif
#endif
-/* PowerPC 602/603/755 software TLB load instructions */
#if !defined(CONFIG_USER_ONLY)
+/* PowerPC 602/603/755 software TLB load instructions */
void OPPROTO op_6xx_tlbld (void)
{
do_load_6xx_tlb(0);
@@ -2038,6 +2038,19 @@ void OPPROTO op_6xx_tlbli (void)
do_load_6xx_tlb(1);
RETURN();
}
+
+/* PowerPC 74xx software TLB load instructions */
+void OPPROTO op_74xx_tlbld (void)
+{
+ do_load_74xx_tlb(0);
+ RETURN();
+}
+
+void OPPROTO op_74xx_tlbli (void)
+{
+ do_load_74xx_tlb(1);
+ RETURN();
+}
#endif
/* 601 specific */
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index a7c81776fd..8bb93ed36b 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -2363,6 +2363,27 @@ void do_load_6xx_tlb (int is_code)
way, is_code, CMP, RPN);
}
+void do_load_74xx_tlb (int is_code)
+{
+ target_ulong RPN, CMP, EPN;
+ int way;
+
+ RPN = env->spr[SPR_PTELO];
+ CMP = env->spr[SPR_PTEHI];
+ EPN = env->spr[SPR_TLBMISS] & ~0x3;
+ way = env->spr[SPR_TLBMISS] & 0x3;
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
+ __func__, (unsigned long)T0, (unsigned long)EPN,
+ (unsigned long)CMP, (unsigned long)RPN, way);
+ }
+#endif
+ /* Store this TLB */
+ ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
+ way, is_code, CMP, RPN);
+}
+
static target_ulong booke_tlb_to_page_size (int size)
{
return 1024 << (2 * size);
diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h
index 6f79cad912..0406682c76 100644
--- a/target-ppc/op_helper.h
+++ b/target-ppc/op_helper.h
@@ -135,6 +135,7 @@ void do_rfid (void);
void do_hrfid (void);
#endif
void do_load_6xx_tlb (int is_code);
+void do_load_74xx_tlb (int is_code);
#endif
/* POWER / PowerPC 601 specific helpers */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index e599243b73..d8f6e95c9e 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -4299,7 +4299,7 @@ GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
/* 602 - 603 - G2 TLB management */
/* tlbld */
-GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
+GEN_HANDLER(tlbld_6xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
{
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVOPC(ctx);
@@ -4314,7 +4314,7 @@ GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
}
/* tlbli */
-GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
+GEN_HANDLER(tlbli_6xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
{
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVOPC(ctx);
@@ -4328,6 +4328,37 @@ GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
#endif
}
+/* 74xx TLB management */
+/* tlbld */
+GEN_HANDLER(tlbld_74xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_op_74xx_tlbld();
+#endif
+}
+
+/* tlbli */
+GEN_HANDLER(tlbli_74xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_EXCP_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ GEN_EXCP_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_op_74xx_tlbli();
+#endif
+}
+
/* POWER instructions not in PowerPC 601 */
/* clf */
GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER)