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 | ... | ... |