use constants for TLB handling (Thiemo Seufer)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1978 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2006-06-14 17:15:19 +00:00
parent c5d6edc3fc
commit 43057ab127
2 changed files with 36 additions and 33 deletions

View File

@ -87,7 +87,7 @@ struct CPUMIPSState {
#endif #endif
#if defined(MIPS_USES_R4K_TLB) #if defined(MIPS_USES_R4K_TLB)
tlb_t tlb[16]; tlb_t tlb[MIPS_TLB_NB];
#endif #endif
uint32_t CP0_index; uint32_t CP0_index;
uint32_t CP0_random; uint32_t CP0_random;

View File

@ -28,53 +28,56 @@
#include "cpu.h" #include "cpu.h"
#include "exec-all.h" #include "exec-all.h"
enum {
TLBRET_DIRTY = -4,
TLBRET_INVALID = -3,
TLBRET_NOMATCH = -2,
TLBRET_BADADDR = -1,
TLBRET_MATCH = 0
};
/* MIPS32 4K MMU emulation */ /* MIPS32 4K MMU emulation */
#ifdef MIPS_USES_R4K_TLB #ifdef MIPS_USES_R4K_TLB
static int map_address (CPUState *env, target_ulong *physical, int *prot, static int map_address (CPUState *env, target_ulong *physical, int *prot,
target_ulong address, int rw, int access_type) target_ulong address, int rw, int access_type)
{ {
target_ulong tag = address & (TARGET_PAGE_MASK << 1);
uint8_t ASID = env->CP0_EntryHi & 0xFF;
tlb_t *tlb; tlb_t *tlb;
target_ulong tag;
uint8_t ASID;
int i, n; int i, n;
int ret;
ret = -2;
tag = address & 0xFFFFE000;
ASID = env->CP0_EntryHi & 0xFF;
for (i = 0; i < MIPS_TLB_NB; i++) { for (i = 0; i < MIPS_TLB_NB; i++) {
tlb = &env->tlb[i]; tlb = &env->tlb[i];
/* Check ASID, virtual page number & size */ /* Check ASID, virtual page number & size */
if ((tlb->G == 1 || tlb->ASID == ASID) && if ((tlb->G == 1 || tlb->ASID == ASID) &&
tlb->VPN == tag && address < tlb->end2) { tlb->VPN == tag && address < tlb->end2) {
/* TLB match */ /* TLB match */
n = (address >> 12) & 1; n = (address >> TARGET_PAGE_BITS) & 1;
/* Check access rights */ /* Check access rights */
if (!(n ? tlb->V1 : tlb->V0)) if (!(n ? tlb->V1 : tlb->V0))
return -3; return TLBRET_INVALID;
if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
*physical = tlb->PFN[n] | (address & 0xFFF); *physical = tlb->PFN[n] | (address & ~TARGET_PAGE_MASK);
*prot = PAGE_READ; *prot = PAGE_READ;
if (n ? tlb->D1 : tlb->D0) if (n ? tlb->D1 : tlb->D0)
*prot |= PAGE_WRITE; *prot |= PAGE_WRITE;
return 0; return TLBRET_MATCH;
} }
return -4; return TLBRET_DIRTY;
} }
} }
return TLBRET_NOMATCH;
return ret;
} }
#endif #endif
int get_physical_address (CPUState *env, target_ulong *physical, int *prot, static int get_physical_address (CPUState *env, target_ulong *physical,
target_ulong address, int rw, int access_type) int *prot, target_ulong address,
int rw, int access_type)
{ {
int user_mode;
int ret;
/* User mode can only access useg */ /* User mode can only access useg */
user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM; int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
int ret = TLBRET_MATCH;
#if 0 #if 0
if (logfile) { if (logfile) {
fprintf(logfile, "user mode %d h %08x\n", fprintf(logfile, "user mode %d h %08x\n",
@ -82,8 +85,7 @@ int get_physical_address (CPUState *env, target_ulong *physical, int *prot,
} }
#endif #endif
if (user_mode && address > 0x7FFFFFFFUL) if (user_mode && address > 0x7FFFFFFFUL)
return -1; return TLBRET_BADADDR;
ret = 0;
if (address < 0x80000000UL) { if (address < 0x80000000UL) {
if (!(env->hflags & MIPS_HFLAG_ERL)) { if (!(env->hflags & MIPS_HFLAG_ERL)) {
#ifdef MIPS_USES_R4K_TLB #ifdef MIPS_USES_R4K_TLB
@ -181,7 +183,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
access_type = ACCESS_INT; access_type = ACCESS_INT;
if (env->user_mode_only) { if (env->user_mode_only) {
/* user mode only emulation */ /* user mode only emulation */
ret = -2; ret = TLBRET_NOMATCH;
goto do_fault; goto do_fault;
} }
ret = get_physical_address(env, &physical, &prot, ret = get_physical_address(env, &physical, &prot,
@ -190,14 +192,15 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n", fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
__func__, address, ret, physical, prot); __func__, address, ret, physical, prot);
} }
if (ret == 0) { if (ret == TLBRET_MATCH) {
ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot, ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
physical & TARGET_PAGE_MASK, prot,
is_user, is_softmmu); is_user, is_softmmu);
} else if (ret < 0) { } else if (ret < 0) {
do_fault: do_fault:
switch (ret) { switch (ret) {
default: default:
case -1: case TLBRET_BADADDR:
/* Reference to kernel address from user mode or supervisor mode */ /* Reference to kernel address from user mode or supervisor mode */
/* Reference to supervisor address from user mode */ /* Reference to supervisor address from user mode */
if (rw) if (rw)
@ -205,7 +208,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
else else
exception = EXCP_AdEL; exception = EXCP_AdEL;
break; break;
case -2: case TLBRET_NOMATCH:
/* No TLB match for a mapped address */ /* No TLB match for a mapped address */
if (rw) if (rw)
exception = EXCP_TLBS; exception = EXCP_TLBS;
@ -213,14 +216,14 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
exception = EXCP_TLBL; exception = EXCP_TLBL;
error_code = 1; error_code = 1;
break; break;
case -3: case TLBRET_INVALID:
/* TLB match with no valid bit */ /* TLB match with no valid bit */
if (rw) if (rw)
exception = EXCP_TLBS; exception = EXCP_TLBS;
else else
exception = EXCP_TLBL; exception = EXCP_TLBL;
break; break;
case -4: case TLBRET_DIRTY:
/* TLB match but 'D' bit is cleared */ /* TLB match but 'D' bit is cleared */
exception = EXCP_LTLBL; exception = EXCP_LTLBL;
break; break;
@ -231,7 +234,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
env->CP0_Context = (env->CP0_Context & 0xff800000) | env->CP0_Context = (env->CP0_Context & 0xff800000) |
((address >> 9) & 0x007ffff0); ((address >> 9) & 0x007ffff0);
env->CP0_EntryHi = env->CP0_EntryHi =
(env->CP0_EntryHi & 0xFF) | (address & 0xFFFFE000); (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
env->exception_index = exception; env->exception_index = exception;
env->error_code = error_code; env->error_code = error_code;
ret = 1; ret = 1;