Statistics
| Branch: | Revision:

root / target-sh4 / helper.c @ b0fb8423

History | View | Annotate | Download (22.5 kB)

1
/*
2
 *  SH4 emulation
3
 *
4
 *  Copyright (c) 2005 Samuel Tardieu
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19
#include <stdarg.h>
20
#include <stdlib.h>
21
#include <stdio.h>
22
#include <string.h>
23
#include <inttypes.h>
24
#include <signal.h>
25

    
26
#include "cpu.h"
27
#include "exec-all.h"
28
#include "hw/sh_intc.h"
29

    
30
#if defined(CONFIG_USER_ONLY)
31

    
32
void do_interrupt (CPUState *env)
33
{
34
  env->exception_index = -1;
35
}
36

    
37
int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
38
                             int mmu_idx, int is_softmmu)
39
{
40
    env->tea = address;
41
    env->exception_index = -1;
42
    switch (rw) {
43
    case 0:
44
        env->exception_index = 0x0a0;
45
        break;
46
    case 1:
47
        env->exception_index = 0x0c0;
48
        break;
49
    case 2:
50
        env->exception_index = 0x0a0;
51
        break;
52
    }
53
    return 1;
54
}
55

    
56
int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
57
{
58
    /* For user mode, only U0 area is cachable. */
59
    return !(addr & 0x80000000);
60
}
61

    
62
#else /* !CONFIG_USER_ONLY */
63

    
64
#define MMU_OK                   0
65
#define MMU_ITLB_MISS            (-1)
66
#define MMU_ITLB_MULTIPLE        (-2)
67
#define MMU_ITLB_VIOLATION       (-3)
68
#define MMU_DTLB_MISS_READ       (-4)
69
#define MMU_DTLB_MISS_WRITE      (-5)
70
#define MMU_DTLB_INITIAL_WRITE   (-6)
71
#define MMU_DTLB_VIOLATION_READ  (-7)
72
#define MMU_DTLB_VIOLATION_WRITE (-8)
73
#define MMU_DTLB_MULTIPLE        (-9)
74
#define MMU_DTLB_MISS            (-10)
75
#define MMU_IADDR_ERROR          (-11)
76
#define MMU_DADDR_ERROR_READ     (-12)
77
#define MMU_DADDR_ERROR_WRITE    (-13)
78

    
79
void do_interrupt(CPUState * env)
80
{
81
    int do_irq = env->interrupt_request & CPU_INTERRUPT_HARD;
82
    int do_exp, irq_vector = env->exception_index;
83

    
84
    /* prioritize exceptions over interrupts */
85

    
86
    do_exp = env->exception_index != -1;
87
    do_irq = do_irq && (env->exception_index == -1);
88

    
89
    if (env->sr & SR_BL) {
90
        if (do_exp && env->exception_index != 0x1e0) {
91
            env->exception_index = 0x000; /* masked exception -> reset */
92
        }
93
        if (do_irq && !env->in_sleep) {
94
            return; /* masked */
95
        }
96
    }
97
    env->in_sleep = 0;
98

    
99
    if (do_irq) {
100
        irq_vector = sh_intc_get_pending_vector(env->intc_handle,
101
                                                (env->sr >> 4) & 0xf);
102
        if (irq_vector == -1) {
103
            return; /* masked */
104
        }
105
    }
106

    
107
    if (qemu_loglevel_mask(CPU_LOG_INT)) {
108
        const char *expname;
109
        switch (env->exception_index) {
110
        case 0x0e0:
111
            expname = "addr_error";
112
            break;
113
        case 0x040:
114
            expname = "tlb_miss";
115
            break;
116
        case 0x0a0:
117
            expname = "tlb_violation";
118
            break;
119
        case 0x180:
120
            expname = "illegal_instruction";
121
            break;
122
        case 0x1a0:
123
            expname = "slot_illegal_instruction";
124
            break;
125
        case 0x800:
126
            expname = "fpu_disable";
127
            break;
128
        case 0x820:
129
            expname = "slot_fpu";
130
            break;
131
        case 0x100:
132
            expname = "data_write";
133
            break;
134
        case 0x060:
135
            expname = "dtlb_miss_write";
136
            break;
137
        case 0x0c0:
138
            expname = "dtlb_violation_write";
139
            break;
140
        case 0x120:
141
            expname = "fpu_exception";
142
            break;
143
        case 0x080:
144
            expname = "initial_page_write";
145
            break;
146
        case 0x160:
147
            expname = "trapa";
148
            break;
149
        default:
150
            expname = do_irq ? "interrupt" : "???";
151
            break;
152
        }
153
        qemu_log("exception 0x%03x [%s] raised\n",
154
                  irq_vector, expname);
155
        log_cpu_state(env, 0);
156
    }
157

    
158
    env->ssr = env->sr;
159
    env->spc = env->pc;
160
    env->sgr = env->gregs[15];
161
    env->sr |= SR_BL | SR_MD | SR_RB;
162

    
163
    if (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
164
        /* Branch instruction should be executed again before delay slot. */
165
        env->spc -= 2;
166
        /* Clear flags for exception/interrupt routine. */
167
        env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL | DELAY_SLOT_TRUE);
168
    }
