Annotation of qemu/target-mips/op_helper.c, revision 1.1.1.4

1.1       root        1: /*
                      2:  *  MIPS emulation helpers for qemu.
                      3:  * 
                      4:  *  Copyright (c) 2004-2005 Jocelyn Mayer
                      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, write to the Free Software
                     18:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     19:  */
                     20: #include "exec.h"
                     21: 
                     22: #define MIPS_DEBUG_DISAS
                     23: 
1.1.1.2   root       24: #define GETPC() (__builtin_return_address(0))
                     25: 
1.1       root       26: /*****************************************************************************/
                     27: /* Exceptions processing helpers */
                     28: void cpu_loop_exit(void)
                     29: {
                     30:     longjmp(env->jmp_env, 1);
                     31: }
                     32: 
                     33: void do_raise_exception_err (uint32_t exception, int error_code)
                     34: {
                     35: #if 1
                     36:     if (logfile && exception < 0x100)
                     37:         fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
                     38: #endif
                     39:     env->exception_index = exception;
                     40:     env->error_code = error_code;
                     41:     T0 = 0;
                     42:     cpu_loop_exit();
                     43: }
                     44: 
                     45: void do_raise_exception (uint32_t exception)
                     46: {
                     47:     do_raise_exception_err(exception, 0);
                     48: }
                     49: 
1.1.1.2   root       50: void do_restore_state (void *pc_ptr)
                     51: {
                     52:   TranslationBlock *tb;
                     53:   unsigned long pc = (unsigned long) pc_ptr;
                     54: 
                     55:   tb = tb_find_pc (pc);
                     56:   cpu_restore_state (tb, env, pc, NULL);
                     57: }
                     58: 
                     59: void do_raise_exception_direct (uint32_t exception)
                     60: {
                     61:     do_restore_state (GETPC ());
                     62:     do_raise_exception_err (exception, 0);
                     63: }
                     64: 
1.1       root       65: #define MEMSUFFIX _raw
                     66: #include "op_helper_mem.c"
                     67: #undef MEMSUFFIX
                     68: #if !defined(CONFIG_USER_ONLY)
                     69: #define MEMSUFFIX _user
                     70: #include "op_helper_mem.c"
                     71: #undef MEMSUFFIX
                     72: #define MEMSUFFIX _kernel
                     73: #include "op_helper_mem.c"
                     74: #undef MEMSUFFIX
                     75: #endif
                     76: 
                     77: /* 64 bits arithmetic for 32 bits hosts */
                     78: #if (HOST_LONG_BITS == 32)
                     79: static inline uint64_t get_HILO (void)
                     80: {
                     81:     return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
                     82: }
                     83: 
                     84: static inline void set_HILO (uint64_t HILO)
                     85: {
                     86:     env->LO = HILO & 0xFFFFFFFF;
                     87:     env->HI = HILO >> 32;
                     88: }
                     89: 
                     90: void do_mult (void)
                     91: {
1.1.1.2   root       92:     set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
1.1       root       93: }
                     94: 
                     95: void do_multu (void)
                     96: {
                     97:     set_HILO((uint64_t)T0 * (uint64_t)T1);
                     98: }
                     99: 
                    100: void do_madd (void)
                    101: {
                    102:     int64_t tmp;
                    103: 
1.1.1.2   root      104:     tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
1.1       root      105:     set_HILO((int64_t)get_HILO() + tmp);
                    106: }
                    107: 
                    108: void do_maddu (void)
                    109: {
                    110:     uint64_t tmp;
                    111: 
                    112:     tmp = ((uint64_t)T0 * (uint64_t)T1);
                    113:     set_HILO(get_HILO() + tmp);
                    114: }
                    115: 
                    116: void do_msub (void)
                    117: {
                    118:     int64_t tmp;
                    119: 
1.1.1.2   root      120:     tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
1.1       root      121:     set_HILO((int64_t)get_HILO() - tmp);
                    122: }
                    123: 
                    124: void do_msubu (void)
                    125: {
                    126:     uint64_t tmp;
                    127: 
                    128:     tmp = ((uint64_t)T0 * (uint64_t)T1);
                    129:     set_HILO(get_HILO() - tmp);
                    130: }
                    131: #endif
                    132: 
