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 |