169
    if (env->flags & DELAY_SLOT_CLEARME)
170
        env->flags = 0;
171

    
172
    if (do_exp) {
173
        env->expevt = env->exception_index;
174
        switch (env->exception_index) {
175
        case 0x000:
176
        case 0x020:
177
        case 0x140:
178
            env->sr &= ~SR_FD;
179
            env->sr |= 0xf << 4; /* IMASK */
180
            env->pc = 0xa0000000;
181
            break;
182
        case 0x040:
183
        case 0x060:
184
            env->pc = env->vbr + 0x400;
185
            break;
186
        case 0x160:
187
            env->spc += 2; /* special case for TRAPA */
188
            /* fall through */
189
        default:
190
            env->pc = env->vbr + 0x100;
191
            break;
192
        }
193
        return;
194
    }
195

    
196
    if (do_irq) {
197
        env->intevt = irq_vector;
198
        env->pc = env->vbr + 0x600;
199
        return;
200
    }
201
}
202

    
203
static void update_itlb_use(CPUState * env, int itlbnb)
204
{
205
    uint8_t or_mask = 0, and_mask = (uint8_t) - 1;
206

    
207
    switch (itlbnb) {
208
    case 0:
209
        and_mask = 0x1f;
210
        break;
211
    case 1:
212
        and_mask = 0xe7;
213
        or_mask = 0x80;
214
        break;
215
    case 2:
216
        and_mask = 0xfb;
217
        or_mask = 0x50;
218
        break;
219
    case 3:
220
        or_mask = 0x2c;
221
        break;
222
    }
223

    
224
    env->mmucr &= (and_mask << 24) | 0x00ffffff;
225
    env->mmucr |= (or_mask << 24);
226
}
227

    
228
static int itlb_replacement(CPUState * env)
229
{
230
    if ((env->mmucr & 0xe0000000) == 0xe0000000)
231
        return 0;
232
    if ((env->mmucr & 0x98000000) == 0x18000000)
233
        return 1;
234
    if ((env->mmucr & 0x54000000) == 0x04000000)
235
        return 2;
236
    if ((env->mmucr & 0x2c000000) == 0x00000000)
237
        return 3;
238
    cpu_abort(env, "Unhandled itlb_replacement");
239
}
240

    
241
/* Find the corresponding entry in the right TLB
242
   Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE
243
*/
244
static int find_tlb_entry(CPUState * env, target_ulong address,
245
                          tlb_t * entries, uint8_t nbtlb, int use_asid)
