Annotation of qemu/target-sh4/helper.c, revision 1.1.1.11

1.1       root        1: /*
                      2:  *  SH4 emulation
1.1.1.3   root        3:  *
1.1       root        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
1.1.1.5   root       17:  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1.1       root       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"
1.1.1.11! root       27: 
        !            28: #if !defined(CONFIG_USER_ONLY)
1.1.1.3   root       29: #include "hw/sh_intc.h"
1.1.1.11! root       30: #endif
1.1       root       31: 
1.1.1.2   root       32: #if defined(CONFIG_USER_ONLY)
                     33: 
1.1.1.11! root       34: void do_interrupt (CPUSH4State *env)
1.1.1.2   root       35: {
                     36:   env->exception_index = -1;
                     37: }
                     38: 
1.1.1.11! root       39: int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
1.1.1.10  root       40:                              int mmu_idx)
1.1.1.2   root       41: {
                     42:     env->tea = address;
1.1.1.7   root       43:     env->exception_index = -1;
1.1.1.2   root       44:     switch (rw) {
                     45:     case 0:
                     46:         env->exception_index = 0x0a0;
                     47:         break;
                     48:     case 1:
                     49:         env->exception_index = 0x0c0;
                     50:         break;
1.1.1.4   root       51:     case 2:
                     52:         env->exception_index = 0x0a0;
                     53:         break;
1.1.1.2   root       54:     }
                     55:     return 1;
                     56: }
                     57: 
1.1.1.5   root       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: 
1.1.1.2   root       64: #else /* !CONFIG_USER_ONLY */
                     65: 
1.1       root       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)
1.1.1.4   root       77: #define MMU_IADDR_ERROR          (-11)
                     78: #define MMU_DADDR_ERROR_READ     (-12)
                     79: #define MMU_DADDR_ERROR_WRITE    (-13)
1.1       root       80: 
1.1.1.11! root       81: void do_interrupt(CPUSH4State * env)
1.1       root       82: {
1.1.1.3   root       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:         }
1.1.1.9   root       95:         if (do_irq && !env->in_sleep) {
1.1.1.3   root       96:             return; /* masked */
                     97:         }
                     98:     }
1.1.1.9   root       99:     env->in_sleep = 0;
1.1.1.3   root      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: 
1.1.1.4   root      109:     if (qemu_loglevel_mask(CPU_LOG_INT)) {
1.1       root      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:
1.1.1.3   root      152:             expname = do_irq ? "interrupt" : "???";
                    153:             break;
1.1       root      154:        }
1.1.1.4   root      155:        qemu_log("exception 0x%03x [%s] raised\n",
                    156:                  irq_vector, expname);
                    157:        log_cpu_state(env, 0);
1.1       root      158:     }
                    159: 
                    160:     env->ssr = env->sr;
1.1.1.3   root      161:     env->spc = env->pc;
1.1       root      162:     env->sgr = env->gregs[15];
                    163:     env->sr |= SR_BL | SR_MD | SR_RB;
                    164: 
1.1.1.4   root      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: 
1.1.1.3   root      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;
1.1       root      202:     }
                    203: }
                    204: 
1.1.1.11! root      205: static void update_itlb_use(CPUSH4State * env, int itlbnb)
1.1       root      206: {
                    207:     uint8_t or_mask = 0, and_mask = (uint8_t) - 1;
                    208: 
                    209:     switch (itlbnb) {
                    210:     case 0:
1.1.1.4   root      211:        and_mask = 0x1f;
1.1       root      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: 
1.1.1.4   root      226:     env->mmucr &= (and_mask << 24) | 0x00ffffff;
1.1       root      227:     env->mmucr |= (or_mask << 24);
                    228: }
                    229: 
1.1.1.11! root      230: static int itlb_replacement(CPUSH4State * env)
1.1       root      231: {
                    232:     if ((env->mmucr & 0xe0000000) == 0xe0000000)
                    233:        return 0;
1.1.1.4   root      234:     if ((env->mmucr & 0x98000000) == 0x18000000)
1.1       root      235:        return 1;
                    236:     if ((env->mmucr & 0x54000000) == 0x04000000)
                    237:        return 2;
                    238:     if ((env->mmucr & 0x2c000000) == 0x00000000)
                    239:        return 3;
1.1.1.7   root      240:     cpu_abort(env, "Unhandled itlb_replacement");
1.1       root      241: }
                    242: 
                    243: /* Find the corresponding entry in the right TLB
                    244:    Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE
                    245: */
1.1.1.11! root      246: static int find_tlb_entry(CPUSH4State * env, target_ulong address,
1.1       root      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 */
1.1.1.4   root      259:        if (!entries[i].sh && use_asid && entries[i].asid != asid)
1.1       root      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 */
1.1.1.4   root      264:            if (match != MMU_DTLB_MISS)
1.1       root      265:                return MMU_DTLB_MULTIPLE;       /* Multiple match */
                    266:            match = i;
                    267:        }
                    268:     }
                    269:     return match;
                    270: }
                    271: 
