target_ulong va,
target_phys_addr_t pa)
{
- ppcemb_tlb_t *tlb = &env->tlb[0].tlbe;
+ ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
tlb->attr = 0;
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
tlb->RPN = pa & TARGET_PAGE_MASK;
tlb->PID = 0;
- tlb = &env->tlb[1].tlbe;
+ tlb = &env->tlb.tlbe[1];
tlb->attr = 0;
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
tlb->size = 1 << 31; /* up to 0xffffffff */
} ppcmas_tlb_t;
union ppc_tlb_t {
- ppc6xx_tlb_t tlb6;
- ppcemb_tlb_t tlbe;
- ppcmas_tlb_t tlbm;
+ ppc6xx_tlb_t *tlb6;
+ ppcemb_tlb_t *tlbe;
+ ppcmas_tlb_t *tlbm;
};
+
+/* possible TLB variants */
+#define TLB_NONE 0
+#define TLB_6XX 1
+#define TLB_EMB 2
+#define TLB_MAS 3
#endif
#define SDR_32_HTABORG 0xFFFF0000UL
int last_way; /* Last used way used to allocate TLB in a LRU way */
int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */
int nb_pids; /* Number of available PID registers */
- ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */
+ int tlb_type; /* Type of TLB we're dealing with */
+ ppc_tlb_t tlb; /* TLB is optional. Allocate them only if needed */
/* 403 dedicated access protection registers */
target_ulong pb[4];
#endif
static inline int booke206_tlbm_id(CPUState *env, ppcmas_tlb_t *tlbm)
{
uintptr_t tlbml = (uintptr_t)tlbm;
- uintptr_t tlbl = (uintptr_t)env->tlb;
+ uintptr_t tlbl = (uintptr_t)env->tlb.tlbm;
- return (tlbml - tlbl) / sizeof(env->tlb[0]);
+ return (tlbml - tlbl) / sizeof(env->tlb.tlbm[0]);
}
static inline int booke206_tlb_size(CPUState *env, int tlbn)
r += booke206_tlb_size(env, i);
}
- return &env->tlb[r].tlbm;
+ return &env->tlb.tlbm[r];
}
#endif
if (env->id_tlbs == 1)
max *= 2;
for (nr = 0; nr < max; nr++) {
- tlb = &env->tlb[nr].tlb6;
+ tlb = &env->tlb.tlb6[nr];
pte_invalidate(&tlb->pte0);
}
tlb_flush(env, 1);
/* Invalidate ITLB + DTLB, all ways */
for (way = 0; way < env->nb_ways; way++) {
nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
- tlb = &env->tlb[nr].tlb6;
+ tlb = &env->tlb.tlb6[nr];
if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
env->nb_tlb, eaddr);
int nr;
nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
- tlb = &env->tlb[nr].tlb6;
+ tlb = &env->tlb.tlb6[nr];
LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
" PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
/* Invalidate any pending reference in Qemu for this virtual address */
for (way = 0; way < env->nb_ways; way++) {
nr = ppc6xx_tlb_getnum(env, eaddr, way,
access_type == ACCESS_CODE ? 1 : 0);
- tlb = &env->tlb[nr].tlb6;
+ tlb = &env->tlb.tlb6[nr];
/* This test "emulates" the PTE index match for hardware TLBs */
if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
/* Update page flags */
- pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw);
+ pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
}
return ret;
/* Default return value is no match */
ret = -1;
for (i = 0; i < env->nb_tlb; i++) {
- tlb = &env->tlb[i].tlbe;
+ tlb = &env->tlb.tlbe[i];
if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
ret = i;
break;
int i;
for (i = 0; i < env->nb_tlb; i++) {
- tlb = &env->tlb[i].tlbe;
+ tlb = &env->tlb.tlbe[i];
tlb->prot &= ~PAGE_VALID;
}
tlb_flush(env, 1);
int i;
for (i = 0; i < env->nb_tlb; i++) {
- tlb = &env->tlb[i].tlbe;
+ tlb = &env->tlb.tlbe[i];
if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
end = tlb->EPN + tlb->size;
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
raddr = (target_phys_addr_t)-1ULL;
pr = msr_pr;
for (i = 0; i < env->nb_tlb; i++) {
- tlb = &env->tlb[i].tlbe;
+ tlb = &env->tlb.tlbe[i];
if (ppcemb_tlb_check(env, tlb, &raddr, address,
env->spr[SPR_40x_PID], 0, i) < 0)
continue;
ret = -1;
raddr = (target_phys_addr_t)-1ULL;
for (i = 0; i < env->nb_tlb; i++) {
- tlb = &env->tlb[i].tlbe;
+ tlb = &env->tlb.tlbe[i];
ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
access_type, i);
if (!ret) {
{
int tlb_size;
int i, j;
- ppc_tlb_t *tlb = env->tlb;
+ ppcmas_tlb_t *tlb = env->tlb.tlbm;
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
if (flags & (1 << i)) {
tlb_size = booke206_tlb_size(env, i);
for (j = 0; j < tlb_size; j++) {
- if (!check_iprot || !(tlb[j].tlbm.mas1 & MAS1_IPROT)) {
- tlb[j].tlbm.mas1 &= ~MAS1_VALID;
+ if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
+ tlb[j].mas1 &= ~MAS1_VALID;
}
}
}
qemu_put_sbe32s(f, &env->last_way);
qemu_put_sbe32s(f, &env->id_tlbs);
qemu_put_sbe32s(f, &env->nb_pids);
- if (env->tlb) {
+ if (env->tlb.tlb6) {
// XXX assumes 6xx
for (i = 0; i < env->nb_tlb; i++) {
- qemu_put_betls(f, &env->tlb[i].tlb6.pte0);
- qemu_put_betls(f, &env->tlb[i].tlb6.pte1);
- qemu_put_betls(f, &env->tlb[i].tlb6.EPN);
+ qemu_put_betls(f, &env->tlb.tlb6[i].pte0);
+ qemu_put_betls(f, &env->tlb.tlb6[i].pte1);
+ qemu_put_betls(f, &env->tlb.tlb6[i].EPN);
}
}
for (i = 0; i < 4; i++)
qemu_get_sbe32s(f, &env->last_way);
qemu_get_sbe32s(f, &env->id_tlbs);
qemu_get_sbe32s(f, &env->nb_pids);
- if (env->tlb) {
+ if (env->tlb.tlb6) {
// XXX assumes 6xx
for (i = 0; i < env->nb_tlb; i++) {
- qemu_get_betls(f, &env->tlb[i].tlb6.pte0);
- qemu_get_betls(f, &env->tlb[i].tlb6.pte1);
- qemu_get_betls(f, &env->tlb[i].tlb6.EPN);
+ qemu_get_betls(f, &env->tlb.tlb6[i].pte0);
+ qemu_get_betls(f, &env->tlb.tlb6[i].pte1);
+ qemu_get_betls(f, &env->tlb.tlb6[i].EPN);
}
}
for (i = 0; i < 4; i++)
int size;
entry &= PPC4XX_TLB_ENTRY_MASK;
- tlb = &env->tlb[entry].tlbe;
+ tlb = &env->tlb.tlbe[entry];
ret = tlb->EPN;
if (tlb->prot & PAGE_VALID) {
ret |= PPC4XX_TLBHI_V;
target_ulong ret;
entry &= PPC4XX_TLB_ENTRY_MASK;
- tlb = &env->tlb[entry].tlbe;
+ tlb = &env->tlb.tlbe[entry];
ret = tlb->RPN;
if (tlb->prot & PAGE_EXEC) {
ret |= PPC4XX_TLBLO_EX;
LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
val);
entry &= PPC4XX_TLB_ENTRY_MASK;
- tlb = &env->tlb[entry].tlbe;
+ tlb = &env->tlb.tlbe[entry];
/* Invalidate previous TLB (if it's valid) */
if (tlb->prot & PAGE_VALID) {
end = tlb->EPN + tlb->size;
LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
val);
entry &= PPC4XX_TLB_ENTRY_MASK;
- tlb = &env->tlb[entry].tlbe;
+ tlb = &env->tlb.tlbe[entry];
tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
tlb->prot = PAGE_READ;
__func__, word, (int)entry, value);
do_flush_tlbs = 0;
entry &= 0x3F;
- tlb = &env->tlb[entry].tlbe;
+ tlb = &env->tlb.tlbe[entry];
switch (word) {
default:
/* Just here to please gcc */
int size;
entry &= 0x3F;
- tlb = &env->tlb[entry].tlbe;
+ tlb = &env->tlb.tlbe[entry];
switch (word) {
default:
/* Just here to please gcc */
env->nb_tlb = nb_tlbs;
env->nb_ways = nb_ways;
env->id_tlbs = 1;
+ env->tlb_type = TLB_6XX;
spr_register(env, SPR_DMISS, "DMISS",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
env->nb_tlb = nb_tlbs;
env->nb_ways = nb_ways;
env->id_tlbs = 1;
+ env->tlb_type = TLB_6XX;
/* XXX : not implemented */
spr_register(env, SPR_PTEHI, "PTEHI",
SPR_NOACCESS, SPR_NOACCESS,
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_4xx_softmmu(env);
env->dcache_line_size = 32;
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_4xx_softmmu(env);
env->dcache_line_size = 32;
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_4xx_softmmu(env);
env->dcache_line_size = 32;
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_4xx_softmmu(env);
env->dcache_line_size = 32;
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_BookE(env);
env->dcache_line_size = 32;
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_BookE(env);
env->dcache_line_size = 32;
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_BookE(env);
env->dcache_line_size = 32;
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_BookE(env);
env->dcache_line_size = 32;
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_BookE(env);
env->dcache_line_size = 32;
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_BookE(env);
env->dcache_line_size = 32;
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ env->tlb_type = TLB_EMB;
#endif
init_excp_e200(env);
env->dcache_line_size = 32;
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = 0;
+ env->tlb_type = TLB_MAS;
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
env->nb_tlb += booke206_tlb_size(env, i);
}
env->nb_BATs = 0;
env->nb_tlb = 0;
env->nb_ways = 0;
+ env->tlb_type = TLB_NONE;
#endif
/* Register SPR common to all PowerPC implementations */
gen_spr_generic(env);
int nb_tlb = env->nb_tlb;
if (env->id_tlbs != 0)
nb_tlb *= 2;
- env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t));
+ switch (env->tlb_type) {
+ case TLB_6XX:
+ env->tlb.tlb6 = qemu_mallocz(nb_tlb * sizeof(ppc6xx_tlb_t));
+ break;
+ case TLB_EMB:
+ env->tlb.tlbe = qemu_mallocz(nb_tlb * sizeof(ppcemb_tlb_t));
+ break;
+ case TLB_MAS:
+ env->tlb.tlbm = qemu_mallocz(nb_tlb * sizeof(ppcmas_tlb_t));
+ break;
+ }
/* Pre-compute some useful values */
env->tlb_per_way = env->nb_tlb / env->nb_ways;
}