1.1.1.2   root      133: #if defined(CONFIG_USER_ONLY) 
                    134: void do_mfc0 (int reg, int sel)
                    135: {
                    136:     cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel);
                    137: }
                    138: void do_mtc0 (int reg, int sel)
                    139: {
                    140:     cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
                    141: }
                    142: 
                    143: void do_tlbwi (void)
                    144: {
                    145:     cpu_abort(env, "tlbwi\n");
                    146: }
                    147: 
                    148: void do_tlbwr (void)
                    149: {
                    150:     cpu_abort(env, "tlbwr\n");
                    151: }
                    152: 
                    153: void do_tlbp (void)
                    154: {
                    155:     cpu_abort(env, "tlbp\n");
                    156: }
                    157: 
                    158: void do_tlbr (void)
                    159: {
                    160:     cpu_abort(env, "tlbr\n");
                    161: }
                    162: #else
                    163: 
1.1       root      164: /* CP0 helpers */
                    165: void do_mfc0 (int reg, int sel)
                    166: {
                    167:     const unsigned char *rn;
                    168: 
                    169:     if (sel != 0 && reg != 16 && reg != 28) {
                    170:         rn = "invalid";
                    171:         goto print;
                    172:     }
                    173:     switch (reg) {
                    174:     case 0:
                    175:         T0 = env->CP0_index;
                    176:         rn = "Index";
                    177:         break;
                    178:     case 1:
                    179:         T0 = cpu_mips_get_random(env);
                    180:         rn = "Random";
                    181:         break;
                    182:     case 2:
                    183:         T0 = env->CP0_EntryLo0;
                    184:         rn = "EntryLo0";
                    185:         break;
                    186:     case 3:
                    187:         T0 = env->CP0_EntryLo1;
                    188:         rn = "EntryLo1";
                    189:         break;
                    190:     case 4:
                    191:         T0 = env->CP0_Context;
                    192:         rn = "Context";
                    193:         break;
                    194:     case 5:
                    195:         T0 = env->CP0_PageMask;
                    196:         rn = "PageMask";
                    197:         break;
                    198:     case 6:
                    199:         T0 = env->CP0_Wired;
                    200:         rn = "Wired";
                    201:         break;
                    202:     case 8:
                    203:         T0 = env->CP0_BadVAddr;
                    204:         rn = "BadVaddr";
                    205:         break;
                    206:     case 9:
                    207:         T0 = cpu_mips_get_count(env);
                    208:         rn = "Count";
                    209:         break;
                    210:     case 10:
                    211:         T0 = env->CP0_EntryHi;
                    212:         rn = "EntryHi";
                    213:         break;
                    214:     case 11:
                    215:         T0 = env->CP0_Compare;
                    216:         rn = "Compare";
                    217:         break;
                    218:     case 12:
                    219:         T0 = env->CP0_Status;
                    220:         if (env->hflags & MIPS_HFLAG_UM)
                    221:             T0 |= (1 << CP0St_UM);
                    222:         rn = "Status";
                    223:         break;
                    224:     case 13:
                    225:         T0 = env->CP0_Cause;
                    226:         rn = "Cause";
                    227:         break;
                    228:     case 14:
                    229:         T0 = env->CP0_EPC;
                    230:         rn = "EPC";
                    231:         break;
                    232:     case 15:
                    233:         T0 = env->CP0_PRid;
                    234:         rn = "PRid";
                    235:         break;
                    236:     case 16:
                    237:         switch (sel) {
                    238:         case 0:
                    239:             T0 = env->CP0_Config0;
                    240:             rn = "Config";
                    241:             break;
                    242:         case 1:
                    243:             T0 = env->CP0_Config1;
                    244:             rn = "Config1";
                    245:             break;
                    246:         default:
                    247:             rn = "Unknown config register";
                    248:             break;
                    249:         }
                    250:         break;
                    251:     case 17:
                    252:         T0 = env->CP0_LLAddr >> 4;
                    253:         rn = "LLAddr";
                    254:         break;
                    255:     case 18:
                    256:         T0 = env->CP0_WatchLo;
                    257:         rn = "WatchLo";
                    258:         break;
                    259:     case 19:
                    260:         T0 = env->CP0_WatchHi;
                    261:         rn = "WatchHi";
                    262:         break;
                    263:     case 23:
                    264:         T0 = env->CP0_Debug;
                    265:         if (env->hflags & MIPS_HFLAG_DM)
                    266:             T0 |= 1 << CP0DB_DM;
                    267:         rn = "Debug";
                    268:         break;
                    269:     case 24:
                    270:         T0 = env->CP0_DEPC;
                    271:         rn = "DEPC";
                    272:         break;
                    273:     case 28:
                    274:         switch (sel) {
                    275:         case 0:
                    276:             T0 = env->CP0_TagLo;
                    277:             rn = "TagLo";
                    278:             break;
                    279:         case 1:
                    280:             T0 = env->CP0_DataLo;
                    281:             rn = "DataLo";
                    282:             break;
                    283:         default:
                    284:             rn = "unknown sel";
                    285:             break;
                    286:         }
                    287:         break;
                    288:     case 30:
                    289:         T0 = env->CP0_ErrorEPC;
                    290:         rn = "ErrorEPC";
                    291:         break;
                    292:     case 31:
                    293:         T0 = env->CP0_DESAVE;
                    294:         rn = "DESAVE";
                    295:         break;
                    296:     default:
                    297:         rn = "unknown";
                    298:         break;
                    299:     }
                    300:  print:
                    301: #if defined MIPS_DEBUG_DISAS
                    302:     if (loglevel & CPU_LOG_TB_IN_ASM) {
                    303:         fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
                    304:                 env->PC, rn, T0, reg, sel);
                    305:     }
                    306: #endif
                    307:     return;
                    308: }
                    309: 
                    310: void do_mtc0 (int reg, int sel)
                    311: {
                    312:     const unsigned char *rn;
                    313:     uint32_t val, old, mask;
                    314: 
                    315:     if (sel != 0 && reg != 16 && reg != 28) {
                    316:         val = -1;
                    317:         old = -1;
                    318:         rn = "invalid";
                    319:         goto print;
                    320:     }
                    321:     switch (reg) {
                    322:     case 0:
                    323:         val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
                    324:         old = env->CP0_index;
                    325:         env->CP0_index = val;
                    326:         rn = "Index";
                    327:         break;
                    328:     case 2:
1.1.1.4 ! root      329:         val = T0 & 0x3FFFFFFF;
1.1       root      330:         old = env->CP0_EntryLo0;
                    331:         env->CP0_EntryLo0 = val;
                    332:         rn = "EntryLo0";
                    333:         break;
                    334:     case 3:
1.1.1.4 ! root      335:         val = T0 & 0x3FFFFFFF;
1.1       root      336:         old = env->CP0_EntryLo1;
                    337:         env->CP0_EntryLo1 = val;
                    338:         rn = "EntryLo1";
                    339:         break;
                    340:     case 4:
1.1.1.4 ! root      341:         val = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0);
1.1       root      342:         old = env->CP0_Context;
                    343:         env->CP0_Context = val;
                    344:         rn = "Context";
                    345:         break;
                    346:     case 5:
                    347:         val = T0 & 0x01FFE000;
                    348:         old = env->CP0_PageMask;
                    349:         env->CP0_PageMask = val;
                    350:         rn = "PageMask";
                    351:         break;
                    352:     case 6:
                    353:         val = T0 & 0x0000000F;
                    354:         old = env->CP0_Wired;
                    355:         env->CP0_Wired = val;
                    356:         rn = "Wired";
                    357:         break;
                    358:     case 9:
                    359:         val = T0;
                    360:         old = cpu_mips_get_count(env);
                    361:         cpu_mips_store_count(env, val);
                    362:         rn = "Count";
                    363:         break;
                    364:     case 10:
1.1.1.4 ! root      365:         val = T0 & 0xFFFFE0FF;
1.1       root      366:         old = env->CP0_EntryHi;
                    367:         env->CP0_EntryHi = val;
1.1.1.2   root      368:        /* If the ASID changes, flush qemu's TLB.  */
                    369:        if ((old & 0xFF) != (val & 0xFF))
                    370:          tlb_flush (env, 1);
1.1       root      371:         rn = "EntryHi";
                    372:         break;
                    373:     case 11:
                    374:         val = T0;
                    375:         old = env->CP0_Compare;
                    376:         cpu_mips_store_compare(env, val);
                    377:         rn = "Compare";
                    378:         break;
                    379:     case 12:
                    380:         val = T0 & 0xFA78FF01;
                    381:         if (T0 & (1 << CP0St_UM))
                    382:             env->hflags |= MIPS_HFLAG_UM;
                    383:         else
                    384:             env->hflags &= ~MIPS_HFLAG_UM;
                    385:         if (T0 & (1 << CP0St_ERL))
                    386:             env->hflags |= MIPS_HFLAG_ERL;
                    387:         else
                    388:             env->hflags &= ~MIPS_HFLAG_ERL;
                    389:         if (T0 & (1 << CP0St_EXL))
                    390:             env->hflags |= MIPS_HFLAG_EXL;
                    391:         else
                    392:             env->hflags &= ~MIPS_HFLAG_EXL;
                    393:         old = env->CP0_Status;
                    394:         env->CP0_Status = val;
                    395:         /* If we unmasked an asserted IRQ, raise it */
                    396:         mask = 0x0000FF00;
                    397:         if (loglevel & CPU_LOG_TB_IN_ASM) {
                    398:             fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
                    399:                     old, val, env->CP0_Cause, old & mask, val & mask,
                    400:                     env->CP0_Cause & mask);
                    401:         }
                    402:         if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
                    403:             !(env->hflags & MIPS_HFLAG_EXL) &&
                    404:             !(env->hflags & MIPS_HFLAG_ERL) &&
