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