246
{
247
    int match = MMU_DTLB_MISS;
248
    uint32_t start, end;
249
    uint8_t asid;
250
    int i;
251

    
252
    asid = env->pteh & 0xff;
253

    
254
    for (i = 0; i < nbtlb; i++) {
255
        if (!entries[i].v)
256
            continue;                /* Invalid entry */
257
        if (!entries[i].sh && use_asid && entries[i].asid != asid)
258
            continue;                /* Bad ASID */
259
        start = (entries[i].vpn << 10) & ~(entries[i].size - 1);
260
        end = start + entries[i].size - 1;
261
        if (address >= start && address <= end) {        /* Match */
262
            if (match != MMU_DTLB_MISS)
263
                return MMU_DTLB_MULTIPLE;        /* Multiple match */
264
            match = i;
265
        }
266
    }
267
    return match;
268
}
269

    
270
static void increment_urc(CPUState * env)
271
{
272
    uint8_t urb, urc;
273

    
274
    /* Increment URC */
275
    urb = ((env->mmucr) >> 18) & 0x3f;
276
    urc = ((env->mmucr) >> 10) & 0x3f;
277
    urc++;
278
    if ((urb > 0 && urc > urb) || urc > (UTLB_SIZE - 1))
279
        urc = 0;
280
    env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
281
}
282

    
283
/* Copy and utlb entry into itlb
284
   Return entry
285
*/
286
static int copy_utlb_entry_itlb(CPUState *env, int utlb)
287
{
288
    int itlb;
289

    
290
    tlb_t * ientry;
291
    itlb = itlb_replacement(env);
292
    ientry = &env->itlb[itlb];
293
    if (ientry->v) {
294
        tlb_flush_page(env, ientry->vpn << 10);
295
    }
296
    *ientry = env->utlb[utlb];
297
    update_itlb_use(env, itlb);
298
    return itlb;
299
}
300

    
301
/* Find itlb entry
302
   Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
303
*/
304
static int find_itlb_entry(CPUState * env, target_ulong address,
305
                           int use_asid)
306
{
307
    int e;
308

    
309
    e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid);
310
    if (e == MMU_DTLB_MULTIPLE) {
311
        e = MMU_ITLB_MULTIPLE;
312
    } else if (e == MMU_DTLB_MISS) {
313
        e = MMU_ITLB_MISS;
314
    } else if (e >= 0) {
315
        update_itlb_use(env, e);
316
    }
317
    return e;
318
}
319

    
320
/* Find utlb entry
321
   Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */
322
static int find_utlb_entry(CPUState * env, target_ulong address, int use_asid)
323
{
324
    /* per utlb access */
325
    increment_urc(env);
326

    
327
    /* Return entry */
328
    return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
329
}
330

    
331
/* Match address against MMU
332
   Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE,
333
   MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ,
334
   MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS,
335
   MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION,
336
   MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE.
337
*/
338
static int get_mmu_address(CPUState * env, target_ulong * physical,
339
                           int *prot, target_ulong address,
340
                           int rw, int access_type)
341
{
342
    int use_asid, n;
343
    tlb_t *matching = NULL;
344

    
345
    use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
346

    
347
    if (rw == 2) {
348
        n = find_itlb_entry(env, address, use_asid);
349
        if (n >= 0) {
350
            matching = &env->itlb[n];
351
            if (!(env->sr & SR_MD) && !(matching->pr & 2))
352
                n = MMU_ITLB_VIOLATION;
353
            else
354
                *prot = PAGE_EXEC;
355
        } else {
356
            n = find_utlb_entry(env, address, use_asid);
357
            if (n >= 0) {
358
                n = copy_utlb_entry_itlb(env, n);
359
                matching = &env->itlb[n];
360
                if (!(env->sr & SR_MD) && !(matching->pr & 2)) {
361
                      n = MMU_ITLB_VIOLATION;
362
                } else {
363
                    *prot = PAGE_READ | PAGE_EXEC;
364
                    if ((matching->pr & 1) && matching->d) {
365
                        *prot |= PAGE_WRITE;
366
                    }
367
                }
368
            } else if (n == MMU_DTLB_MULTIPLE) {
369
                n = MMU_ITLB_MULTIPLE;
370
            } else if (n == MMU_DTLB_MISS) {
371
                n = MMU_ITLB_MISS;
372
            }
373
        }
374
    } else {
375
        n = find_utlb_entry(env, address, use_asid);
376
        if (n >= 0) {
377
            matching = &env->utlb[n];
378
            if (!(env->sr & SR_MD) && !(matching->pr & 2)) {
379
                n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE :
380
                    MMU_DTLB_VIOLATION_READ;
381
            } else if ((rw == 1) && !(matching->pr & 1)) {
382
                n = MMU_DTLB_VIOLATION_WRITE;
383
            } else if ((rw == 1) && !matching->d) {
384
                n = MMU_DTLB_INITIAL_WRITE;
385
            } else {
386
                *prot = PAGE_READ;
387
                if ((matching->pr & 1) && matching->d) {
388
                    *prot |= PAGE_WRITE;
389
                }
390
            }
391
        } else if (n == MMU_DTLB_MISS) {
392
            n = (rw == 1) ? MMU_DTLB_MISS_WRITE :
393
                MMU_DTLB_MISS_READ;
394
        }
395
    }
396
    if (n >= 0) {
397
        n = MMU_OK;
398
        *physical = ((matching->ppn << 10) & ~(matching->size - 1)) |
399
            (address & (matching->size - 1));
400
    }
401
    return n;
402
}
403

    
404
static int get_physical_address(CPUState * env, target_ulong * physical,
405
                                int *prot, target_ulong address,
406
                                int rw, int access_type)