1.1.1.4 ! root      405:             !(env->hflags & MIPS_HFLAG_DM) &&
1.1       root      406:             (env->CP0_Status & env->CP0_Cause & mask)) {
                    407:             if (logfile)
                    408:                 fprintf(logfile, "Raise pending IRQs\n");
                    409:             env->interrupt_request |= CPU_INTERRUPT_HARD;
1.1.1.4 ! root      410:         } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
1.1       root      411:             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
                    412:         }
                    413:         rn = "Status";
                    414:         break;
                    415:     case 13:
                    416:         val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
                    417:         old = env->CP0_Cause;
                    418:         env->CP0_Cause = val;
                    419: #if 0
                    420:         {
                    421:             int i;
                    422:             /* Check if we ever asserted a software IRQ */
                    423:             for (i = 0; i < 2; i++) {
                    424:                 mask = 0x100 << i;
                    425:                 if ((val & mask) & !(old & mask))
                    426:                     mips_set_irq(i);
                    427:             }
                    428:         }
                    429: #endif
                    430:         rn = "Cause";
                    431:         break;
                    432:     case 14:
                    433:         val = T0;
                    434:         old = env->CP0_EPC;
                    435:         env->CP0_EPC = val;
                    436:         rn = "EPC";
                    437:         break;
                    438:     case 16:
                    439:         switch (sel) {
                    440:         case 0:
                    441: #if defined(MIPS_USES_R4K_TLB)
                    442:             val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
                    443: #else
                    444:             val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
                    445: #endif
                    446:             old = env->CP0_Config0;
                    447:             env->CP0_Config0 = val;
                    448:             rn = "Config0";
                    449:             break;
                    450:         default:
                    451:             val = -1;
                    452:             old = -1;
                    453:             rn = "bad config selector";
                    454:             break;
                    455:         }
                    456:         break;
                    457:     case 18:
                    458:         val = T0;
                    459:         old = env->CP0_WatchLo;
                    460:         env->CP0_WatchLo = val;
                    461:         rn = "WatchLo";
                    462:         break;
                    463:     case 19:
                    464:         val = T0 & 0x40FF0FF8;
                    465:         old = env->CP0_WatchHi;
                    466:         env->CP0_WatchHi = val;
                    467:         rn = "WatchHi";
                    468:         break;
                    469:     case 23:
                    470:         val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
                    471:         if (T0 & (1 << CP0DB_DM))
                    472:             env->hflags |= MIPS_HFLAG_DM;
                    473:         else
                    474:             env->hflags &= ~MIPS_HFLAG_DM;
                    475:         old = env->CP0_Debug;
                    476:         env->CP0_Debug = val;
                    477:         rn = "Debug";
                    478:         break;
                    479:     case 24:
                    480:         val = T0;
                    481:         old = env->CP0_DEPC;
                    482:         env->CP0_DEPC = val;
                    483:         rn = "DEPC";
                    484:         break;
                    485:     case 28:
                    486:         switch (sel) {
                    487:         case 0:
                    488:             val = T0 & 0xFFFFFCF6;
                    489:             old = env->CP0_TagLo;
                    490:             env->CP0_TagLo = val;
                    491:             rn = "TagLo";
                    492:             break;
                    493:         default:
                    494:             val = -1;
                    495:             old = -1;
                    496:             rn = "invalid sel";
                    497:             break;
                    498:         }
                    499:         break;
                    500:     case 30:
                    501:         val = T0;
                    502:         old = env->CP0_ErrorEPC;
                    503:         env->CP0_ErrorEPC = val;
                    504:         rn = "EPC";
                    505:         break;
                    506:     case 31:
                    507:         val = T0;
                    508:         old = env->CP0_DESAVE;
                    509:         env->CP0_DESAVE = val;
                    510:         rn = "DESAVE";
                    511:         break;
                    512:     default:
                    513:         val = -1;
                    514:         old = -1;
                    515:         rn = "unknown";
                    516:         break;
                    517:     }
                    518:  print:
                    519: #if defined MIPS_DEBUG_DISAS
                    520:     if (loglevel & CPU_LOG_TB_IN_ASM) {
                    521:         fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
                    522:                 env->PC, rn, T0, val, reg, sel, old);
                    523:     }
                    524: #endif
                    525:     return;
                    526: }
                    527: 
