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 | 33 | # define FP_ENDIAN_IDX 0 |
34 | 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 | 38 | target_ulong VPN; |
40 | 39 | uint32_t PageMask; |
41 | 40 | uint_fast8_t ASID; |
... | ... | @@ -48,7 +47,6 @@ struct tlb_t { |
48 | 47 | uint_fast16_t D1:1; |
49 | 48 | target_ulong PFN[2]; |
50 | 49 | }; |
51 | -#endif | |
52 | 50 | |
53 | 51 | typedef struct CPUMIPSState CPUMIPSState; |
54 | 52 | struct CPUMIPSState { |
... | ... | @@ -100,11 +98,19 @@ struct CPUMIPSState { |
100 | 98 | #define FP_INVALID 16 |
101 | 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 | 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 | 114 | int32_t CP0_Index; |
109 | 115 | int32_t CP0_Random; |
110 | 116 | target_ulong CP0_EntryLo0; |
... | ... | @@ -289,6 +295,16 @@ struct CPUMIPSState { |
289 | 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 | 308 | typedef struct mips_def_t mips_def_t; |
293 | 309 | int mips_find_by_name (const unsigned char *name, mips_def_t **def); |
294 | 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 | 105 | void do_mtc0_entryhi(uint32_t in); |
106 | 106 | void do_mtc0_status_debug(uint32_t old, uint32_t val); |
107 | 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 | 108 | void dump_fpu(CPUState *env); |
113 | 109 | void fpu_dump_state(CPUState *env, FILE *f, |
114 | 110 | int (*fpu_fprintf)(FILE *f, const char *fmt, ...), |
... | ... | @@ -151,7 +147,7 @@ void dump_sc (void); |
151 | 147 | int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
152 | 148 | int is_user, int is_softmmu); |
153 | 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 | 152 | void cpu_loop_exit(void); |
157 | 153 | void do_raise_exception_err (uint32_t exception, int error_code); | ... | ... |
target-mips/helper.c
... | ... | @@ -36,16 +36,42 @@ enum { |
36 | 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 | 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 | 70 | uint8_t ASID = env->CP0_EntryHi & 0xFF; |
45 | 71 | int i; |
46 | 72 | |
47 | 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 | 75 | /* 1k pages are not supported. */ |
50 | 76 | target_ulong mask = tlb->PageMask | 0x1FFF; |
51 | 77 | target_ulong tag = address & ~mask; |
... | ... | @@ -71,7 +97,6 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, |
71 | 97 | } |
72 | 98 | return TLBRET_NOMATCH; |
73 | 99 | } |
74 | -#endif | |
75 | 100 | |
76 | 101 | static int get_physical_address (CPUState *env, target_ulong *physical, |
77 | 102 | int *prot, target_ulong address, |
... | ... | @@ -104,14 +129,9 @@ static int get_physical_address (CPUState *env, target_ulong *physical, |
104 | 129 | if (address <= (int32_t)0x7FFFFFFFUL) { |
105 | 130 | /* useg */ |
106 | 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 | 133 | } else { |
114 | - *physical = address; | |
134 | + *physical = address & 0xFFFFFFFF; | |
115 | 135 | *prot = PAGE_READ | PAGE_WRITE; |
116 | 136 | } |
117 | 137 | #ifdef TARGET_MIPS64 |
... | ... | @@ -123,14 +143,14 @@ static int get_physical_address (CPUState *env, target_ulong *physical, |
123 | 143 | } else if (address < 0x3FFFFFFFFFFFFFFFULL) { |
124 | 144 | /* xuseg */ |
125 | 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 | 147 | } else { |
128 | 148 | ret = TLBRET_BADADDR; |
129 | 149 | } |
130 | 150 | } else if (address < 0x7FFFFFFFFFFFFFFFULL) { |
131 | 151 | /* xsseg */ |
132 | 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 | 154 | } else { |
135 | 155 | ret = TLBRET_BADADDR; |
136 | 156 | } |
... | ... | @@ -148,7 +168,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, |
148 | 168 | /* xkseg */ |
149 | 169 | /* XXX: check supervisor mode */ |
150 | 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 | 172 | } else { |
153 | 173 | ret = TLBRET_BADADDR; |
154 | 174 | } |
... | ... | @@ -165,22 +185,12 @@ static int get_physical_address (CPUState *env, target_ulong *physical, |
165 | 185 | *prot = PAGE_READ | PAGE_WRITE; |
166 | 186 | } else if (address < (int32_t)0xE0000000UL) { |
167 | 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 | 189 | } else { |
175 | 190 | /* kseg3 */ |
176 | 191 | /* XXX: check supervisor mode */ |
177 | 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 | 195 | #if 0 |
186 | 196 | if (logfile) { |
... | ... | @@ -483,15 +493,15 @@ void do_interrupt (CPUState *env) |
483 | 493 | } |
484 | 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 | 499 | target_ulong addr; |
490 | 500 | target_ulong end; |
491 | 501 | uint8_t ASID = env->CP0_EntryHi & 0xFF; |
492 | 502 | target_ulong mask; |
493 | 503 | |
494 | - tlb = &env->tlb[idx]; | |
504 | + tlb = &env->mmu.r4k.tlb[idx]; | |
495 | 505 | /* The qemu TLB is flushed then the ASID changes, so no need to |
496 | 506 | flush these entries again. */ |
497 | 507 | if (tlb->G == 0 && tlb->ASID != ASID) { |
... | ... | @@ -502,7 +512,7 @@ void invalidate_tlb (CPUState *env, int idx, int use_extra) |
502 | 512 | /* For tlbwr, we can shadow the discarded entry into |
503 | 513 | a new (fake) TLB entry, as long as the guest can not |
504 | 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 | 516 | env->tlb_in_use++; |
507 | 517 | return; |
508 | 518 | } | ... | ... |
target-mips/mips-defs.h
target-mips/op.c
... | ... | @@ -1411,12 +1411,7 @@ void op_mtc0_ebase (void) |
1411 | 1411 | |
1412 | 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 | 1415 | RETURN(); |
1421 | 1416 | } |
1422 | 1417 | |
... | ... | @@ -2680,31 +2675,29 @@ void op_bc1tany4 (void) |
2680 | 2675 | RETURN(); |
2681 | 2676 | } |
2682 | 2677 | |
2683 | -#if defined(MIPS_USES_R4K_TLB) | |
2684 | 2678 | void op_tlbwi (void) |
2685 | 2679 | { |
2686 | - CALL_FROM_TB0(do_tlbwi); | |
2680 | + CALL_FROM_TB0(env->do_tlbwi); | |
2687 | 2681 | RETURN(); |
2688 | 2682 | } |
2689 | 2683 | |
2690 | 2684 | void op_tlbwr (void) |
2691 | 2685 | { |
2692 | - CALL_FROM_TB0(do_tlbwr); | |
2686 | + CALL_FROM_TB0(env->do_tlbwr); | |
2693 | 2687 | RETURN(); |
2694 | 2688 | } |
2695 | 2689 | |
2696 | 2690 | void op_tlbp (void) |
2697 | 2691 | { |
2698 | - CALL_FROM_TB0(do_tlbp); | |
2692 | + CALL_FROM_TB0(env->do_tlbp); | |
2699 | 2693 | RETURN(); |
2700 | 2694 | } |
2701 | 2695 | |
2702 | 2696 | void op_tlbr (void) |
2703 | 2697 | { |
2704 | - CALL_FROM_TB0(do_tlbr); | |
2698 | + CALL_FROM_TB0(env->do_tlbr); | |
2705 | 2699 | RETURN(); |
2706 | 2700 | } |
2707 | -#endif | |
2708 | 2701 | |
2709 | 2702 | /* Specials */ |
2710 | 2703 | #if defined (CONFIG_USER_ONLY) | ... | ... |
target-mips/op_helper.c
... | ... | @@ -298,26 +298,6 @@ void do_mtc0_status_irqraise_debug (void) |
298 | 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 | 301 | void cpu_mips_tlb_flush (CPUState *env, int flush_global) |
322 | 302 | { |
323 | 303 | cpu_abort(env, "mips_tlb_flush\n"); |
... | ... | @@ -389,7 +369,6 @@ void fpu_handle_exception(void) |
389 | 369 | } |
390 | 370 | |
391 | 371 | /* TLB management */ |
392 | -#if defined(MIPS_USES_R4K_TLB) | |
393 | 372 | void cpu_mips_tlb_flush (CPUState *env, int flush_global) |
394 | 373 | { |
395 | 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 | 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 | 381 | /* Discard entries from env->tlb[first] onwards. */ |
403 | 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 | 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 | 393 | tlb->VPN = env->CP0_EntryHi & ~(target_ulong)0x1FFF; |
415 | 394 | tlb->ASID = env->CP0_EntryHi & 0xFF; |
416 | 395 | tlb->PageMask = env->CP0_PageMask; |
... | ... | @@ -425,28 +404,28 @@ static void fill_tlb (int idx) |
425 | 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 | 409 | /* Discard cached TLB entries. We could avoid doing this if the |
431 | 410 | tlbwi is just upgrading access permissions on the current entry; |
432 | 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 | 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 | 429 | target_ulong tag; |
451 | 430 | uint8_t ASID; |
452 | 431 | int i; |
... | ... | @@ -454,7 +433,7 @@ void do_tlbp (void) |
454 | 433 | tag = env->CP0_EntryHi & (int32_t)0xFFFFE000; |
455 | 434 | ASID = env->CP0_EntryHi & 0xFF; |
456 | 435 | for (i = 0; i < env->nb_tlb; i++) { |
457 | - tlb = &env->tlb[i]; | |
436 | + tlb = &env->mmu.r4k.tlb[i]; | |
458 | 437 | /* Check ASID, virtual page number & size */ |
459 | 438 | if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { |
460 | 439 | /* TLB match */ |
... | ... | @@ -465,11 +444,11 @@ void do_tlbp (void) |
465 | 444 | if (i == env->nb_tlb) { |
466 | 445 | /* No match. Discard any shadow entries, if any of them match. */ |
467 | 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 | 449 | /* Check ASID, virtual page number & size */ |
471 | 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 | 452 | break; |
474 | 453 | } |
475 | 454 | } |
... | ... | @@ -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 | 463 | uint8_t ASID; |
485 | 464 | |
486 | 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 | 468 | /* If this will change the current ASID, flush qemu's TLB. */ |
490 | 469 | if (ASID != tlb->ASID) |
491 | 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 | 474 | env->CP0_EntryHi = tlb->VPN | tlb->ASID; |
496 | 475 | env->CP0_PageMask = tlb->PageMask; |
... | ... | @@ -499,7 +478,6 @@ void do_tlbr (void) |
499 | 478 | env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | |
500 | 479 | (tlb->C1 << 3) | (tlb->PFN[1] >> 6); |
501 | 480 | } |
502 | -#endif | |
503 | 481 | |
504 | 482 | #endif /* !CONFIG_USER_ONLY */ |
505 | 483 | ... | ... |
target-mips/translate.c
... | ... | @@ -4164,7 +4164,7 @@ die: |
4164 | 4164 | } |
4165 | 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 | 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 | 4199 | opn = "dmtc0"; |
4200 | 4200 | break; |
4201 | 4201 | #endif |
4202 | -#if defined(MIPS_USES_R4K_TLB) | |
4203 | 4202 | case OPC_TLBWI: |
4204 | - gen_op_tlbwi(); | |
4205 | 4203 | opn = "tlbwi"; |
4204 | + if (!env->do_tlbwi) | |
4205 | + goto die; | |
4206 | + gen_op_tlbwi(); | |
4206 | 4207 | break; |
4207 | 4208 | case OPC_TLBWR: |
4208 | - gen_op_tlbwr(); | |
4209 | 4209 | opn = "tlbwr"; |
4210 | + if (!env->do_tlbwr) | |
4211 | + goto die; | |
4212 | + gen_op_tlbwr(); | |
4210 | 4213 | break; |
4211 | 4214 | case OPC_TLBP: |
4212 | - gen_op_tlbp(); | |
4213 | 4215 | opn = "tlbp"; |
4216 | + if (!env->do_tlbp) | |
4217 | + goto die; | |
4218 | + gen_op_tlbp(); | |
4214 | 4219 | break; |
4215 | 4220 | case OPC_TLBR: |
4216 | - gen_op_tlbr(); | |
4217 | 4221 | opn = "tlbr"; |
4222 | + if (!env->do_tlbr) | |
4223 | + goto die; | |
4224 | + gen_op_tlbr(); | |
4218 | 4225 | break; |
4219 | -#endif | |
4220 | 4226 | case OPC_ERET: |
4221 | 4227 | opn = "eret"; |
4222 | 4228 | save_cpu_state(ctx, 0); |
... | ... | @@ -4244,6 +4250,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) |
4244 | 4250 | ctx->bstate = BS_EXCP; |
4245 | 4251 | break; |
4246 | 4252 | default: |
4253 | + die: | |
4247 | 4254 | MIPS_INVAL(opn); |
4248 | 4255 | generate_exception(ctx, EXCP_RI); |
4249 | 4256 | return; |
... | ... | @@ -5576,10 +5583,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) |
5576 | 5583 | case OPC_DMFC0: |
5577 | 5584 | case OPC_DMTC0: |
5578 | 5585 | #endif |
5579 | - gen_cp0(ctx, op1, rt, rd); | |
5586 | + gen_cp0(env, ctx, op1, rt, rd); | |
5580 | 5587 | break; |
5581 | 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 | 5590 | break; |
5584 | 5591 | case OPC_MFMC0: |
5585 | 5592 | op2 = MASK_MFMC0(ctx->opcode); | ... | ... |
target-mips/translate_init.c
... | ... | @@ -148,7 +148,7 @@ static mips_def_t mips_defs[] = |
148 | 148 | .Status_rw_bitmask = 0x3678FFFF, |
149 | 149 | .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | |
150 | 150 | (1 << FCR0_D) | (1 << FCR0_S) | |
151 | - (0x4 << FCR0_PRID) | (0x0 << FCR0_REV), | |
151 | + (0x5 << FCR0_PRID) | (0x0 << FCR0_REV), | |
152 | 152 | }, |
153 | 153 | #endif |
154 | 154 | }; |
... | ... | @@ -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 | 207 | int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) |
184 | 208 | { |
185 | 209 | if (!def) |
... | ... | @@ -199,10 +223,23 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) |
199 | 223 | env->CCRes = def->CCRes; |
200 | 224 | env->Status_rw_bitmask = def->Status_rw_bitmask; |
201 | 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 | 241 | env->CP0_Random = env->nb_tlb - 1; |
205 | 242 | env->tlb_in_use = env->nb_tlb; |
206 | -#endif | |
243 | +#endif /* CONFIG_USER_ONLY */ | |
207 | 244 | return 0; |
208 | 245 | } | ... | ... |