407
{
408
    /* P1, P2 and P4 areas do not use translation */
409
    if ((address >= 0x80000000 && address < 0xc0000000) ||
410
        address >= 0xe0000000) {
411
        if (!(env->sr & SR_MD)
412
            && (address < 0xe0000000 || address >= 0xe4000000)) {
413
            /* Unauthorized access in user mode (only store queues are available) */
414
            fprintf(stderr, "Unauthorized access\n");
415
            if (rw == 0)
416
                return MMU_DADDR_ERROR_READ;
417
            else if (rw == 1)
418
                return MMU_DADDR_ERROR_WRITE;
419
            else
420
                return MMU_IADDR_ERROR;
421
        }
422
        if (address >= 0x80000000 && address < 0xc0000000) {
423
            /* Mask upper 3 bits for P1 and P2 areas */
424
            *physical = address & 0x1fffffff;
425
        } else {
426
            *physical = address;
427
        }
428
        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
429
        return MMU_OK;
430
    }
431

    
432
    /* If MMU is disabled, return the corresponding physical page */
433
    if (!(env->mmucr & MMUCR_AT)) {
434
        *physical = address & 0x1FFFFFFF;
435
        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
436
        return MMU_OK;
437
    }
438

    
439
    /* We need to resort to the MMU */
440
    return get_mmu_address(env, physical, prot, address, rw, access_type);
441
}
442

    
443
int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
444
                             int mmu_idx, int is_softmmu)
