From f707726e8d8308d58edbcd4664e252a445cc9b8c Mon Sep 17 00:00:00 2001 From: Igor Kovalenko Date: Mon, 27 Jul 2009 01:57:39 +0400 Subject: [PATCH] sparc64 really implement itlb/dtlb automatic replacement writes - implement "used" bit in tlb translation entry - mark tlb entry used if qemu code/data translation succeeds - fold i/d mmu replacement writes code into replace_tlb_1bit_lru which adds 1bit lru replacement algorithm; previously code tried to replace first unlocked entry only - extract more bitmasks to named macros - add "immu" or "dmmu" type name to debugging output where appropriate Signed-off-by: igor.v.kovalenko@gmail.com -- Kind regards, Igor V. Kovalenko --- target-sparc/cpu.h | 11 +++ target-sparc/helper.c | 4 +- target-sparc/op_helper.c | 159 +++++++++++++++++---------------------- 3 files changed, 84 insertions(+), 90 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 98c185f001..490fd7b57f 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -273,6 +273,17 @@ enum { }; #endif +#define TTE_VALID_BIT (1ULL << 63) +#define TTE_USED_BIT (1ULL << 41) +#define TTE_LOCKED_BIT (1ULL << 6) + +#define TTE_IS_VALID(tte) ((tte) & TTE_VALID_BIT) +#define TTE_IS_USED(tte) ((tte) & TTE_USED_BIT) +#define TTE_IS_LOCKED(tte) ((tte) & TTE_LOCKED_BIT) + +#define TTE_SET_USED(tte) ((tte) |= TTE_USED_BIT) +#define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT) + typedef struct SparcTLBEntry { uint64_t tag; uint64_t tte; diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 429be3768c..70343e3052 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -409,7 +409,7 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, } // valid, context match, virtual address match? - if ((tlb->tte & 0x8000000000000000ULL) && + if (TTE_IS_VALID(tlb->tte) && compare_masked(context, tlb->tag, 0x1fff) && compare_masked(address, tlb->tag, mask)) { @@ -468,6 +468,7 @@ static int get_physical_address_data(CPUState *env, *prot = PAGE_READ; if (env->dtlb[i].tte & 0x2) *prot |= PAGE_WRITE; + TTE_SET_USED(env->dtlb[i].tte); return 0; } } @@ -513,6 +514,7 @@ static int get_physical_address_code(CPUState *env, return 1; } *prot = PAGE_EXEC; + TTE_SET_USED(env->itlb[i].tte); return 0; } } diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 5acaa0d268..9b959fe305 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -87,13 +87,14 @@ static uint64_t ultrasparc_tag_target(uint64_t tag_access_register) return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22); } -static void replace_tlb_entry(SparcTLBEntry *tlb, CPUState *env1, - uint64_t tlb_tag, uint64_t tlb_tte) +static void replace_tlb_entry(SparcTLBEntry *tlb, + uint64_t tlb_tag, uint64_t tlb_tte, + CPUState *env1) { target_ulong mask, size, va, offset; // flush page range if translation is valid - if (tlb->tte & 0x8000000000000000ULL) { + if (TTE_IS_VALID(tlb->tte)) { mask = 0xffffffffffffe000ULL; mask <<= 3 * ((tlb->tte >> 61) & 3); @@ -111,23 +112,22 @@ static void replace_tlb_entry(SparcTLBEntry *tlb, CPUState *env1, } static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, - CPUState *env1) + const char* strmmu, CPUState *env1) { unsigned int i; target_ulong mask; for (i = 0; i < 64; i++) { - if (tlb[i].tte & 0x8000000000000000ULL) { + if (TTE_IS_VALID(tlb[i].tte)) { mask = 0xffffffffffffe000ULL; mask <<= 3 * ((tlb[i].tte >> 61) & 3); if ((demap_addr & mask) == (tlb[i].tag & mask)) { - replace_tlb_entry(&tlb[i], env1, 0, 0); + replace_tlb_entry(&tlb[i], 0, 0, env1); #ifdef DEBUG_MMU - DPRINTF_MMU("mmu demap invalidated entry [%02u]\n", - i); - dump_mmu(env); + DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i); + dump_mmu(env1); #endif } //return; @@ -136,6 +136,56 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, } +static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, + uint64_t tlb_tag, uint64_t tlb_tte, + const char* strmmu, CPUState *env1) +{ + unsigned int i, replace_used; + + // Try replacing invalid entry + for (i = 0; i < 64; i++) { + if (!TTE_IS_VALID(tlb[i].tte)) { + replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); +#ifdef DEBUG_MMU + DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i); + dump_mmu(env1); +#endif + return; + } + } + + // All entries are valid, try replacing unlocked entry + + for (replace_used = 0; replace_used < 2; ++replace_used) { + + // Used entries are not replaced on first pass + + for (i = 0; i < 64; i++) { + if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) { + + replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); +#ifdef DEBUG_MMU + DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n", + strmmu, (replace_used?"used":"unused"), i); + dump_mmu(env1); +#endif + return; + } + } + + // Now reset used bit and search for unused entries again + + for (i = 0; i < 64; i++) { + TTE_SET_UNUSED(tlb[i].tte); + } + } + +#ifdef DEBUG_MMU + DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu); +#endif + // error state? +} + #endif static inline void address_mask(CPUState *env1, target_ulong *addr) @@ -2547,59 +2597,24 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) return; } case 0x54: // I-MMU data in - { - unsigned int i; - - // Try finding an invalid entry - for (i = 0; i < 64; i++) { - if ((env->itlb[i].tte & 0x8000000000000000ULL) == 0) { - replace_tlb_entry(&env->itlb[i], env, - env->immu.tag_access, val); -#ifdef DEBUG_MMU - DPRINTF_MMU("immu data map replaced invalid entry [%i]\n", - i); - dump_mmu(env); -#endif - return; - } - } - // Try finding an unlocked entry - for (i = 0; i < 64; i++) { - if ((env->itlb[i].tte & 0x40) == 0) { - replace_tlb_entry(&env->itlb[i], env, - env->immu.tag_access, val); -#ifdef DEBUG_MMU - DPRINTF_MMU("immu data map replaced unlocked entry [%i]\n", - i); - dump_mmu(env); -#endif - return; - } - } -#ifdef DEBUG_MMU - DPRINTF_MMU("immu data map failed: no entries available\n"); -#endif - // error state? - return; - } + replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env); + return; case 0x55: // I-MMU data access { // TODO: auto demap unsigned int i = (addr >> 3) & 0x3f; - replace_tlb_entry(&env->itlb[i], env, - env->immu.tag_access, val); + replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env); #ifdef DEBUG_MMU - DPRINTF_MMU("immu data access replaced entry [%i]\n", - i); + DPRINTF_MMU("immu data access replaced entry [%i]\n", i); dump_mmu(env); #endif return; } case 0x57: // I-MMU demap - demap_tlb(env->itlb, val, env); + demap_tlb(env->itlb, val, "immu", env); return; case 0x58: // D-MMU regs { @@ -2649,56 +2664,22 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) return; } case 0x5c: // D-MMU data in - { - unsigned int i; - - // Try finding an invalid entry - for (i = 0; i < 64; i++) { - if ((env->dtlb[i].tte & 0x8000000000000000ULL) == 0) { - replace_tlb_entry(&env->dtlb[i], env, - env->dmmu.tag_access, val); -#ifdef DEBUG_MMU - DPRINTF_MMU("dmmu data map replaced invalid entry [%i]\n", - i); - dump_mmu(env); -#endif - return; - } - } - // Try finding an unlocked entry - for (i = 0; i < 64; i++) { - if ((env->dtlb[i].tte & 0x40) == 0) { - replace_tlb_entry(&env->dtlb[i], env, - env->dmmu.tag_access, val); -#ifdef DEBUG_MMU - DPRINTF_MMU("dmmu data map replaced unlocked entry [%i]\n", - i); - dump_mmu(env); -#endif - return; - } - } -#ifdef DEBUG_MMU - DPRINTF_MMU("dmmu data map failed: no entries available\n"); -#endif - // error state? - return; - } + replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env); + return; case 0x5d: // D-MMU data access { unsigned int i = (addr >> 3) & 0x3f; - replace_tlb_entry(&env->dtlb[i], env, - env->dmmu.tag_access, val); + replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env); + #ifdef DEBUG_MMU - DPRINTF_MMU("dmmu data access replaced entry [%i]\n", - i); + DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i); dump_mmu(env); #endif return; } case 0x5f: // D-MMU demap - demap_tlb(env->dtlb, val, env); + demap_tlb(env->dtlb, val, "dmmu", env); return; case 0x49: // Interrupt data receive // XXX