Revision 29929e34
b/target-mips/cpu.h | ||
---|---|---|
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 | 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 | 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 | 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, ...)); |
b/target-mips/exec.h | ||
---|---|---|
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 | 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); |
b/target-mips/helper.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 |
} |
b/target-mips/mips-defs.h | ||
---|---|---|
6 | 6 |
|
7 | 7 |
/* real pages are variable size... */ |
8 | 8 |
#define TARGET_PAGE_BITS 12 |
9 |
/* Uses MIPS R4Kc TLB model */ |
|
10 |
#define MIPS_USES_R4K_TLB |
|
11 | 9 |
#define MIPS_TLB_MAX 128 |
12 | 10 |
|
13 | 11 |
#ifdef TARGET_MIPS64 |
b/target-mips/op.c | ||
---|---|---|
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 | 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) |
b/target-mips/op_helper.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 |
|
b/target-mips/translate.c | ||
---|---|---|
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 | 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 | 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 | 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); |
b/target-mips/translate_init.c | ||
---|---|---|
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 | 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 | 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 |
} |
Also available in: Unified diff