445
{
446
    target_ulong physical;
447
    int prot, ret, access_type;
448

    
449
    access_type = ACCESS_INT;
450
    ret =
451
        get_physical_address(env, &physical, &prot, address, rw,
452
                             access_type);
453

    
454
    if (ret != MMU_OK) {
455
        env->tea = address;
456
        if (ret != MMU_DTLB_MULTIPLE && ret != MMU_ITLB_MULTIPLE) {
457
            env->pteh = (env->pteh & PTEH_ASID_MASK) |
458
                    (address & PTEH_VPN_MASK);
459
        }
460
        switch (ret) {
461
        case MMU_ITLB_MISS:
462
        case MMU_DTLB_MISS_READ:
463
            env->exception_index = 0x040;
464
            break;
465
        case MMU_DTLB_MULTIPLE:
466
        case MMU_ITLB_MULTIPLE:
467
            env->exception_index = 0x140;
468
            break;
469
        case MMU_ITLB_VIOLATION:
470
            env->exception_index = 0x0a0;
471
            break;
472
        case MMU_DTLB_MISS_WRITE:
473
            env->exception_index = 0x060;
474
            break;
475
        case MMU_DTLB_INITIAL_WRITE:
476
            env->exception_index = 0x080;
477
            break;
478
        case MMU_DTLB_VIOLATION_READ:
479
            env->exception_index = 0x0a0;
480
            break;
481
        case MMU_DTLB_VIOLATION_WRITE:
482
            env->exception_index = 0x0c0;
483
            break;
484
        case MMU_IADDR_ERROR:
485
        case MMU_DADDR_ERROR_READ:
486
            env->exception_index = 0x0e0;
487
            break;
488
        case MMU_DADDR_ERROR_WRITE:
489
            env->exception_index = 0x100;
490
            break;
491
        default:
492
            cpu_abort(env, "Unhandled MMU fault");
493
        }
494
        return 1;
495
    }
496

    
497
    address &= TARGET_PAGE_MASK;
498
    physical &= TARGET_PAGE_MASK;
499

    
500
    tlb_set_page(env, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
501
    return 0;
502
}
503

    
504
target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
505
{
506
    target_ulong physical;
507
    int prot;
508

    
509
    get_physical_address(env, &physical, &prot, addr, 0, 0);
510
    return physical;
511
}
512

    
513
void cpu_load_tlb(CPUSH4State * env)
514
{
515
    int n = cpu_mmucr_urc(env->mmucr);
516
    tlb_t * entry = &env->utlb[n];
517

    
518
    if (entry->v) {
519
        /* Overwriting valid entry in utlb. */
520
        target_ulong address = entry->vpn << 10;
521
        tlb_flush_page(env, address);
522
    }
523

    
524
    /* Take values into cpu status from registers. */
525
    entry->asid = (uint8_t)cpu_pteh_asid(env->pteh);
526
    entry->vpn  = cpu_pteh_vpn(env->pteh);
527
    entry->v    = (uint8_t)cpu_ptel_v(env->ptel);
528
    entry->ppn  = cpu_ptel_ppn(env->ptel);
529
    entry->sz   = (uint8_t)cpu_ptel_sz(env->ptel);
530
    switch (entry->sz) {
531
    case 0: /* 00 */
532
        entry->size = 1024; /* 1K */
533
        break;
534
    case 1: /* 01 */
535
        entry->size = 1024 * 4; /* 4K */
536
        break;
537
    case 2: /* 10 */
538
        entry->size = 1024 * 64; /* 64K */
539
        break;
540
    case 3: /* 11 */
541
        entry->size = 1024 * 1024; /* 1M */
542
        break;
543
    default:
544
        cpu_abort(env, "Unhandled load_tlb");
545
        break;
546
    }
547
    entry->sh   = (uint8_t)cpu_ptel_sh(env->ptel);
548
    entry->c    = (uint8_t)cpu_ptel_c(env->ptel);
549
    entry->pr   = (uint8_t)cpu_ptel_pr(env->ptel);
550
    entry->d    = (uint8_t)cpu_ptel_d(env->ptel);
551
    entry->wt   = (uint8_t)cpu_ptel_wt(env->ptel);
552
    entry->sa   = (uint8_t)cpu_ptea_sa(env->ptea);
553
    entry->tc   = (uint8_t)cpu_ptea_tc(env->ptea);
554
}
555

    
556
 void cpu_sh4_invalidate_tlb(CPUSH4State *s)
557
{
558
    int i;
559

    
560
    /* UTLB */
561
    for (i = 0; i < UTLB_SIZE; i++) {
562
        tlb_t * entry = &s->utlb[i];
563
        entry->v = 0;
564
    }
565
    /* ITLB */
566
    for (i = 0; i < ITLB_SIZE; i++) {
567
        tlb_t * entry = &s->itlb[i];
568
        entry->v = 0;
569
    }
570

    
571
    tlb_flush(s, 1);
572
}
573

    
574
uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s,
575
                                       target_phys_addr_t addr)
576
{
577
    int index = (addr & 0x00000300) >> 8;
578
    tlb_t * entry = &s->itlb[index];
579

    
580
    return (entry->vpn  << 10) |
581
           (entry->v    <<  8) |
582
           (entry->asid);
583
}
584

    
585
void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
586
                                    uint32_t mem_value)
587
{
588
    uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
589
    uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
590
    uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
591

    
592
    int index = (addr & 0x00000300) >> 8;
593
    tlb_t * entry = &s->itlb[index];
594
    if (entry->v) {
595
        /* Overwriting valid entry in itlb. */
596
        target_ulong address = entry->vpn << 10;
597
        tlb_flush_page(s, address);
598
    }
599
    entry->asid = asid;
600
    entry->vpn = vpn;
601
    entry->v = v;
602
}
603

    
604
uint32_t cpu_sh4_read_mmaped_itlb_data(CPUSH4State *s,
605
                                       target_phys_addr_t addr)
