Commit f707726e8d8308d58edbcd4664e252a445cc9b8c
Committed by
Blue Swirl
1 parent
6e8e7d4c
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
Showing
3 changed files
with
84 additions
and
90 deletions
target-sparc/cpu.h
| @@ -273,6 +273,17 @@ enum { | @@ -273,6 +273,17 @@ enum { | ||
| 273 | }; | 273 | }; |
| 274 | #endif | 274 | #endif |
| 275 | 275 | ||
| 276 | +#define TTE_VALID_BIT (1ULL << 63) | ||
| 277 | +#define TTE_USED_BIT (1ULL << 41) | ||
| 278 | +#define TTE_LOCKED_BIT (1ULL << 6) | ||
| 279 | + | ||
| 280 | +#define TTE_IS_VALID(tte) ((tte) & TTE_VALID_BIT) | ||
| 281 | +#define TTE_IS_USED(tte) ((tte) & TTE_USED_BIT) | ||
| 282 | +#define TTE_IS_LOCKED(tte) ((tte) & TTE_LOCKED_BIT) | ||
| 283 | + | ||
| 284 | +#define TTE_SET_USED(tte) ((tte) |= TTE_USED_BIT) | ||
| 285 | +#define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT) | ||
| 286 | + | ||
| 276 | typedef struct SparcTLBEntry { | 287 | typedef struct SparcTLBEntry { |
| 277 | uint64_t tag; | 288 | uint64_t tag; |
| 278 | uint64_t tte; | 289 | uint64_t tte; |
target-sparc/helper.c
| @@ -409,7 +409,7 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, | @@ -409,7 +409,7 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, | ||
| 409 | } | 409 | } |
| 410 | 410 | ||
| 411 | // valid, context match, virtual address match? | 411 | // valid, context match, virtual address match? |
| 412 | - if ((tlb->tte & 0x8000000000000000ULL) && | 412 | + if (TTE_IS_VALID(tlb->tte) && |
| 413 | compare_masked(context, tlb->tag, 0x1fff) && | 413 | compare_masked(context, tlb->tag, 0x1fff) && |
| 414 | compare_masked(address, tlb->tag, mask)) | 414 | compare_masked(address, tlb->tag, mask)) |
| 415 | { | 415 | { |
| @@ -468,6 +468,7 @@ static int get_physical_address_data(CPUState *env, | @@ -468,6 +468,7 @@ static int get_physical_address_data(CPUState *env, | ||
| 468 | *prot = PAGE_READ; | 468 | *prot = PAGE_READ; |
| 469 | if (env->dtlb[i].tte & 0x2) | 469 | if (env->dtlb[i].tte & 0x2) |
| 470 | *prot |= PAGE_WRITE; | 470 | *prot |= PAGE_WRITE; |
| 471 | + TTE_SET_USED(env->dtlb[i].tte); | ||
| 471 | return 0; | 472 | return 0; |
| 472 | } | 473 | } |
| 473 | } | 474 | } |
| @@ -513,6 +514,7 @@ static int get_physical_address_code(CPUState *env, | @@ -513,6 +514,7 @@ static int get_physical_address_code(CPUState *env, | ||
| 513 | return 1; | 514 | return 1; |
| 514 | } | 515 | } |
| 515 | *prot = PAGE_EXEC; | 516 | *prot = PAGE_EXEC; |
| 517 | + TTE_SET_USED(env->itlb[i].tte); | ||
| 516 | return 0; | 518 | return 0; |
| 517 | } | 519 | } |
| 518 | } | 520 | } |
target-sparc/op_helper.c
| @@ -87,13 +87,14 @@ static uint64_t ultrasparc_tag_target(uint64_t tag_access_register) | @@ -87,13 +87,14 @@ static uint64_t ultrasparc_tag_target(uint64_t tag_access_register) | ||
| 87 | return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22); | 87 | return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | -static void replace_tlb_entry(SparcTLBEntry *tlb, CPUState *env1, | ||
| 91 | - uint64_t tlb_tag, uint64_t tlb_tte) | 90 | +static void replace_tlb_entry(SparcTLBEntry *tlb, |
| 91 | + uint64_t tlb_tag, uint64_t tlb_tte, | ||
| 92 | + CPUState *env1) | ||
| 92 | { | 93 | { |
| 93 | target_ulong mask, size, va, offset; | 94 | target_ulong mask, size, va, offset; |
| 94 | 95 | ||
| 95 | // flush page range if translation is valid | 96 | // flush page range if translation is valid |
| 96 | - if (tlb->tte & 0x8000000000000000ULL) { | 97 | + if (TTE_IS_VALID(tlb->tte)) { |
| 97 | 98 | ||
| 98 | mask = 0xffffffffffffe000ULL; | 99 | mask = 0xffffffffffffe000ULL; |
| 99 | mask <<= 3 * ((tlb->tte >> 61) & 3); | 100 | mask <<= 3 * ((tlb->tte >> 61) & 3); |
| @@ -111,23 +112,22 @@ static void replace_tlb_entry(SparcTLBEntry *tlb, CPUState *env1, | @@ -111,23 +112,22 @@ static void replace_tlb_entry(SparcTLBEntry *tlb, CPUState *env1, | ||
| 111 | } | 112 | } |
| 112 | 113 | ||
| 113 | static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, | 114 | static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, |
| 114 | - CPUState *env1) | 115 | + const char* strmmu, CPUState *env1) |
| 115 | { | 116 | { |
| 116 | unsigned int i; | 117 | unsigned int i; |
| 117 | target_ulong mask; | 118 | target_ulong mask; |
| 118 | 119 | ||
| 119 | for (i = 0; i < 64; i++) { | 120 | for (i = 0; i < 64; i++) { |
| 120 | - if (tlb[i].tte & 0x8000000000000000ULL) { | 121 | + if (TTE_IS_VALID(tlb[i].tte)) { |
| 121 | 122 | ||
| 122 | mask = 0xffffffffffffe000ULL; | 123 | mask = 0xffffffffffffe000ULL; |
| 123 | mask <<= 3 * ((tlb[i].tte >> 61) & 3); | 124 | mask <<= 3 * ((tlb[i].tte >> 61) & 3); |
| 124 | 125 | ||
| 125 | if ((demap_addr & mask) == (tlb[i].tag & mask)) { | 126 | if ((demap_addr & mask) == (tlb[i].tag & mask)) { |
| 126 | - replace_tlb_entry(&tlb[i], env1, 0, 0); | 127 | + replace_tlb_entry(&tlb[i], 0, 0, env1); |
| 127 | #ifdef DEBUG_MMU | 128 | #ifdef DEBUG_MMU |
| 128 | - DPRINTF_MMU("mmu demap invalidated entry [%02u]\n", | ||
| 129 | - i); | ||
| 130 | - dump_mmu(env); | 129 | + DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i); |
| 130 | + dump_mmu(env1); | ||
| 131 | #endif | 131 | #endif |
| 132 | } | 132 | } |
| 133 | //return; | 133 | //return; |
| @@ -136,6 +136,56 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, | @@ -136,6 +136,56 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, | ||
| 136 | 136 | ||
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | +static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, | ||
| 140 | + uint64_t tlb_tag, uint64_t tlb_tte, | ||
| 141 | + const char* strmmu, CPUState *env1) | ||
| 142 | +{ | ||
| 143 | + unsigned int i, replace_used; | ||
| 144 | + | ||
| 145 | + // Try replacing invalid entry | ||
| 146 | + for (i = 0; i < 64; i++) { | ||
| 147 | + if (!TTE_IS_VALID(tlb[i].tte)) { | ||
| 148 | + replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); | ||
| 149 | +#ifdef DEBUG_MMU | ||
| 150 | + DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i); | ||
| 151 | + dump_mmu(env1); | ||
| 152 | +#endif | ||
| 153 | + return; | ||
| 154 | + } | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + // All entries are valid, try replacing unlocked entry | ||
| 158 | + | ||
| 159 | + for (replace_used = 0; replace_used < 2; ++replace_used) { | ||
| 160 | + | ||
| 161 | + // Used entries are not replaced on first pass | ||
| 162 | + | ||
| 163 | + for (i = 0; i < 64; i++) { | ||
| 164 | + if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) { | ||
| 165 | + | ||
| 166 | + replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); | ||
| 167 | +#ifdef DEBUG_MMU | ||
| 168 | + DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n", | ||
| 169 | + strmmu, (replace_used?"used":"unused"), i); | ||
| 170 | + dump_mmu(env1); | ||
| 171 | +#endif | ||
| 172 | + return; | ||
| 173 | + } | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + // Now reset used bit and search for unused entries again | ||
| 177 | + | ||
| 178 | + for (i = 0; i < 64; i++) { | ||
| 179 | + TTE_SET_UNUSED(tlb[i].tte); | ||
| 180 | + } | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | +#ifdef DEBUG_MMU | ||
| 184 | + DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu); | ||
| 185 | +#endif | ||
| 186 | + // error state? | ||
| 187 | +} | ||
| 188 | + | ||
| 139 | #endif | 189 | #endif |
| 140 | 190 | ||
| 141 | static inline void address_mask(CPUState *env1, target_ulong *addr) | 191 | 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) | @@ -2547,59 +2597,24 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) | ||
| 2547 | return; | 2597 | return; |
| 2548 | } | 2598 | } |
| 2549 | case 0x54: // I-MMU data in | 2599 | case 0x54: // I-MMU data in |
| 2550 | - { | ||
| 2551 | - unsigned int i; | ||
| 2552 | - | ||
| 2553 | - // Try finding an invalid entry | ||
| 2554 | - for (i = 0; i < 64; i++) { | ||
| 2555 | - if ((env->itlb[i].tte & 0x8000000000000000ULL) == 0) { | ||
| 2556 | - replace_tlb_entry(&env->itlb[i], env, | ||
| 2557 | - env->immu.tag_access, val); | ||
| 2558 | -#ifdef DEBUG_MMU | ||
| 2559 | - DPRINTF_MMU("immu data map replaced invalid entry [%i]\n", | ||
| 2560 | - i); | ||
| 2561 | - dump_mmu(env); | ||
| 2562 | -#endif | ||
| 2563 | - return; | ||
| 2564 | - } | ||
| 2565 | - } | ||
| 2566 | - // Try finding an unlocked entry | ||
| 2567 | - for (i = 0; i < 64; i++) { | ||
| 2568 | - if ((env->itlb[i].tte & 0x40) == 0) { | ||
| 2569 | - replace_tlb_entry(&env->itlb[i], env, | ||
| 2570 | - env->immu.tag_access, val); | ||
| 2571 | -#ifdef DEBUG_MMU | ||
| 2572 | - DPRINTF_MMU("immu data map replaced unlocked entry [%i]\n", | ||
| 2573 | - i); | ||
| 2574 | - dump_mmu(env); | ||
| 2575 | -#endif | ||
| 2576 | - return; | ||
| 2577 | - } | ||
| 2578 | - } | ||
| 2579 | -#ifdef DEBUG_MMU | ||
| 2580 | - DPRINTF_MMU("immu data map failed: no entries available\n"); | ||
| 2581 | -#endif | ||
| 2582 | - // error state? | ||
| 2583 | - return; | ||
| 2584 | - } | 2600 | + replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env); |
| 2601 | + return; | ||
| 2585 | case 0x55: // I-MMU data access | 2602 | case 0x55: // I-MMU data access |
| 2586 | { | 2603 | { |
| 2587 | // TODO: auto demap | 2604 | // TODO: auto demap |
| 2588 | 2605 | ||
| 2589 | unsigned int i = (addr >> 3) & 0x3f; | 2606 | unsigned int i = (addr >> 3) & 0x3f; |
| 2590 | 2607 | ||
| 2591 | - replace_tlb_entry(&env->itlb[i], env, | ||
| 2592 | - env->immu.tag_access, val); | 2608 | + replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env); |
| 2593 | 2609 | ||
| 2594 | #ifdef DEBUG_MMU | 2610 | #ifdef DEBUG_MMU |
| 2595 | - DPRINTF_MMU("immu data access replaced entry [%i]\n", | ||
| 2596 | - i); | 2611 | + DPRINTF_MMU("immu data access replaced entry [%i]\n", i); |
| 2597 | dump_mmu(env); | 2612 | dump_mmu(env); |
| 2598 | #endif | 2613 | #endif |
| 2599 | return; | 2614 | return; |
| 2600 | } | 2615 | } |
| 2601 | case 0x57: // I-MMU demap | 2616 | case 0x57: // I-MMU demap |
| 2602 | - demap_tlb(env->itlb, val, env); | 2617 | + demap_tlb(env->itlb, val, "immu", env); |
| 2603 | return; | 2618 | return; |
| 2604 | case 0x58: // D-MMU regs | 2619 | case 0x58: // D-MMU regs |
| 2605 | { | 2620 | { |
| @@ -2649,56 +2664,22 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) | @@ -2649,56 +2664,22 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) | ||
| 2649 | return; | 2664 | return; |
| 2650 | } | 2665 | } |
| 2651 | case 0x5c: // D-MMU data in | 2666 | case 0x5c: // D-MMU data in |
| 2652 | - { | ||
| 2653 | - unsigned int i; | ||
| 2654 | - | ||
| 2655 | - // Try finding an invalid entry | ||
| 2656 | - for (i = 0; i < 64; i++) { | ||
| 2657 | - if ((env->dtlb[i].tte & 0x8000000000000000ULL) == 0) { | ||
| 2658 | - replace_tlb_entry(&env->dtlb[i], env, | ||
| 2659 | - env->dmmu.tag_access, val); | ||
| 2660 | -#ifdef DEBUG_MMU | ||
| 2661 | - DPRINTF_MMU("dmmu data map replaced invalid entry [%i]\n", | ||
| 2662 | - i); | ||
| 2663 | - dump_mmu(env); | ||
| 2664 | -#endif | ||
| 2665 | - return; | ||
| 2666 | - } | ||
| 2667 | - } | ||
| 2668 | - // Try finding an unlocked entry | ||
| 2669 | - for (i = 0; i < 64; i++) { | ||
| 2670 | - if ((env->dtlb[i].tte & 0x40) == 0) { | ||
| 2671 | - replace_tlb_entry(&env->dtlb[i], env, | ||
| 2672 | - env->dmmu.tag_access, val); | ||
| 2673 | -#ifdef DEBUG_MMU | ||
| 2674 | - DPRINTF_MMU("dmmu data map replaced unlocked entry [%i]\n", | ||
| 2675 | - i); | ||
| 2676 | - dump_mmu(env); | ||
| 2677 | -#endif | ||
| 2678 | - return; | ||
| 2679 | - } | ||
| 2680 | - } | ||
| 2681 | -#ifdef DEBUG_MMU | ||
| 2682 | - DPRINTF_MMU("dmmu data map failed: no entries available\n"); | ||
| 2683 | -#endif | ||
| 2684 | - // error state? | ||
| 2685 | - return; | ||
| 2686 | - } | 2667 | + replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env); |
| 2668 | + return; | ||
| 2687 | case 0x5d: // D-MMU data access | 2669 | case 0x5d: // D-MMU data access |
| 2688 | { | 2670 | { |
| 2689 | unsigned int i = (addr >> 3) & 0x3f; | 2671 | unsigned int i = (addr >> 3) & 0x3f; |
| 2690 | 2672 | ||
| 2691 | - replace_tlb_entry(&env->dtlb[i], env, | ||
| 2692 | - env->dmmu.tag_access, val); | 2673 | + replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env); |
| 2674 | + | ||
| 2693 | #ifdef DEBUG_MMU | 2675 | #ifdef DEBUG_MMU |
| 2694 | - DPRINTF_MMU("dmmu data access replaced entry [%i]\n", | ||
| 2695 | - i); | 2676 | + DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i); |
| 2696 | dump_mmu(env); | 2677 | dump_mmu(env); |
| 2697 | #endif | 2678 | #endif |
| 2698 | return; | 2679 | return; |
| 2699 | } | 2680 | } |
| 2700 | case 0x5f: // D-MMU demap | 2681 | case 0x5f: // D-MMU demap |
| 2701 | - demap_tlb(env->dtlb, val, env); | 2682 | + demap_tlb(env->dtlb, val, "dmmu", env); |
| 2702 | return; | 2683 | return; |
| 2703 | case 0x49: // Interrupt data receive | 2684 | case 0x49: // Interrupt data receive |
| 2704 | // XXX | 2685 | // XXX |