Commit 29929e349009731a2fb22a983da75f67b6e78362

Authored by ths
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
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 }