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 | 273 | }; |
| 274 | 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 | 287 | typedef struct SparcTLBEntry { |
| 277 | 288 | uint64_t tag; |
| 278 | 289 | uint64_t tte; | ... | ... |
target-sparc/helper.c
| ... | ... | @@ -409,7 +409,7 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, |
| 409 | 409 | } |
| 410 | 410 | |
| 411 | 411 | // valid, context match, virtual address match? |
| 412 | - if ((tlb->tte & 0x8000000000000000ULL) && | |
| 412 | + if (TTE_IS_VALID(tlb->tte) && | |
| 413 | 413 | compare_masked(context, tlb->tag, 0x1fff) && |
| 414 | 414 | compare_masked(address, tlb->tag, mask)) |
| 415 | 415 | { |
| ... | ... | @@ -468,6 +468,7 @@ static int get_physical_address_data(CPUState *env, |
| 468 | 468 | *prot = PAGE_READ; |
| 469 | 469 | if (env->dtlb[i].tte & 0x2) |
| 470 | 470 | *prot |= PAGE_WRITE; |
| 471 | + TTE_SET_USED(env->dtlb[i].tte); | |
| 471 | 472 | return 0; |
| 472 | 473 | } |
| 473 | 474 | } |
| ... | ... | @@ -513,6 +514,7 @@ static int get_physical_address_code(CPUState *env, |
| 513 | 514 | return 1; |
| 514 | 515 | } |
| 515 | 516 | *prot = PAGE_EXEC; |
| 517 | + TTE_SET_USED(env->itlb[i].tte); | |
| 516 | 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 | 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 | 94 | target_ulong mask, size, va, offset; |
| 94 | 95 | |
| 95 | 96 | // flush page range if translation is valid |
| 96 | - if (tlb->tte & 0x8000000000000000ULL) { | |
| 97 | + if (TTE_IS_VALID(tlb->tte)) { | |
| 97 | 98 | |
| 98 | 99 | mask = 0xffffffffffffe000ULL; |
| 99 | 100 | mask <<= 3 * ((tlb->tte >> 61) & 3); |
| ... | ... | @@ -111,23 +112,22 @@ static void replace_tlb_entry(SparcTLBEntry *tlb, CPUState *env1, |
| 111 | 112 | } |
| 112 | 113 | |
| 113 | 114 | static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, |
| 114 | - CPUState *env1) | |
| 115 | + const char* strmmu, CPUState *env1) | |
| 115 | 116 | { |
| 116 | 117 | unsigned int i; |
| 117 | 118 | target_ulong mask; |
| 118 | 119 | |
| 119 | 120 | for (i = 0; i < 64; i++) { |
| 120 | - if (tlb[i].tte & 0x8000000000000000ULL) { | |
| 121 | + if (TTE_IS_VALID(tlb[i].tte)) { | |
| 121 | 122 | |
| 122 | 123 | mask = 0xffffffffffffe000ULL; |
| 123 | 124 | mask <<= 3 * ((tlb[i].tte >> 61) & 3); |
| 124 | 125 | |
| 125 | 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 | 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 | 131 | #endif |
| 132 | 132 | } |
| 133 | 133 | //return; |
| ... | ... | @@ -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 | 189 | #endif |
| 140 | 190 | |
| 141 | 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 | 2597 | return; |
| 2548 | 2598 | } |
| 2549 | 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 | 2602 | case 0x55: // I-MMU data access |
| 2586 | 2603 | { |
| 2587 | 2604 | // TODO: auto demap |
| 2588 | 2605 | |
| 2589 | 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 | 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 | 2612 | dump_mmu(env); |
| 2598 | 2613 | #endif |
| 2599 | 2614 | return; |
| 2600 | 2615 | } |
| 2601 | 2616 | case 0x57: // I-MMU demap |
| 2602 | - demap_tlb(env->itlb, val, env); | |
| 2617 | + demap_tlb(env->itlb, val, "immu", env); | |
| 2603 | 2618 | return; |
| 2604 | 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 | 2664 | return; |
| 2650 | 2665 | } |
| 2651 | 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 | 2669 | case 0x5d: // D-MMU data access |
| 2688 | 2670 | { |
| 2689 | 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 | 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 | 2677 | dump_mmu(env); |
| 2697 | 2678 | #endif |
| 2698 | 2679 | return; |
| 2699 | 2680 | } |
| 2700 | 2681 | case 0x5f: // D-MMU demap |
| 2701 | - demap_tlb(env->dtlb, val, env); | |
| 2682 | + demap_tlb(env->dtlb, val, "dmmu", env); | |
| 2702 | 2683 | return; |
| 2703 | 2684 | case 0x49: // Interrupt data receive |
| 2704 | 2685 | // XXX | ... | ... |