Statistics
| Branch: | Revision:

root / target-sh4 / helper.c @ a8170e5e

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

    
28
#if !defined(CONFIG_USER_ONLY)
29
#include "hw/sh_intc.h"
30
#endif
31

    
32
#if defined(CONFIG_USER_ONLY)
33

    
34
void do_interrupt (CPUSH4State *env)
35
{
36
  env->exception_index = -1;
37
}
38

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

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

    
64
#else /* !CONFIG_USER_ONLY */
65

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

    
81
void do_interrupt(CPUSH4State * env)
82
{
83
    int do_irq = env->interrupt_request & CPU_INTERRUPT_HARD;
84
    int do_exp, irq_vector = env->exception_index;
85

    
86
    /* prioritize exceptions over interrupts */
87

    
88
    do_exp = env->exception_index != -1;
89
    do_irq = do_irq && (env->exception_index == -1);
90

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

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

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

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

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

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

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

    
205
static void update_itlb_use(CPUSH4State * env, int itlbnb)
206
{
207
    uint8_t or_mask = 0, and_mask = (uint8_t) - 1;
208

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

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

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

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

    
254
    asid = env->pteh & 0xff;
255

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

    
272
static void increment_urc(CPUSH4State * env)
273
{
274
    uint8_t urb, urc;
275

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

    
285
/* Copy and utlb entry into itlb
286
   Return entry
287
*/
288
static int copy_utlb_entry_itlb(CPUSH4State *env, int utlb)
289
{
290
    int itlb;
291

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

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

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

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

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

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

    
347
    use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
348

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

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

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

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

    
445
int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
446
                             int mmu_idx)
447
{
448
    target_ulong physical;
449
    int prot, ret, access_type;
450

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

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

    
499
    address &= TARGET_PAGE_MASK;
500
    physical &= TARGET_PAGE_MASK;
501

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

    
506
hwaddr cpu_get_phys_page_debug(CPUSH4State * env, target_ulong addr)
507
{
508
    target_ulong physical;
509
    int prot;
510

    
511
    get_physical_address(env, &physical, &prot, addr, 0, 0);
512
    return physical;
513
}
514

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

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

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

    
558
 void cpu_sh4_invalidate_tlb(CPUSH4State *s)
559
{
560
    int i;
561

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

    
573
    tlb_flush(s, 1);
574
}
575

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

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

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

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

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

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

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

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

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

    
663
    increment_urc(s); /* per utlb access */
664

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

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

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

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

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

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

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

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

    
749
    increment_urc(s); /* per utlb access */
750

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

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

    
776
    increment_urc(s); /* per utlb access */
777

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

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

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

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

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

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

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

    
842
    return 0;
843
}
844

    
845
#endif