1.1.1.4 ! root      528: #ifdef MIPS_USES_FPU
        !           529: #include "softfloat.h"
        !           530: 
        !           531: void fpu_handle_exception(void)
        !           532: {
        !           533: #ifdef CONFIG_SOFTFLOAT
        !           534:     int flags = get_float_exception_flags(&env->fp_status);
        !           535:     unsigned int cpuflags = 0, enable, cause = 0;
        !           536: 
        !           537:     enable = GET_FP_ENABLE(env->fcr31);
        !           538: 
        !           539:     /* determine current flags */   
        !           540:     if (flags & float_flag_invalid) {
        !           541:         cpuflags |= FP_INVALID;
        !           542:         cause |= FP_INVALID & enable;
        !           543:     }
        !           544:     if (flags & float_flag_divbyzero) {
        !           545:         cpuflags |= FP_DIV0;    
        !           546:         cause |= FP_DIV0 & enable;
        !           547:     }
        !           548:     if (flags & float_flag_overflow) {
        !           549:         cpuflags |= FP_OVERFLOW;    
        !           550:         cause |= FP_OVERFLOW & enable;
        !           551:     }
        !           552:     if (flags & float_flag_underflow) {
        !           553:         cpuflags |= FP_UNDERFLOW;   
        !           554:         cause |= FP_UNDERFLOW & enable;
        !           555:     }
        !           556:     if (flags & float_flag_inexact) {
        !           557:         cpuflags |= FP_INEXACT; 
        !           558:         cause |= FP_INEXACT & enable;
        !           559:     }
        !           560:     SET_FP_FLAGS(env->fcr31, cpuflags);
        !           561:     SET_FP_CAUSE(env->fcr31, cause);
        !           562: #else
        !           563:     SET_FP_FLAGS(env->fcr31, 0);
        !           564:     SET_FP_CAUSE(env->fcr31, 0);
        !           565: #endif
        !           566: }
        !           567: #endif /* MIPS_USES_FPU */
        !           568: 