1.1.1.11! root      272: static void increment_urc(CPUSH4State * env)
1.1.1.4   root      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: 
1.1.1.8   root      285: /* Copy and utlb entry into itlb
                    286:    Return entry
                    287: */
1.1.1.11! root      288: static int copy_utlb_entry_itlb(CPUSH4State *env, int utlb)
1.1.1.8   root      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
1.1       root      304:    Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
                    305: */
1.1.1.11! root      306: static int find_itlb_entry(CPUSH4State * env, target_ulong address,
1.1.1.8   root      307:                            int use_asid)
1.1       root      308: {
1.1.1.8   root      309:     int e;
1.1       root      310: 
                    311:     e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid);
1.1.1.8   root      312:     if (e == MMU_DTLB_MULTIPLE) {
1.1       root      313:        e = MMU_ITLB_MULTIPLE;
1.1.1.8   root      314:     } else if (e == MMU_DTLB_MISS) {
1.1.1.4   root      315:        e = MMU_ITLB_MISS;
1.1.1.8   root      316:     } else if (e >= 0) {
1.1       root      317:        update_itlb_use(env, e);
1.1.1.8   root      318:     }
1.1       root      319:     return e;
                    320: }
                    321: 
                    322: /* Find utlb entry
                    323:    Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */
1.1.1.11! root      324: static int find_utlb_entry(CPUSH4State * env, target_ulong address, int use_asid)
1.1       root      325: {
1.1.1.4   root      326:     /* per utlb access */
                    327:     increment_urc(env);
1.1       root      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,
1.1.1.4   root      337:    MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION,
                    338:    MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE.
1.1       root      339: */
1.1.1.11! root      340: static int get_mmu_address(CPUSH4State * env, target_ulong * physical,
1.1       root      341:                           int *prot, target_ulong address,
                    342:                           int rw, int access_type)
                    343: {
1.1.1.4   root      344:     int use_asid, n;
1.1       root      345:     tlb_t *matching = NULL;
                    346: 
1.1.1.4   root      347:     use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
1.1       root      348: 
1.1.1.4   root      349:     if (rw == 2) {
1.1.1.8   root      350:         n = find_itlb_entry(env, address, use_asid);
1.1       root      351:        if (n >= 0) {
                    352:            matching = &env->itlb[n];
1.1.1.6   root      353:            if (!(env->sr & SR_MD) && !(matching->pr & 2))
1.1       root      354:                n = MMU_ITLB_VIOLATION;
                    355:            else
1.1.1.7   root      356:                *prot = PAGE_EXEC;
1.1.1.8   root      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:             }
1.1       root      375:        }
                    376:     } else {
                    377:        n = find_utlb_entry(env, address, use_asid);
                    378:        if (n >= 0) {
                    379:            matching = &env->utlb[n];
1.1.1.7   root      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;
1.1.1.8   root      385:             } else if ((rw == 1) && !matching->d) {
1.1.1.7   root      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:             }
1.1       root      393:        } else if (n == MMU_DTLB_MISS) {
1.1.1.4   root      394:            n = (rw == 1) ? MMU_DTLB_MISS_WRITE :
1.1       root      395:                MMU_DTLB_MISS_READ;
                    396:        }
                    397:     }
                    398:     if (n >= 0) {
1.1.1.7   root      399:        n = MMU_OK;
1.1       root      400:        *physical = ((matching->ppn << 10) & ~(matching->size - 1)) |
                    401:            (address & (matching->size - 1));
                    402:     }
                    403:     return n;
                    404: }
                    405: 
1.1.1.11! root      406: static int get_physical_address(CPUSH4State * env, target_ulong * physical,
1.1.1.4   root      407:                                 int *prot, target_ulong address,
                    408:                                 int rw, int access_type)