606
{
607
    int array = (addr & 0x00800000) >> 23;
608
    int index = (addr & 0x00000300) >> 8;
609
    tlb_t * entry = &s->itlb[index];
610

    
611
    if (array == 0) {
612
        /* ITLB Data Array 1 */
613
        return (entry->ppn << 10) |
614
               (entry->v   <<  8) |
615
               (entry->pr  <<  5) |
616
               ((entry->sz & 1) <<  6) |
617
               ((entry->sz & 2) <<  4) |
618
               (entry->c   <<  3) |
619
               (entry->sh  <<  1);
620
    } else {
621
        /* ITLB Data Array 2 */
622
        return (entry->tc << 1) |
623
               (entry->sa);
624
    }
625
}
626

    
627
void cpu_sh4_write_mmaped_itlb_data(CPUSH4State *s, target_phys_addr_t addr,
628
                                    uint32_t mem_value)
629
{
630
    int array = (addr & 0x00800000) >> 23;
631
    int index = (addr & 0x00000300) >> 8;
632
    tlb_t * entry = &s->itlb[index];
633

    
634
    if (array == 0) {
635
        /* ITLB Data Array 1 */
636
        if (entry->v) {
637
            /* Overwriting valid entry in utlb. */
638
            target_ulong address = entry->vpn << 10;
639
            tlb_flush_page(s, address);
640
        }
641
        entry->ppn = (mem_value & 0x1ffffc00) >> 10;
642
        entry->v   = (mem_value & 0x00000100) >> 8;
643
        entry->sz  = (mem_value & 0x00000080) >> 6 |
644
                     (mem_value & 0x00000010) >> 4;
645
        entry->pr  = (mem_value & 0x00000040) >> 5;
646
        entry->c   = (mem_value & 0x00000008) >> 3;
647
        entry->sh  = (mem_value & 0x00000002) >> 1;
648
    } else {
649
        /* ITLB Data Array 2 */
650
        entry->tc  = (mem_value & 0x00000008) >> 3;
651
        entry->sa  = (mem_value & 0x00000007);
652
    }
653
}
654

    
655
uint32_t cpu_sh4_read_mmaped_utlb_addr(CPUSH4State *s,
656
                                       target_phys_addr_t addr)
657
{
658
    int index = (addr & 0x00003f00) >> 8;
659
    tlb_t * entry = &s->utlb[index];
660

    
661
    increment_urc(s); /* per utlb access */
662

    
663
    return (entry->vpn  << 10) |
664
           (entry->v    <<  8) |
665
           (entry->asid);
666
}
667

    
668
void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
669
                                    uint32_t mem_value)
670
{
671
    int associate = addr & 0x0000080;
672
    uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
673
    uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9);
674
    uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
675
    uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
676
    int use_asid = (s->mmucr & MMUCR_SV) == 0 || (s->sr & SR_MD) == 0;
677

    
678
    if (associate) {
679
        int i;
680
        tlb_t * utlb_match_entry = NULL;
681
        int needs_tlb_flush = 0;
682

    
683
        /* search UTLB */
684
        for (i = 0; i < UTLB_SIZE; i++) {
685
            tlb_t * entry = &s->utlb[i];
686
            if (!entry->v)
687
                continue;
688

    
689
            if (entry->vpn == vpn
690
                && (!use_asid || entry->asid == asid || entry->sh)) {
691
                if (utlb_match_entry) {
692
                    /* Multiple TLB Exception */
693
                    s->exception_index = 0x140;
694
                    s->tea = addr;
695
                    break;
696
                }
697
                if (entry->v && !v)
698
                    needs_tlb_flush = 1;
699
                entry->v = v;
700
                entry->d = d;
701
                utlb_match_entry = entry;
702
            }
703
            increment_urc(s); /* per utlb access */
704
        }
705

    
706
        /* search ITLB */
707
        for (i = 0; i < ITLB_SIZE; i++) {
708
            tlb_t * entry = &s->itlb[i];
709
            if (entry->vpn == vpn
710
                && (!use_asid || entry->asid == asid || entry->sh)) {
711
                if (entry->v && !v)
712
                    needs_tlb_flush = 1;
713
                if (utlb_match_entry)
714
                    *entry = *utlb_match_entry;
715
                else
716
                    entry->v = v;
717
                break;
718
            }
719
        }
720

    
721
        if (needs_tlb_flush)
722
            tlb_flush_page(s, vpn << 10);
723
        
724
    } else {
725
        int index = (addr & 0x00003f00) >> 8;
726
        tlb_t * entry = &s->utlb[index];
727
        if (entry->v) {
728
            /* Overwriting valid entry in utlb. */
729
            target_ulong address = entry->vpn << 10;
730
            tlb_flush_page(s, address);
731
        }
732
        entry->asid = asid;
733
        entry->vpn = vpn;
734
        entry->d = d;
735
        entry->v = v;
736
        increment_urc(s);
737
    }