1.1       root      569: /* TLB management */
                    570: #if defined(MIPS_USES_R4K_TLB)
1.1.1.3   root      571: static void invalidate_tlb (int idx)
1.1       root      572: {
                    573:     tlb_t *tlb;
1.1.1.3   root      574:     target_ulong addr;
1.1       root      575: 
                    576:     tlb = &env->tlb[idx];
1.1.1.3   root      577:     if (tlb->V0) {
                    578:         tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN);
1.1.1.2   root      579:         addr = tlb->VPN;
                    580:         while (addr < tlb->end) {
                    581:             tlb_flush_page (env, addr);
                    582:             addr += TARGET_PAGE_SIZE;
                    583:         }
1.1       root      584:     }
1.1.1.3   root      585:     if (tlb->V1) {
                    586:         tb_invalidate_page_range(tlb->PFN[1], tlb->end2 - tlb->end);
1.1.1.2   root      587:         addr = tlb->end;
                    588:         while (addr < tlb->end2) {
                    589:             tlb_flush_page (env, addr);
                    590:             addr += TARGET_PAGE_SIZE;
                    591:         }
1.1       root      592:     }
                    593: }
                    594: 
1.1.1.3   root      595: static void fill_tlb (int idx)
1.1       root      596: {
                    597:     tlb_t *tlb;
                    598:     int size;
                    599: 
                    600:     /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
                    601:     tlb = &env->tlb[idx];
                    602:     tlb->VPN = env->CP0_EntryHi & 0xFFFFE000;
1.1.1.3   root      603:     tlb->ASID = env->CP0_EntryHi & 0xFF;
1.1       root      604:     size = env->CP0_PageMask >> 13;
                    605:     size = 4 * (size + 1);
                    606:     tlb->end = tlb->VPN + (1 << (8 + size));
1.1.1.2   root      607:     tlb->end2 = tlb->end + (1 << (8 + size));
1.1       root      608:     tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1.1.1.3   root      609:     tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
                    610:     tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
                    611:     tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
1.1       root      612:     tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1.1.1.3   root      613:     tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
                    614:     tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
                    615:     tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
1.1       root      616:     tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
                    617: }
                    618: 
                    619: void do_tlbwi (void)
                    620: {
                    621:     /* Wildly undefined effects for CP0_index containing a too high value and
                    622:        MIPS_TLB_NB not being a power of two.  But so does real silicon.  */
1.1.1.3   root      623:     invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1));
                    624:     fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1));