1.1       root      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)
1.1.1.6   root      414:            && (address < 0xe0000000 || address >= 0xe4000000)) {
1.1       root      415:            /* Unauthorized access in user mode (only store queues are available) */
                    416:            fprintf(stderr, "Unauthorized access\n");
1.1.1.4   root      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;
1.1       root      429:        }
1.1.1.7   root      430:        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1.1       root      431:        return MMU_OK;
                    432:     }
                    433: 
                    434:     /* If MMU is disabled, return the corresponding physical page */
1.1.1.8   root      435:     if (!(env->mmucr & MMUCR_AT)) {
1.1       root      436:        *physical = address & 0x1FFFFFFF;
1.1.1.7   root      437:        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1.1       root      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: 
1.1.1.11! root      445: int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
1.1.1.10  root      446:                              int mmu_idx)
1.1       root      447: {
1.1.1.7   root      448:     target_ulong physical;
1.1       root      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;
1.1.1.8   root      458:        if (ret != MMU_DTLB_MULTIPLE && ret != MMU_ITLB_MULTIPLE) {
                    459:            env->pteh = (env->pteh & PTEH_ASID_MASK) |
                    460:                    (address & PTEH_VPN_MASK);
                    461:        }
1.1       root      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;
1.1.1.4   root      486:        case MMU_IADDR_ERROR:
                    487:        case MMU_DADDR_ERROR_READ:
1.1.1.8   root      488:            env->exception_index = 0x0e0;
1.1.1.4   root      489:            break;
                    490:        case MMU_DADDR_ERROR_WRITE:
                    491:            env->exception_index = 0x100;
                    492:            break;
1.1       root      493:        default:
1.1.1.7   root      494:             cpu_abort(env, "Unhandled MMU fault");
1.1       root      495:        }
                    496:        return 1;
                    497:     }
                    498: 
1.1.1.7   root      499:     address &= TARGET_PAGE_MASK;
                    500:     physical &= TARGET_PAGE_MASK;
1.1       root      501: 
1.1.1.7   root      502:     tlb_set_page(env, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
                    503:     return 0;
1.1       root      504: }
1.1.1.2   root      505: 
1.1.1.11! root      506: target_phys_addr_t cpu_get_phys_page_debug(CPUSH4State * env, target_ulong addr)
1.1.1.2   root      507: {
                    508:     target_ulong physical;
                    509:     int prot;
                    510: 
1.1.1.4   root      511:     get_physical_address(env, &physical, &prot, addr, 0, 0);
1.1.1.2   root      512:     return physical;
                    513: }
                    514: 
1.1.1.4   root      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;
1.1.1.7   root      523:        tlb_flush_page(env, address);
1.1.1.4   root      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:
1.1.1.7   root      546:         cpu_abort(env, "Unhandled load_tlb");
1.1.1.4   root      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: 
1.1.1.6   root      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 */
1.1.1.8   root      568:     for (i = 0; i < ITLB_SIZE; i++) {
                    569:         tlb_t * entry = &s->itlb[i];
1.1.1.6   root      570:         entry->v = 0;
                    571:     }
                    572: 
                    573:     tlb_flush(s, 1);
                    574: }
                    575: 
1.1.1.8   root      576: uint32_t cpu_sh4_read_mmaped_itlb_addr(CPUSH4State *s,
                    577:                                        target_phys_addr_t 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, target_phys_addr_t 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:                                        target_phys_addr_t 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, target_phys_addr_t 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:                                        target_phys_addr_t 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: 
1.1.1.4   root      670: void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t 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;
1.1.1.7   root      732:            tlb_flush_page(s, address);
1.1.1.4   root      733:        }
                    734:        entry->asid = asid;
                    735:        entry->vpn = vpn;
                    736:        entry->d = d;
                    737:        entry->v = v;
                    738:        increment_urc(s);
                    739:     }
                    740: }
                    741: 
1.1.1.8   root      742: uint32_t cpu_sh4_read_mmaped_utlb_data(CPUSH4State *s,
                    743:                                        target_phys_addr_t 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, target_phys_addr_t 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: 
1.1.1.5   root      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.
1.1.1.11! root      820:      *        When you move the ccr into CPUSH4State, the code will be
1.1.1.5   root      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: 
1.1.1.2   root      845: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.