738
}
739

    
740
uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSH4State *s,
741
                                       target_phys_addr_t addr)
742
{
743
    int array = (addr & 0x00800000) >> 23;
744
    int index = (addr & 0x00003f00) >> 8;
745
    tlb_t * entry = &s->utlb[index];
746

    
747
    increment_urc(s); /* per utlb access */
748

    
749
    if (array == 0) {
750
        /* ITLB Data Array 1 */
751
        return (entry->ppn << 10) |
752
               (entry->v   <<  8) |
753
               (entry->pr  <<  5) |
754
               ((entry->sz & 1) <<  6) |
755
               ((entry->sz & 2) <<  4) |
756
               (entry->c   <<  3) |
757
               (entry->d   <<  2) |
758
               (entry->sh  <<  1) |
759
               (entry->wt);
760
    } else {
761
        /* ITLB Data Array 2 */
762
        return (entry->tc << 1) |
763
               (entry->sa);
764
    }
765
}
766

    
767
void cpu_sh4_write_mmaped_utlb_data(CPUSH4State *s, target_phys_addr_t addr,
768
                                    uint32_t mem_value)
769
{
770
    int array = (addr & 0x00800000) >> 23;
771
    int index = (addr & 0x00003f00) >> 8;
772
    tlb_t * entry = &s->utlb[index];
773

    
774
    increment_urc(s); /* per utlb access */
775

    
776
    if (array == 0) {
777
        /* UTLB Data Array 1 */
778
        if (entry->v) {
779
            /* Overwriting valid entry in utlb. */
780
            target_ulong address = entry->vpn << 10;
781
            tlb_flush_page(s, address);
782
        }
783
        entry->ppn = (mem_value & 0x1ffffc00) >> 10;
784
        entry->v   = (mem_value & 0x00000100) >> 8;
785
        entry->sz  = (mem_value & 0x00000080) >> 6 |
786
                     (mem_value & 0x00000010) >> 4;
787
        entry->pr  = (mem_value & 0x00000060) >> 5;
788
        entry->c   = (mem_value & 0x00000008) >> 3;
789
        entry->d   = (mem_value & 0x00000004) >> 2;
790
        entry->sh  = (mem_value & 0x00000002) >> 1;
791
        entry->wt  = (mem_value & 0x00000001);
792
    } else {
793
        /* UTLB Data Array 2 */
794
        entry->tc = (mem_value & 0x00000008) >> 3;
795
        entry->sa = (mem_value & 0x00000007);
796
    }
797
}
798

    
799
int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
800
{
801
    int n;
802
    int use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
803

    
804
    /* check area */
805
    if (env->sr & SR_MD) {
806
        /* For previledged mode, P2 and P4 area is not cachable. */
807
        if ((0xA0000000 <= addr && addr < 0xC0000000) || 0xE0000000 <= addr)
808
            return 0;
809
    } else {
810
        /* For user mode, only U0 area is cachable. */
811
        if (0x80000000 <= addr)
812
            return 0;
813
    }
814

    
815
    /*
816
     * TODO : Evaluate CCR and check if the cache is on or off.
817
     *        Now CCR is not in CPUSH4State, but in SH7750State.
818
     *        When you move the ccr inot CPUSH4State, the code will be
819
     *        as follows.
820
     */
821
#if 0
822
    /* check if operand cache is enabled or not. */
823
    if (!(env->ccr & 1))
824
        return 0;
825
#endif
826

    
827
    /* if MMU is off, no check for TLB. */
828
    if (env->mmucr & MMUCR_AT)
829
        return 1;
830

    
831
    /* check TLB */
832
    n = find_tlb_entry(env, addr, env->itlb, ITLB_SIZE, use_asid);
833
    if (n >= 0)
834
        return env->itlb[n].c;
835

    
836
    n = find_tlb_entry(env, addr, env->utlb, UTLB_SIZE, use_asid);
837
    if (n >= 0)
838
        return env->utlb[n].c;
839

    
840
    return 0;
841
}
842

    
843
#endif