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
This commit is contained in:
		
							parent
							
								
									6e8e7d4c09
								
							
						
					
					
						commit
						f707726e8d
					
				@ -273,6 +273,17 @@ enum {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
#endif
 | 
					#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 {
 | 
					typedef struct SparcTLBEntry {
 | 
				
			||||||
    uint64_t tag;
 | 
					    uint64_t tag;
 | 
				
			||||||
    uint64_t tte;
 | 
					    uint64_t tte;
 | 
				
			||||||
 | 
				
			|||||||
@ -409,7 +409,7 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // valid, context match, virtual address match?
 | 
					    // valid, context match, virtual address match?
 | 
				
			||||||
    if ((tlb->tte & 0x8000000000000000ULL) &&
 | 
					    if (TTE_IS_VALID(tlb->tte) &&
 | 
				
			||||||
            compare_masked(context, tlb->tag, 0x1fff) &&
 | 
					            compare_masked(context, tlb->tag, 0x1fff) &&
 | 
				
			||||||
            compare_masked(address, tlb->tag, mask))
 | 
					            compare_masked(address, tlb->tag, mask))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -468,6 +468,7 @@ static int get_physical_address_data(CPUState *env,
 | 
				
			|||||||
            *prot = PAGE_READ;
 | 
					            *prot = PAGE_READ;
 | 
				
			||||||
            if (env->dtlb[i].tte & 0x2)
 | 
					            if (env->dtlb[i].tte & 0x2)
 | 
				
			||||||
                *prot |= PAGE_WRITE;
 | 
					                *prot |= PAGE_WRITE;
 | 
				
			||||||
 | 
					            TTE_SET_USED(env->dtlb[i].tte);
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -513,6 +514,7 @@ static int get_physical_address_code(CPUState *env,
 | 
				
			|||||||
                return 1;
 | 
					                return 1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            *prot = PAGE_EXEC;
 | 
					            *prot = PAGE_EXEC;
 | 
				
			||||||
 | 
					            TTE_SET_USED(env->itlb[i].tte);
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
					    return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void replace_tlb_entry(SparcTLBEntry *tlb, CPUState *env1,
 | 
					static void replace_tlb_entry(SparcTLBEntry *tlb,
 | 
				
			||||||
                              uint64_t tlb_tag, uint64_t tlb_tte)
 | 
					                              uint64_t tlb_tag, uint64_t tlb_tte,
 | 
				
			||||||
 | 
					                              CPUState *env1)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    target_ulong mask, size, va, offset;
 | 
					    target_ulong mask, size, va, offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // flush page range if translation is valid
 | 
					    // flush page range if translation is valid
 | 
				
			||||||
    if (tlb->tte & 0x8000000000000000ULL) {
 | 
					    if (TTE_IS_VALID(tlb->tte)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mask = 0xffffffffffffe000ULL;
 | 
					        mask = 0xffffffffffffe000ULL;
 | 
				
			||||||
        mask <<= 3 * ((tlb->tte >> 61) & 3);
 | 
					        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,
 | 
					static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
 | 
				
			||||||
                      CPUState *env1)
 | 
					                      const char* strmmu, CPUState *env1)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    unsigned int i;
 | 
					    unsigned int i;
 | 
				
			||||||
    target_ulong mask;
 | 
					    target_ulong mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < 64; i++) {
 | 
					    for (i = 0; i < 64; i++) {
 | 
				
			||||||
        if (tlb[i].tte & 0x8000000000000000ULL) {
 | 
					        if (TTE_IS_VALID(tlb[i].tte)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            mask = 0xffffffffffffe000ULL;
 | 
					            mask = 0xffffffffffffe000ULL;
 | 
				
			||||||
            mask <<= 3 * ((tlb[i].tte >> 61) & 3);
 | 
					            mask <<= 3 * ((tlb[i].tte >> 61) & 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ((demap_addr & mask) == (tlb[i].tag & mask)) {
 | 
					            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
 | 
					#ifdef DEBUG_MMU
 | 
				
			||||||
                DPRINTF_MMU("mmu demap invalidated entry [%02u]\n",
 | 
					                DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
 | 
				
			||||||
                            i);
 | 
					                dump_mmu(env1);
 | 
				
			||||||
                dump_mmu(env);
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            //return;
 | 
					            //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
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void address_mask(CPUState *env1, target_ulong *addr)
 | 
					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;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case 0x54: // I-MMU data in
 | 
					    case 0x54: // I-MMU data in
 | 
				
			||||||
        {
 | 
					        replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
 | 
				
			||||||
            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;
 | 
					        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    case 0x55: // I-MMU data access
 | 
					    case 0x55: // I-MMU data access
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // TODO: auto demap
 | 
					            // TODO: auto demap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            unsigned int i = (addr >> 3) & 0x3f;
 | 
					            unsigned int i = (addr >> 3) & 0x3f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            replace_tlb_entry(&env->itlb[i], env,
 | 
					            replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
 | 
				
			||||||
                              env->immu.tag_access, val);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef DEBUG_MMU
 | 
					#ifdef DEBUG_MMU
 | 
				
			||||||
            DPRINTF_MMU("immu data access replaced entry [%i]\n",
 | 
					            DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
 | 
				
			||||||
                        i);
 | 
					 | 
				
			||||||
            dump_mmu(env);
 | 
					            dump_mmu(env);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case 0x57: // I-MMU demap
 | 
					    case 0x57: // I-MMU demap
 | 
				
			||||||
        demap_tlb(env->itlb, val, env);
 | 
					        demap_tlb(env->itlb, val, "immu", env);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    case 0x58: // D-MMU regs
 | 
					    case 0x58: // D-MMU regs
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@ -2649,56 +2664,22 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case 0x5c: // D-MMU data in
 | 
					    case 0x5c: // D-MMU data in
 | 
				
			||||||
        {
 | 
					        replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
 | 
				
			||||||
            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;
 | 
					        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    case 0x5d: // D-MMU data access
 | 
					    case 0x5d: // D-MMU data access
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            unsigned int i = (addr >> 3) & 0x3f;
 | 
					            unsigned int i = (addr >> 3) & 0x3f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            replace_tlb_entry(&env->dtlb[i], env,
 | 
					            replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
 | 
				
			||||||
                              env->dmmu.tag_access, val);
 | 
					
 | 
				
			||||||
#ifdef DEBUG_MMU
 | 
					#ifdef DEBUG_MMU
 | 
				
			||||||
            DPRINTF_MMU("dmmu data access replaced entry [%i]\n",
 | 
					            DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
 | 
				
			||||||
                        i);
 | 
					 | 
				
			||||||
            dump_mmu(env);
 | 
					            dump_mmu(env);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    case 0x5f: // D-MMU demap
 | 
					    case 0x5f: // D-MMU demap
 | 
				
			||||||
        demap_tlb(env->dtlb, val, env);
 | 
					        demap_tlb(env->dtlb, val, "dmmu", env);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    case 0x49: // Interrupt data receive
 | 
					    case 0x49: // Interrupt data receive
 | 
				
			||||||
        // XXX
 | 
					        // XXX
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user