1.1       root      625: }
                    626: 
                    627: void do_tlbwr (void)
                    628: {
                    629:     int r = cpu_mips_get_random(env);
                    630: 
1.1.1.3   root      631:     invalidate_tlb(r);
                    632:     fill_tlb(r);
1.1       root      633: }
                    634: 
                    635: void do_tlbp (void)
                    636: {
                    637:     tlb_t *tlb;
                    638:     target_ulong tag;
                    639:     uint8_t ASID;
                    640:     int i;
                    641: 
1.1.1.4 ! root      642:     tag = env->CP0_EntryHi & 0xFFFFE000;
        !           643:     ASID = env->CP0_EntryHi & 0xFF;
        !           644:     for (i = 0; i < MIPS_TLB_NB; i++) {
1.1       root      645:         tlb = &env->tlb[i];
                    646:         /* Check ASID, virtual page number & size */
                    647:         if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
                    648:             /* TLB match */
                    649:             env->CP0_index = i;
                    650:             break;
                    651:         }
                    652:     }
                    653:     if (i == MIPS_TLB_NB) {
                    654:         env->CP0_index |= 0x80000000;
                    655:     }
                    656: }
                    657: 
                    658: void do_tlbr (void)
                    659: {
                    660:     tlb_t *tlb;
1.1.1.3   root      661:     uint8_t ASID;
1.1       root      662:     int size;
                    663: 
1.1.1.3   root      664:     ASID = env->CP0_EntryHi & 0xFF;
1.1       root      665:     tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)];
1.1.1.2   root      666: 
                    667:     /* If this will change the current ASID, flush qemu's TLB.  */
