aboutsummaryrefslogtreecommitdiff
path: root/target-mips
diff options
context:
space:
mode:
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2007-05-13 14:07:26 +0000
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2007-05-13 14:07:26 +0000
commitf2e9ebef12c6f00d650eb06f33dbdd06db0919f2 (patch)
treeffa843b8357a4c7824f6ed7edf181bf4406b1e21 /target-mips
parent388bb21af622a413cc37f6df1f3ac5a92e951760 (diff)
MMU code improvements, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2811 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-mips')
-rw-r--r--target-mips/helper.c22
-rw-r--r--target-mips/op.c2
-rw-r--r--target-mips/op_helper.c18
3 files changed, 24 insertions, 18 deletions
diff --git a/target-mips/helper.c b/target-mips/helper.c
index cb568f11a5..484834a592 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -73,19 +73,18 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot,
for (i = 0; i < env->tlb_in_use; i++) {
r4k_tlb_t *tlb = &env->mmu.r4k.tlb[i];
/* 1k pages are not supported. */
- target_ulong mask = tlb->PageMask | 0x1FFF;
+ target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
target_ulong tag = address & ~mask;
- int n;
+ target_ulong VPN = tlb->VPN & ~mask;
/* Check ASID, virtual page number & size */
- if ((tlb->G == 1 || tlb->ASID == ASID) &&
- tlb->VPN == tag) {
+ if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
/* TLB match */
- n = !!(address & mask & ~(mask >> 1));
+ int n = !!(address & mask & ~(mask >> 1));
/* Check access rights */
- if (!(n ? tlb->V1 : tlb->V0))
+ if (!(n ? tlb->V1 : tlb->V0))
return TLBRET_INVALID;
- if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
+ if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
*physical = tlb->PFN[n] | (address & (mask >> 1));
*prot = PAGE_READ;
if (n ? tlb->D1 : tlb->D0)
@@ -502,7 +501,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
target_ulong mask;
tlb = &env->mmu.r4k.tlb[idx];
- /* The qemu TLB is flushed then the ASID changes, so no need to
+ /* The qemu TLB is flushed when the ASID changes, so no need to
flush these entries again. */
if (tlb->G == 0 && tlb->ASID != ASID) {
return;
@@ -518,9 +517,9 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
}
/* 1k pages are not supported. */
- mask = tlb->PageMask | 0x1FFF;
+ mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
if (tlb->V0) {
- addr = tlb->VPN;
+ addr = tlb->VPN & ~mask;
end = addr | (mask >> 1);
while (addr < end) {
tlb_flush_page (env, addr);
@@ -528,8 +527,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
}
}
if (tlb->V1) {
- addr = tlb->VPN | ((mask >> 1) + 1);
- addr = tlb->VPN + TARGET_PAGE_SIZE;
+ addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
end = addr | mask;
while (addr < end) {
tlb_flush_page (env, addr);
diff --git a/target-mips/op.c b/target-mips/op.c
index a0611e01c1..835b02a646 100644
--- a/target-mips/op.c
+++ b/target-mips/op.c
@@ -1283,7 +1283,7 @@ void op_mtc0_context (void)
void op_mtc0_pagemask (void)
{
/* 1k pages not implemented */
- env->CP0_PageMask = T0 & 0x1FFFE000;
+ env->CP0_PageMask = T0 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
RETURN();
}
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 9d7a560001..895ca7ff8f 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -390,7 +390,7 @@ static void r4k_fill_tlb (int idx)
/* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
tlb = &env->mmu.r4k.tlb[idx];
- tlb->VPN = env->CP0_EntryHi & ~(target_ulong)0x1FFF;
+ tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
tlb->ASID = env->CP0_EntryHi & 0xFF;
tlb->PageMask = env->CP0_PageMask;
tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
@@ -426,16 +426,21 @@ void r4k_do_tlbwr (void)
void r4k_do_tlbp (void)
{
r4k_tlb_t *tlb;
+ target_ulong mask;
target_ulong tag;
+ target_ulong VPN;
uint8_t ASID;
int i;
- tag = env->CP0_EntryHi & (int32_t)0xFFFFE000;
ASID = env->CP0_EntryHi & 0xFF;
for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->mmu.r4k.tlb[i];
+ /* 1k pages are not supported. */
+ mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
+ tag = env->CP0_EntryHi & ~mask;
+ VPN = tlb->VPN & ~mask;
/* Check ASID, virtual page number & size */
- if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
+ if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
/* TLB match */
env->CP0_Index = i;
break;
@@ -445,9 +450,12 @@ void r4k_do_tlbp (void)
/* No match. Discard any shadow entries, if any of them match. */
for (i = env->nb_tlb; i < env->tlb_in_use; i++) {
tlb = &env->mmu.r4k.tlb[i];
-
+ /* 1k pages are not supported. */
+ mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
+ tag = env->CP0_EntryHi & ~mask;
+ VPN = tlb->VPN & ~mask;
/* Check ASID, virtual page number & size */
- if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
+ if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
r4k_mips_tlb_flush_extra (env, i);
break;
}