Commit 29929e349009731a2fb22a983da75f67b6e78362
1 parent
f707cfba
MIPS TLB style selection at runtime, by Herve Poussineau.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2809 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
8 changed files
with
149 additions
and
114 deletions
target-mips/cpu.h
| @@ -33,9 +33,8 @@ union fpr_t { | @@ -33,9 +33,8 @@ union fpr_t { | ||
| 33 | # define FP_ENDIAN_IDX 0 | 33 | # define FP_ENDIAN_IDX 0 |
| 34 | #endif | 34 | #endif |
| 35 | 35 | ||
| 36 | -#if defined(MIPS_USES_R4K_TLB) | ||
| 37 | -typedef struct tlb_t tlb_t; | ||
| 38 | -struct tlb_t { | 36 | +typedef struct r4k_tlb_t r4k_tlb_t; |
| 37 | +struct r4k_tlb_t { | ||
| 39 | target_ulong VPN; | 38 | target_ulong VPN; |
| 40 | uint32_t PageMask; | 39 | uint32_t PageMask; |
| 41 | uint_fast8_t ASID; | 40 | uint_fast8_t ASID; |
| @@ -48,7 +47,6 @@ struct tlb_t { | @@ -48,7 +47,6 @@ struct tlb_t { | ||
| 48 | uint_fast16_t D1:1; | 47 | uint_fast16_t D1:1; |
| 49 | target_ulong PFN[2]; | 48 | target_ulong PFN[2]; |
| 50 | }; | 49 | }; |
| 51 | -#endif | ||
| 52 | 50 | ||
| 53 | typedef struct CPUMIPSState CPUMIPSState; | 51 | typedef struct CPUMIPSState CPUMIPSState; |
| 54 | struct CPUMIPSState { | 52 | struct CPUMIPSState { |
| @@ -100,11 +98,19 @@ struct CPUMIPSState { | @@ -100,11 +98,19 @@ struct CPUMIPSState { | ||
| 100 | #define FP_INVALID 16 | 98 | #define FP_INVALID 16 |
| 101 | #define FP_UNIMPLEMENTED 32 | 99 | #define FP_UNIMPLEMENTED 32 |
| 102 | 100 | ||
| 103 | -#if defined(MIPS_USES_R4K_TLB) | ||
| 104 | - tlb_t tlb[MIPS_TLB_MAX]; | ||
| 105 | - uint32_t tlb_in_use; | ||
| 106 | uint32_t nb_tlb; | 101 | uint32_t nb_tlb; |
| 107 | -#endif | 102 | + uint32_t tlb_in_use; |
| 103 | + int (*map_address) (CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type); | ||
| 104 | + void (*do_tlbwi) (void); | ||
| 105 | + void (*do_tlbwr) (void); | ||
| 106 | + void (*do_tlbp) (void); | ||
| 107 | + void (*do_tlbr) (void); | ||
| 108 | + union { | ||
| 109 | + struct { | ||
| 110 | + r4k_tlb_t tlb[MIPS_TLB_MAX]; | ||
| 111 | + } r4k; | ||
| 112 | + } mmu; | ||
| 113 | + | ||
| 108 | int32_t CP0_Index; | 114 | int32_t CP0_Index; |
| 109 | int32_t CP0_Random; | 115 | int32_t CP0_Random; |
| 110 | target_ulong CP0_EntryLo0; | 116 | target_ulong CP0_EntryLo0; |
| @@ -289,6 +295,16 @@ struct CPUMIPSState { | @@ -289,6 +295,16 @@ struct CPUMIPSState { | ||
| 289 | struct QEMUTimer *timer; /* Internal timer */ | 295 | struct QEMUTimer *timer; /* Internal timer */ |
| 290 | }; | 296 | }; |
| 291 | 297 | ||
| 298 | +int no_mmu_map_address (CPUMIPSState *env, target_ulong *physical, int *prot, | ||
| 299 | + target_ulong address, int rw, int access_type); | ||
| 300 | +int fixed_mmu_map_address (CPUMIPSState *env, target_ulong *physical, int *prot, | ||
| 301 | + target_ulong address, int rw, int access_type); | ||
| 302 | +int r4k_map_address (CPUMIPSState *env, target_ulong *physical, int *prot, | ||
| 303 | + target_ulong address, int rw, int access_type); | ||
| 304 | +void r4k_do_tlbwi (void); | ||
| 305 | +void r4k_do_tlbwr (void); | ||
| 306 | +void r4k_do_tlbp (void); | ||
| 307 | +void r4k_do_tlbr (void); | ||
| 292 | typedef struct mips_def_t mips_def_t; | 308 | typedef struct mips_def_t mips_def_t; |
| 293 | int mips_find_by_name (const unsigned char *name, mips_def_t **def); | 309 | int mips_find_by_name (const unsigned char *name, mips_def_t **def); |
| 294 | void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); | 310 | void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); |
target-mips/exec.h
| @@ -105,10 +105,6 @@ void do_mfc0_count(void); | @@ -105,10 +105,6 @@ void do_mfc0_count(void); | ||
| 105 | void do_mtc0_entryhi(uint32_t in); | 105 | void do_mtc0_entryhi(uint32_t in); |
| 106 | void do_mtc0_status_debug(uint32_t old, uint32_t val); | 106 | void do_mtc0_status_debug(uint32_t old, uint32_t val); |
| 107 | void do_mtc0_status_irqraise_debug(void); | 107 | void do_mtc0_status_irqraise_debug(void); |
| 108 | -void do_tlbwi (void); | ||
| 109 | -void do_tlbwr (void); | ||
| 110 | -void do_tlbp (void); | ||
| 111 | -void do_tlbr (void); | ||
| 112 | void dump_fpu(CPUState *env); | 108 | void dump_fpu(CPUState *env); |
| 113 | void fpu_dump_state(CPUState *env, FILE *f, | 109 | void fpu_dump_state(CPUState *env, FILE *f, |
| 114 | int (*fpu_fprintf)(FILE *f, const char *fmt, ...), | 110 | int (*fpu_fprintf)(FILE *f, const char *fmt, ...), |
| @@ -151,7 +147,7 @@ void dump_sc (void); | @@ -151,7 +147,7 @@ void dump_sc (void); | ||
| 151 | int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | 147 | int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
| 152 | int is_user, int is_softmmu); | 148 | int is_user, int is_softmmu); |
| 153 | void do_interrupt (CPUState *env); | 149 | void do_interrupt (CPUState *env); |
| 154 | -void invalidate_tlb (CPUState *env, int idx, int use_extra); | 150 | +void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra); |
| 155 | 151 | ||
| 156 | void cpu_loop_exit(void); | 152 | void cpu_loop_exit(void); |
| 157 | void do_raise_exception_err (uint32_t exception, int error_code); | 153 | void do_raise_exception_err (uint32_t exception, int error_code); |
target-mips/helper.c
| @@ -36,16 +36,42 @@ enum { | @@ -36,16 +36,42 @@ enum { | ||
| 36 | TLBRET_MATCH = 0 | 36 | TLBRET_MATCH = 0 |
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | -/* MIPS32 4K MMU emulation */ | ||
| 40 | -#ifdef MIPS_USES_R4K_TLB | ||
| 41 | -static int map_address (CPUState *env, target_ulong *physical, int *prot, | 39 | +/* no MMU emulation */ |
| 40 | +int no_mmu_map_address (CPUState *env, target_ulong *physical, int *prot, | ||
| 42 | target_ulong address, int rw, int access_type) | 41 | target_ulong address, int rw, int access_type) |
| 43 | { | 42 | { |
| 43 | + *physical = address; | ||
| 44 | + *prot = PAGE_READ | PAGE_WRITE; | ||
| 45 | + return TLBRET_MATCH; | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +/* fixed mapping MMU emulation */ | ||
| 49 | +int fixed_mmu_map_address (CPUState *env, target_ulong *physical, int *prot, | ||
| 50 | + target_ulong address, int rw, int access_type) | ||
| 51 | +{ | ||
| 52 | + if (address <= (int32_t)0x7FFFFFFFUL) { | ||
| 53 | + if (!(env->CP0_Status & (1 << CP0St_ERL))) | ||
| 54 | + *physical = address + 0x40000000UL; | ||
| 55 | + else | ||
| 56 | + *physical = address; | ||
| 57 | + } else if (address <= (int32_t)0xBFFFFFFFUL) | ||
| 58 | + *physical = address & 0x1FFFFFFF; | ||
| 59 | + else | ||
| 60 | + *physical = address; | ||
| 61 | + | ||
| 62 | + *prot = PAGE_READ | PAGE_WRITE; | ||
| 63 | + return TLBRET_MATCH; | ||
| 64 | +} | ||
| 65 | + | ||
| 66 | +/* MIPS32/MIPS64 R4000-style MMU emulation */ | ||
| 67 | +int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, | ||
| 68 | + target_ulong address, int rw, int access_type) | ||
| 69 | +{ | ||
| 44 | uint8_t ASID = env->CP0_EntryHi & 0xFF; | 70 | uint8_t ASID = env->CP0_EntryHi & 0xFF; |
| 45 | int i; | 71 | int i; |
| 46 | 72 | ||
| 47 | for (i = 0; i < env->tlb_in_use; i++) { | 73 | for (i = 0; i < env->tlb_in_use; i++) { |
| 48 | - tlb_t *tlb = &env->tlb[i]; | 74 | + r4k_tlb_t *tlb = &env->mmu.r4k.tlb[i]; |
| 49 | /* 1k pages are not supported. */ | 75 | /* 1k pages are not supported. */ |
| 50 | target_ulong mask = tlb->PageMask | 0x1FFF; | 76 | target_ulong mask = tlb->PageMask | 0x1FFF; |
| 51 | target_ulong tag = address & ~mask; | 77 | target_ulong tag = address & ~mask; |
| @@ -71,7 +97,6 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, | @@ -71,7 +97,6 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, | ||
| 71 | } | 97 | } |
| 72 | return TLBRET_NOMATCH; | 98 | return TLBRET_NOMATCH; |
| 73 | } | 99 | } |
| 74 | -#endif | ||
| 75 | 100 | ||
| 76 | static int get_physical_address (CPUState *env, target_ulong *physical, | 101 | static int get_physical_address (CPUState *env, target_ulong *physical, |
| 77 | int *prot, target_ulong address, | 102 | int *prot, target_ulong address, |
| @@ -104,14 +129,9 @@ static int get_physical_address (CPUState *env, target_ulong *physical, | @@ -104,14 +129,9 @@ static int get_physical_address (CPUState *env, target_ulong *physical, | ||
| 104 | if (address <= (int32_t)0x7FFFFFFFUL) { | 129 | if (address <= (int32_t)0x7FFFFFFFUL) { |
| 105 | /* useg */ | 130 | /* useg */ |
| 106 | if (!(env->CP0_Status & (1 << CP0St_ERL) && user_mode)) { | 131 | if (!(env->CP0_Status & (1 << CP0St_ERL) && user_mode)) { |
| 107 | -#ifdef MIPS_USES_R4K_TLB | ||
| 108 | - ret = map_address(env, physical, prot, address, rw, access_type); | ||
| 109 | -#else | ||
| 110 | - *physical = address + 0x40000000UL; | ||
| 111 | - *prot = PAGE_READ | PAGE_WRITE; | ||
| 112 | -#endif | 132 | + ret = env->map_address(env, physical, prot, address, rw, access_type); |
| 113 | } else { | 133 | } else { |
| 114 | - *physical = address; | 134 | + *physical = address & 0xFFFFFFFF; |
| 115 | *prot = PAGE_READ | PAGE_WRITE; | 135 | *prot = PAGE_READ | PAGE_WRITE; |
| 116 | } | 136 | } |
| 117 | #ifdef TARGET_MIPS64 | 137 | #ifdef TARGET_MIPS64 |
| @@ -123,14 +143,14 @@ static int get_physical_address (CPUState *env, target_ulong *physical, | @@ -123,14 +143,14 @@ static int get_physical_address (CPUState *env, target_ulong *physical, | ||
| 123 | } else if (address < 0x3FFFFFFFFFFFFFFFULL) { | 143 | } else if (address < 0x3FFFFFFFFFFFFFFFULL) { |
| 124 | /* xuseg */ | 144 | /* xuseg */ |
| 125 | if (UX && address < 0x000000FFFFFFFFFFULL) { | 145 | if (UX && address < 0x000000FFFFFFFFFFULL) { |
| 126 | - ret = map_address(env, physical, prot, address, rw, access_type); | 146 | + ret = env->map_address(env, physical, prot, address, rw, access_type); |
| 127 | } else { | 147 | } else { |
| 128 | ret = TLBRET_BADADDR; | 148 | ret = TLBRET_BADADDR; |
| 129 | } | 149 | } |
| 130 | } else if (address < 0x7FFFFFFFFFFFFFFFULL) { | 150 | } else if (address < 0x7FFFFFFFFFFFFFFFULL) { |
| 131 | /* xsseg */ | 151 | /* xsseg */ |
| 132 | if (SX && address < 0x400000FFFFFFFFFFULL) { | 152 | if (SX && address < 0x400000FFFFFFFFFFULL) { |
| 133 | - ret = map_address(env, physical, prot, address, rw, access_type); | 153 | + ret = env->map_address(env, physical, prot, address, rw, access_type); |
| 134 | } else { | 154 | } else { |
| 135 | ret = TLBRET_BADADDR; | 155 | ret = TLBRET_BADADDR; |
| 136 | } | 156 | } |
| @@ -148,7 +168,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, | @@ -148,7 +168,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, | ||
| 148 | /* xkseg */ | 168 | /* xkseg */ |
| 149 | /* XXX: check supervisor mode */ | 169 | /* XXX: check supervisor mode */ |
| 150 | if (KX && address < 0xC00000FF7FFFFFFFULL) { | 170 | if (KX && address < 0xC00000FF7FFFFFFFULL) { |
| 151 | - ret = map_address(env, physical, prot, address, rw, access_type); | 171 | + ret = env->map_address(env, physical, prot, address, rw, access_type); |
| 152 | } else { | 172 | } else { |
| 153 | ret = TLBRET_BADADDR; | 173 | ret = TLBRET_BADADDR; |
| 154 | } | 174 | } |
| @@ -165,22 +185,12 @@ static int get_physical_address (CPUState *env, target_ulong *physical, | @@ -165,22 +185,12 @@ static int get_physical_address (CPUState *env, target_ulong *physical, | ||
| 165 | *prot = PAGE_READ | PAGE_WRITE; | 185 | *prot = PAGE_READ | PAGE_WRITE; |
| 166 | } else if (address < (int32_t)0xE0000000UL) { | 186 | } else if (address < (int32_t)0xE0000000UL) { |
| 167 | /* kseg2 */ | 187 | /* kseg2 */ |
| 168 | -#ifdef MIPS_USES_R4K_TLB | ||
| 169 | - ret = map_address(env, physical, prot, address, rw, access_type); | ||
| 170 | -#else | ||
| 171 | - *physical = address & 0xFFFFFFFF; | ||
| 172 | - *prot = PAGE_READ | PAGE_WRITE; | ||
| 173 | -#endif | 188 | + ret = env->map_address(env, physical, prot, address, rw, access_type); |
| 174 | } else { | 189 | } else { |
| 175 | /* kseg3 */ | 190 | /* kseg3 */ |
| 176 | /* XXX: check supervisor mode */ | 191 | /* XXX: check supervisor mode */ |
| 177 | /* XXX: debug segment is not emulated */ | 192 | /* XXX: debug segment is not emulated */ |
| 178 | -#ifdef MIPS_USES_R4K_TLB | ||
| 179 | - ret = map_address(env, physical, prot, address, rw, access_type); | ||
| 180 | -#else | ||
| 181 | - *physical = address & 0xFFFFFFFF; | ||
| 182 | - *prot = PAGE_READ | PAGE_WRITE; | ||
| 183 | -#endif | 193 | + ret = env->map_address(env, physical, prot, address, rw, access_type); |
| 184 | } | 194 | } |
| 185 | #if 0 | 195 | #if 0 |
| 186 | if (logfile) { | 196 | if (logfile) { |
| @@ -483,15 +493,15 @@ void do_interrupt (CPUState *env) | @@ -483,15 +493,15 @@ void do_interrupt (CPUState *env) | ||
| 483 | } | 493 | } |
| 484 | #endif /* !defined(CONFIG_USER_ONLY) */ | 494 | #endif /* !defined(CONFIG_USER_ONLY) */ |
| 485 | 495 | ||
| 486 | -void invalidate_tlb (CPUState *env, int idx, int use_extra) | 496 | +void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) |
| 487 | { | 497 | { |
| 488 | - tlb_t *tlb; | 498 | + r4k_tlb_t *tlb; |
| 489 | target_ulong addr; | 499 | target_ulong addr; |
| 490 | target_ulong end; | 500 | target_ulong end; |
| 491 | uint8_t ASID = env->CP0_EntryHi & 0xFF; | 501 | uint8_t ASID = env->CP0_EntryHi & 0xFF; |
| 492 | target_ulong mask; | 502 | target_ulong mask; |
| 493 | 503 | ||
| 494 | - tlb = &env->tlb[idx]; | 504 | + tlb = &env->mmu.r4k.tlb[idx]; |
| 495 | /* The qemu TLB is flushed then the ASID changes, so no need to | 505 | /* The qemu TLB is flushed then the ASID changes, so no need to |
| 496 | flush these entries again. */ | 506 | flush these entries again. */ |
| 497 | if (tlb->G == 0 && tlb->ASID != ASID) { | 507 | if (tlb->G == 0 && tlb->ASID != ASID) { |
| @@ -502,7 +512,7 @@ void invalidate_tlb (CPUState *env, int idx, int use_extra) | @@ -502,7 +512,7 @@ void invalidate_tlb (CPUState *env, int idx, int use_extra) | ||
| 502 | /* For tlbwr, we can shadow the discarded entry into | 512 | /* For tlbwr, we can shadow the discarded entry into |
| 503 | a new (fake) TLB entry, as long as the guest can not | 513 | a new (fake) TLB entry, as long as the guest can not |
| 504 | tell that it's there. */ | 514 | tell that it's there. */ |
| 505 | - env->tlb[env->tlb_in_use] = *tlb; | 515 | + env->mmu.r4k.tlb[env->tlb_in_use] = *tlb; |
| 506 | env->tlb_in_use++; | 516 | env->tlb_in_use++; |
| 507 | return; | 517 | return; |
| 508 | } | 518 | } |
target-mips/mips-defs.h
| @@ -6,8 +6,6 @@ | @@ -6,8 +6,6 @@ | ||
| 6 | 6 | ||
| 7 | /* real pages are variable size... */ | 7 | /* real pages are variable size... */ |
| 8 | #define TARGET_PAGE_BITS 12 | 8 | #define TARGET_PAGE_BITS 12 |
| 9 | -/* Uses MIPS R4Kc TLB model */ | ||
| 10 | -#define MIPS_USES_R4K_TLB | ||
| 11 | #define MIPS_TLB_MAX 128 | 9 | #define MIPS_TLB_MAX 128 |
| 12 | 10 | ||
| 13 | #ifdef TARGET_MIPS64 | 11 | #ifdef TARGET_MIPS64 |
target-mips/op.c
| @@ -1411,12 +1411,7 @@ void op_mtc0_ebase (void) | @@ -1411,12 +1411,7 @@ void op_mtc0_ebase (void) | ||
| 1411 | 1411 | ||
| 1412 | void op_mtc0_config0 (void) | 1412 | void op_mtc0_config0 (void) |
| 1413 | { | 1413 | { |
| 1414 | -#if defined(MIPS_USES_R4K_TLB) | ||
| 1415 | - /* Fixed mapping MMU not implemented */ | ||
| 1416 | - env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF88) | (T0 & 0x00000001); | ||
| 1417 | -#else | ||
| 1418 | - env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF88) | (T0 & 0x00000001); | ||
| 1419 | -#endif | 1414 | + env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (T0 & 0x00000001); |
| 1420 | RETURN(); | 1415 | RETURN(); |
| 1421 | } | 1416 | } |
| 1422 | 1417 | ||
| @@ -2680,31 +2675,29 @@ void op_bc1tany4 (void) | @@ -2680,31 +2675,29 @@ void op_bc1tany4 (void) | ||
| 2680 | RETURN(); | 2675 | RETURN(); |
| 2681 | } | 2676 | } |
| 2682 | 2677 | ||
| 2683 | -#if defined(MIPS_USES_R4K_TLB) | ||
| 2684 | void op_tlbwi (void) | 2678 | void op_tlbwi (void) |
| 2685 | { | 2679 | { |
| 2686 | - CALL_FROM_TB0(do_tlbwi); | 2680 | + CALL_FROM_TB0(env->do_tlbwi); |
| 2687 | RETURN(); | 2681 | RETURN(); |
| 2688 | } | 2682 | } |
| 2689 | 2683 | ||
| 2690 | void op_tlbwr (void) | 2684 | void op_tlbwr (void) |
| 2691 | { | 2685 | { |
| 2692 | - CALL_FROM_TB0(do_tlbwr); | 2686 | + CALL_FROM_TB0(env->do_tlbwr); |
| 2693 | RETURN(); | 2687 | RETURN(); |
| 2694 | } | 2688 | } |
| 2695 | 2689 | ||
| 2696 | void op_tlbp (void) | 2690 | void op_tlbp (void) |
| 2697 | { | 2691 | { |
| 2698 | - CALL_FROM_TB0(do_tlbp); | 2692 | + CALL_FROM_TB0(env->do_tlbp); |
| 2699 | RETURN(); | 2693 | RETURN(); |
| 2700 | } | 2694 | } |
| 2701 | 2695 | ||
| 2702 | void op_tlbr (void) | 2696 | void op_tlbr (void) |
| 2703 | { | 2697 | { |
| 2704 | - CALL_FROM_TB0(do_tlbr); | 2698 | + CALL_FROM_TB0(env->do_tlbr); |
| 2705 | RETURN(); | 2699 | RETURN(); |
| 2706 | } | 2700 | } |
| 2707 | -#endif | ||
| 2708 | 2701 | ||
| 2709 | /* Specials */ | 2702 | /* Specials */ |
| 2710 | #if defined (CONFIG_USER_ONLY) | 2703 | #if defined (CONFIG_USER_ONLY) |
target-mips/op_helper.c
| @@ -298,26 +298,6 @@ void do_mtc0_status_irqraise_debug (void) | @@ -298,26 +298,6 @@ void do_mtc0_status_irqraise_debug (void) | ||
| 298 | cpu_abort(env, "mtc0 status irqraise debug\n"); | 298 | cpu_abort(env, "mtc0 status irqraise debug\n"); |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | -void do_tlbwi (void) | ||
| 302 | -{ | ||
| 303 | - cpu_abort(env, "tlbwi\n"); | ||
| 304 | -} | ||
| 305 | - | ||
| 306 | -void do_tlbwr (void) | ||
| 307 | -{ | ||
| 308 | - cpu_abort(env, "tlbwr\n"); | ||
| 309 | -} | ||
| 310 | - | ||
| 311 | -void do_tlbp (void) | ||
| 312 | -{ | ||
| 313 | - cpu_abort(env, "tlbp\n"); | ||
| 314 | -} | ||
| 315 | - | ||
| 316 | -void do_tlbr (void) | ||
| 317 | -{ | ||
| 318 | - cpu_abort(env, "tlbr\n"); | ||
| 319 | -} | ||
| 320 | - | ||
| 321 | void cpu_mips_tlb_flush (CPUState *env, int flush_global) | 301 | void cpu_mips_tlb_flush (CPUState *env, int flush_global) |
| 322 | { | 302 | { |
| 323 | cpu_abort(env, "mips_tlb_flush\n"); | 303 | cpu_abort(env, "mips_tlb_flush\n"); |
| @@ -389,7 +369,6 @@ void fpu_handle_exception(void) | @@ -389,7 +369,6 @@ void fpu_handle_exception(void) | ||
| 389 | } | 369 | } |
| 390 | 370 | ||
| 391 | /* TLB management */ | 371 | /* TLB management */ |
| 392 | -#if defined(MIPS_USES_R4K_TLB) | ||
| 393 | void cpu_mips_tlb_flush (CPUState *env, int flush_global) | 372 | void cpu_mips_tlb_flush (CPUState *env, int flush_global) |
| 394 | { | 373 | { |
| 395 | /* Flush qemu's TLB and discard all shadowed entries. */ | 374 | /* Flush qemu's TLB and discard all shadowed entries. */ |
| @@ -397,20 +376,20 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global) | @@ -397,20 +376,20 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global) | ||
| 397 | env->tlb_in_use = env->nb_tlb; | 376 | env->tlb_in_use = env->nb_tlb; |
| 398 | } | 377 | } |
| 399 | 378 | ||
| 400 | -static void mips_tlb_flush_extra (CPUState *env, int first) | 379 | +static void r4k_mips_tlb_flush_extra (CPUState *env, int first) |
| 401 | { | 380 | { |
| 402 | /* Discard entries from env->tlb[first] onwards. */ | 381 | /* Discard entries from env->tlb[first] onwards. */ |
| 403 | while (env->tlb_in_use > first) { | 382 | while (env->tlb_in_use > first) { |
| 404 | - invalidate_tlb(env, --env->tlb_in_use, 0); | 383 | + r4k_invalidate_tlb(env, --env->tlb_in_use, 0); |
| 405 | } | 384 | } |
| 406 | } | 385 | } |
| 407 | 386 | ||
| 408 | -static void fill_tlb (int idx) | 387 | +static void r4k_fill_tlb (int idx) |
| 409 | { | 388 | { |
| 410 | - tlb_t *tlb; | 389 | + r4k_tlb_t *tlb; |
| 411 | 390 | ||
| 412 | /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ | 391 | /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ |
| 413 | - tlb = &env->tlb[idx]; | 392 | + tlb = &env->mmu.r4k.tlb[idx]; |
| 414 | tlb->VPN = env->CP0_EntryHi & ~(target_ulong)0x1FFF; | 393 | tlb->VPN = env->CP0_EntryHi & ~(target_ulong)0x1FFF; |
| 415 | tlb->ASID = env->CP0_EntryHi & 0xFF; | 394 | tlb->ASID = env->CP0_EntryHi & 0xFF; |
| 416 | tlb->PageMask = env->CP0_PageMask; | 395 | tlb->PageMask = env->CP0_PageMask; |
| @@ -425,28 +404,28 @@ static void fill_tlb (int idx) | @@ -425,28 +404,28 @@ static void fill_tlb (int idx) | ||
| 425 | tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; | 404 | tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; |
| 426 | } | 405 | } |
| 427 | 406 | ||
| 428 | -void do_tlbwi (void) | 407 | +void r4k_do_tlbwi (void) |
| 429 | { | 408 | { |
| 430 | /* Discard cached TLB entries. We could avoid doing this if the | 409 | /* Discard cached TLB entries. We could avoid doing this if the |
| 431 | tlbwi is just upgrading access permissions on the current entry; | 410 | tlbwi is just upgrading access permissions on the current entry; |
| 432 | that might be a further win. */ | 411 | that might be a further win. */ |
| 433 | - mips_tlb_flush_extra (env, env->nb_tlb); | 412 | + r4k_mips_tlb_flush_extra (env, env->nb_tlb); |
| 434 | 413 | ||
| 435 | - invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0); | ||
| 436 | - fill_tlb(env->CP0_Index % env->nb_tlb); | 414 | + r4k_invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0); |
| 415 | + r4k_fill_tlb(env->CP0_Index % env->nb_tlb); | ||
| 437 | } | 416 | } |
| 438 | 417 | ||
| 439 | -void do_tlbwr (void) | 418 | +void r4k_do_tlbwr (void) |
| 440 | { | 419 | { |
| 441 | int r = cpu_mips_get_random(env); | 420 | int r = cpu_mips_get_random(env); |
| 442 | 421 | ||
| 443 | - invalidate_tlb(env, r, 1); | ||
| 444 | - fill_tlb(r); | 422 | + r4k_invalidate_tlb(env, r, 1); |
| 423 | + r4k_fill_tlb(r); | ||
| 445 | } | 424 | } |
| 446 | 425 | ||
| 447 | -void do_tlbp (void) | 426 | +void r4k_do_tlbp (void) |
| 448 | { | 427 | { |
| 449 | - tlb_t *tlb; | 428 | + r4k_tlb_t *tlb; |
| 450 | target_ulong tag; | 429 | target_ulong tag; |
| 451 | uint8_t ASID; | 430 | uint8_t ASID; |
| 452 | int i; | 431 | int i; |
| @@ -454,7 +433,7 @@ void do_tlbp (void) | @@ -454,7 +433,7 @@ void do_tlbp (void) | ||
| 454 | tag = env->CP0_EntryHi & (int32_t)0xFFFFE000; | 433 | tag = env->CP0_EntryHi & (int32_t)0xFFFFE000; |
| 455 | ASID = env->CP0_EntryHi & 0xFF; | 434 | ASID = env->CP0_EntryHi & 0xFF; |
| 456 | for (i = 0; i < env->nb_tlb; i++) { | 435 | for (i = 0; i < env->nb_tlb; i++) { |
| 457 | - tlb = &env->tlb[i]; | 436 | + tlb = &env->mmu.r4k.tlb[i]; |
| 458 | /* Check ASID, virtual page number & size */ | 437 | /* Check ASID, virtual page number & size */ |
| 459 | if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { | 438 | if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { |
| 460 | /* TLB match */ | 439 | /* TLB match */ |
| @@ -465,11 +444,11 @@ void do_tlbp (void) | @@ -465,11 +444,11 @@ void do_tlbp (void) | ||
| 465 | if (i == env->nb_tlb) { | 444 | if (i == env->nb_tlb) { |
| 466 | /* No match. Discard any shadow entries, if any of them match. */ | 445 | /* No match. Discard any shadow entries, if any of them match. */ |
| 467 | for (i = env->nb_tlb; i < env->tlb_in_use; i++) { | 446 | for (i = env->nb_tlb; i < env->tlb_in_use; i++) { |
| 468 | - tlb = &env->tlb[i]; | 447 | + tlb = &env->mmu.r4k.tlb[i]; |
| 469 | 448 | ||
| 470 | /* Check ASID, virtual page number & size */ | 449 | /* Check ASID, virtual page number & size */ |
| 471 | if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { | 450 | if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { |
| 472 | - mips_tlb_flush_extra (env, i); | 451 | + r4k_mips_tlb_flush_extra (env, i); |
| 473 | break; | 452 | break; |
| 474 | } | 453 | } |
| 475 | } | 454 | } |
| @@ -478,19 +457,19 @@ void do_tlbp (void) | @@ -478,19 +457,19 @@ void do_tlbp (void) | ||
| 478 | } | 457 | } |
| 479 | } | 458 | } |
| 480 | 459 | ||
| 481 | -void do_tlbr (void) | 460 | +void r4k_do_tlbr (void) |
| 482 | { | 461 | { |
| 483 | - tlb_t *tlb; | 462 | + r4k_tlb_t *tlb; |
| 484 | uint8_t ASID; | 463 | uint8_t ASID; |
| 485 | 464 | ||
| 486 | ASID = env->CP0_EntryHi & 0xFF; | 465 | ASID = env->CP0_EntryHi & 0xFF; |
| 487 | - tlb = &env->tlb[env->CP0_Index % env->nb_tlb]; | 466 | + tlb = &env->mmu.r4k.tlb[env->CP0_Index % env->nb_tlb]; |
| 488 | 467 | ||
| 489 | /* If this will change the current ASID, flush qemu's TLB. */ | 468 | /* If this will change the current ASID, flush qemu's TLB. */ |
| 490 | if (ASID != tlb->ASID) | 469 | if (ASID != tlb->ASID) |
| 491 | cpu_mips_tlb_flush (env, 1); | 470 | cpu_mips_tlb_flush (env, 1); |
| 492 | 471 | ||
| 493 | - mips_tlb_flush_extra(env, env->nb_tlb); | 472 | + r4k_mips_tlb_flush_extra(env, env->nb_tlb); |
| 494 | 473 | ||
| 495 | env->CP0_EntryHi = tlb->VPN | tlb->ASID; | 474 | env->CP0_EntryHi = tlb->VPN | tlb->ASID; |
| 496 | env->CP0_PageMask = tlb->PageMask; | 475 | env->CP0_PageMask = tlb->PageMask; |
| @@ -499,7 +478,6 @@ void do_tlbr (void) | @@ -499,7 +478,6 @@ void do_tlbr (void) | ||
| 499 | env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | | 478 | env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | |
| 500 | (tlb->C1 << 3) | (tlb->PFN[1] >> 6); | 479 | (tlb->C1 << 3) | (tlb->PFN[1] >> 6); |
| 501 | } | 480 | } |
| 502 | -#endif | ||
| 503 | 481 | ||
| 504 | #endif /* !CONFIG_USER_ONLY */ | 482 | #endif /* !CONFIG_USER_ONLY */ |
| 505 | 483 |
target-mips/translate.c
| @@ -4164,7 +4164,7 @@ die: | @@ -4164,7 +4164,7 @@ die: | ||
| 4164 | } | 4164 | } |
| 4165 | #endif /* TARGET_MIPS64 */ | 4165 | #endif /* TARGET_MIPS64 */ |
| 4166 | 4166 | ||
| 4167 | -static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) | 4167 | +static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rd) |
| 4168 | { | 4168 | { |
| 4169 | const char *opn = "ldst"; | 4169 | const char *opn = "ldst"; |
| 4170 | 4170 | ||
| @@ -4199,24 +4199,30 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) | @@ -4199,24 +4199,30 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) | ||
| 4199 | opn = "dmtc0"; | 4199 | opn = "dmtc0"; |
| 4200 | break; | 4200 | break; |
| 4201 | #endif | 4201 | #endif |
| 4202 | -#if defined(MIPS_USES_R4K_TLB) | ||
| 4203 | case OPC_TLBWI: | 4202 | case OPC_TLBWI: |
| 4204 | - gen_op_tlbwi(); | ||
| 4205 | opn = "tlbwi"; | 4203 | opn = "tlbwi"; |
| 4204 | + if (!env->do_tlbwi) | ||
| 4205 | + goto die; | ||
| 4206 | + gen_op_tlbwi(); | ||
| 4206 | break; | 4207 | break; |
| 4207 | case OPC_TLBWR: | 4208 | case OPC_TLBWR: |
| 4208 | - gen_op_tlbwr(); | ||
| 4209 | opn = "tlbwr"; | 4209 | opn = "tlbwr"; |
| 4210 | + if (!env->do_tlbwr) | ||
| 4211 | + goto die; | ||
| 4212 | + gen_op_tlbwr(); | ||
| 4210 | break; | 4213 | break; |
| 4211 | case OPC_TLBP: | 4214 | case OPC_TLBP: |
| 4212 | - gen_op_tlbp(); | ||
| 4213 | opn = "tlbp"; | 4215 | opn = "tlbp"; |
| 4216 | + if (!env->do_tlbp) | ||
| 4217 | + goto die; | ||
| 4218 | + gen_op_tlbp(); | ||
| 4214 | break; | 4219 | break; |
| 4215 | case OPC_TLBR: | 4220 | case OPC_TLBR: |
| 4216 | - gen_op_tlbr(); | ||
| 4217 | opn = "tlbr"; | 4221 | opn = "tlbr"; |
| 4222 | + if (!env->do_tlbr) | ||
| 4223 | + goto die; | ||
| 4224 | + gen_op_tlbr(); | ||
| 4218 | break; | 4225 | break; |
| 4219 | -#endif | ||
| 4220 | case OPC_ERET: | 4226 | case OPC_ERET: |
| 4221 | opn = "eret"; | 4227 | opn = "eret"; |
| 4222 | save_cpu_state(ctx, 0); | 4228 | save_cpu_state(ctx, 0); |
| @@ -4244,6 +4250,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) | @@ -4244,6 +4250,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) | ||
| 4244 | ctx->bstate = BS_EXCP; | 4250 | ctx->bstate = BS_EXCP; |
| 4245 | break; | 4251 | break; |
| 4246 | default: | 4252 | default: |
| 4253 | + die: | ||
| 4247 | MIPS_INVAL(opn); | 4254 | MIPS_INVAL(opn); |
| 4248 | generate_exception(ctx, EXCP_RI); | 4255 | generate_exception(ctx, EXCP_RI); |
| 4249 | return; | 4256 | return; |
| @@ -5576,10 +5583,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | @@ -5576,10 +5583,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) | ||
| 5576 | case OPC_DMFC0: | 5583 | case OPC_DMFC0: |
| 5577 | case OPC_DMTC0: | 5584 | case OPC_DMTC0: |
| 5578 | #endif | 5585 | #endif |
| 5579 | - gen_cp0(ctx, op1, rt, rd); | 5586 | + gen_cp0(env, ctx, op1, rt, rd); |
| 5580 | break; | 5587 | break; |
| 5581 | case OPC_C0_FIRST ... OPC_C0_LAST: | 5588 | case OPC_C0_FIRST ... OPC_C0_LAST: |
| 5582 | - gen_cp0(ctx, MASK_C0(ctx->opcode), rt, rd); | 5589 | + gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); |
| 5583 | break; | 5590 | break; |
| 5584 | case OPC_MFMC0: | 5591 | case OPC_MFMC0: |
| 5585 | op2 = MASK_MFMC0(ctx->opcode); | 5592 | op2 = MASK_MFMC0(ctx->opcode); |
target-mips/translate_init.c
| @@ -148,7 +148,7 @@ static mips_def_t mips_defs[] = | @@ -148,7 +148,7 @@ static mips_def_t mips_defs[] = | ||
| 148 | .Status_rw_bitmask = 0x3678FFFF, | 148 | .Status_rw_bitmask = 0x3678FFFF, |
| 149 | .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | | 149 | .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | |
| 150 | (1 << FCR0_D) | (1 << FCR0_S) | | 150 | (1 << FCR0_D) | (1 << FCR0_S) | |
| 151 | - (0x4 << FCR0_PRID) | (0x0 << FCR0_REV), | 151 | + (0x5 << FCR0_PRID) | (0x0 << FCR0_REV), |
| 152 | }, | 152 | }, |
| 153 | #endif | 153 | #endif |
| 154 | }; | 154 | }; |
| @@ -180,6 +180,30 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) | @@ -180,6 +180,30 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) | ||
| 180 | } | 180 | } |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | +#ifndef CONFIG_USER_ONLY | ||
| 184 | +static void no_mmu_init (CPUMIPSState *env, mips_def_t *def) | ||
| 185 | +{ | ||
| 186 | + env->nb_tlb = 1; | ||
| 187 | + env->map_address = &no_mmu_map_address; | ||
| 188 | +} | ||
| 189 | + | ||
| 190 | +static void fixed_mmu_init (CPUMIPSState *env, mips_def_t *def) | ||
| 191 | +{ | ||
| 192 | + env->nb_tlb = 1; | ||
| 193 | + env->map_address = &fixed_mmu_map_address; | ||
| 194 | +} | ||
| 195 | + | ||
| 196 | +static void r4k_mmu_init (CPUMIPSState *env, mips_def_t *def) | ||
| 197 | +{ | ||
| 198 | + env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); | ||
| 199 | + env->map_address = &r4k_map_address; | ||
| 200 | + env->do_tlbwi = r4k_do_tlbwi; | ||
| 201 | + env->do_tlbwr = r4k_do_tlbwr; | ||
| 202 | + env->do_tlbp = r4k_do_tlbp; | ||
| 203 | + env->do_tlbr = r4k_do_tlbr; | ||
| 204 | +} | ||
| 205 | +#endif /* CONFIG_USER_ONLY */ | ||
| 206 | + | ||
| 183 | int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) | 207 | int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) |
| 184 | { | 208 | { |
| 185 | if (!def) | 209 | if (!def) |
| @@ -199,10 +223,23 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) | @@ -199,10 +223,23 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) | ||
| 199 | env->CCRes = def->CCRes; | 223 | env->CCRes = def->CCRes; |
| 200 | env->Status_rw_bitmask = def->Status_rw_bitmask; | 224 | env->Status_rw_bitmask = def->Status_rw_bitmask; |
| 201 | env->fcr0 = def->CP1_fcr0; | 225 | env->fcr0 = def->CP1_fcr0; |
| 202 | -#if defined (MIPS_USES_R4K_TLB) | ||
| 203 | - env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); | 226 | +#ifndef CONFIG_USER_ONLY |
| 227 | + switch ((env->CP0_Config0 >> CP0C0_MT) & 3) { | ||
| 228 | + case 0: | ||
| 229 | + no_mmu_init(env, def); | ||
| 230 | + break; | ||
| 231 | + case 1: | ||
| 232 | + r4k_mmu_init(env, def); | ||
| 233 | + break; | ||
| 234 | + case 3: | ||
| 235 | + fixed_mmu_init(env, def); | ||
| 236 | + break; | ||
| 237 | + default: | ||
| 238 | + /* Older CPUs like the R3000 may need nonstandard handling here. */ | ||
| 239 | + cpu_abort(env, "MMU type not supported\n"); | ||
| 240 | + } | ||
| 204 | env->CP0_Random = env->nb_tlb - 1; | 241 | env->CP0_Random = env->nb_tlb - 1; |
| 205 | env->tlb_in_use = env->nb_tlb; | 242 | env->tlb_in_use = env->nb_tlb; |
| 206 | -#endif | 243 | +#endif /* CONFIG_USER_ONLY */ |
| 207 | return 0; | 244 | return 0; |
| 208 | } | 245 | } |