1.1.1.3   root      668:     if (ASID != tlb->ASID && tlb->G != 1)
1.1.1.2   root      669:       tlb_flush (env, 1);
                    670: 
1.1       root      671:     env->CP0_EntryHi = tlb->VPN | tlb->ASID;
                    672:     size = (tlb->end - tlb->VPN) >> 12;
                    673:     env->CP0_PageMask = (size - 1) << 13;
1.1.1.3   root      674:     env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2)
                    675:                | (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
                    676:     env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2)
                    677:                | (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
1.1       root      678: }
                    679: #endif
                    680: 
1.1.1.2   root      681: #endif /* !CONFIG_USER_ONLY */
                    682: 
1.1       root      683: void op_dump_ldst (const unsigned char *func)
                    684: {
                    685:     if (loglevel)
                    686:         fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
                    687: }
                    688: 
                    689: void dump_sc (void)
                    690: {
                    691:     if (loglevel) {
                    692:         fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
                    693:                 T1, T0, env->CP0_LLAddr);
                    694:     }
                    695: }
                    696: 
                    697: void debug_eret (void)
                    698: {
                    699:     if (loglevel) {
                    700:         fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
                    701:                 env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
                    702:                 env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
                    703:     }
                    704: }
                    705: 
                    706: void do_pmon (int function)
                    707: {
                    708:     function /= 2;
                    709:     switch (function) {
                    710:     case 2: /* TODO: char inbyte(int waitflag); */
                    711:         if (env->gpr[4] == 0)
                    712:             env->gpr[2] = -1;
                    713:         /* Fall through */
                    714:     case 11: /* TODO: char inbyte (void); */
                    715:         env->gpr[2] = -1;
                    716:         break;
                    717:     case 3:
                    718:     case 12:
                    719:         printf("%c", env->gpr[4] & 0xFF);
                    720:         break;
                    721:     case 17:
                    722:         break;
                    723:     case 158:
                    724:         {
                    725:             unsigned char *fmt = (void *)env->gpr[4];
                    726:             printf("%s", fmt);
                    727:         }
                    728:         break;
                    729:     }
                    730: }
                    731: 
                    732: #if !defined(CONFIG_USER_ONLY) 
                    733: 
1.1.1.2   root      734: static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
                    735: 
1.1       root      736: #define MMUSUFFIX _mmu
1.1.1.2   root      737: #define ALIGNED_ONLY
1.1       root      738: 
                    739: #define SHIFT 0
                    740: #include "softmmu_template.h"
                    741: 
                    742: #define SHIFT 1
                    743: #include "softmmu_template.h"
                    744: 
                    745: #define SHIFT 2
                    746: #include "softmmu_template.h"
                    747: 
                    748: #define SHIFT 3
                    749: #include "softmmu_template.h"
                    750: 
1.1.1.2   root      751: static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
                    752: {
                    753:     env->CP0_BadVAddr = addr;
                    754:     do_restore_state (retaddr);
                    755:     do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
                    756: }
                    757: 
1.1       root      758: void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
                    759: {
                    760:     TranslationBlock *tb;
                    761:     CPUState *saved_env;
                    762:     unsigned long pc;
                    763:     int ret;
                    764: 
                    765:     /* XXX: hack to restore env in all cases, even if not called from
                    766:        generated code */
                    767:     saved_env = env;
                    768:     env = cpu_single_env;
                    769:     ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1);
                    770:     if (ret) {
                    771:         if (retaddr) {
                    772:             /* now we have a real cpu fault */
                    773:             pc = (unsigned long)retaddr;
                    774:             tb = tb_find_pc(pc);
                    775:             if (tb) {
                    776:                 /* the PC is inside the translated code. It means that we have
                    777:                    a virtual CPU fault */
                    778:                 cpu_restore_state(tb, env, pc, NULL);
                    779:             }
                    780:         }
                    781:         do_raise_exception_err(env->exception_index, env->error_code);
                    782:     }
                    783:     env = saved_env;
                    784: }
                    785: 
                    786: #endif

unix.superglobalmegacorp.com

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