simplified PowerPC exception handling (Jocelyn Mayer)
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 2 Jul 2005 22:09:27 +0000 (22:09 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 2 Jul 2005 22:09:27 +0000 (22:09 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1492 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-defs.h
linux-user/main.c
target-ppc/cpu.h
target-ppc/helper.c
target-ppc/op.c
target-ppc/op_helper.c
target-ppc/translate.c

index c58d271..83d1748 100644 (file)
@@ -68,9 +68,9 @@ typedef uint64_t target_phys_addr_t;
 
 #define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
 
-#define EXCP_INTERRUPT         256 /* async interruption */
-#define EXCP_HLT        257 /* hlt instruction reached */
-#define EXCP_DEBUG      258 /* cpu stopped after a breakpoint or singlestep */
+#define EXCP_INTERRUPT         0x10000 /* async interruption */
+#define EXCP_HLT        0x10001 /* hlt instruction reached */
+#define EXCP_DEBUG      0x10002 /* cpu stopped after a breakpoint or singlestep */
 
 #define MAX_BREAKPOINTS 32
 
index d8fd0e4..856147f 100644 (file)
@@ -706,28 +706,22 @@ void cpu_loop(CPUPPCState *env)
                 fprintf(logfile, "Invalid data memory access: 0x%08x\n",
                         env->spr[SPR_DAR]);
             }
-            switch (env->error_code & 0xF) {
-            case EXCP_DSI_TRANSLATE:
+            switch (env->error_code & 0xFF000000) {
+            case 0x40000000:
                 info.si_signo = TARGET_SIGSEGV;
                 info.si_errno = 0;
                 info.si_code = TARGET_SEGV_MAPERR;
                 break;
-            case EXCP_DSI_NOTSUP:
-            case EXCP_DSI_EXTERNAL:
+            case 0x04000000:
                 info.si_signo = TARGET_SIGILL;
                 info.si_errno = 0;
                 info.si_code = TARGET_ILL_ILLADR;
                 break;
-            case EXCP_DSI_PROT: 
+            case 0x08000000:
                 info.si_signo = TARGET_SIGSEGV;
                 info.si_errno = 0;
                 info.si_code = TARGET_SEGV_ACCERR;
                 break;
-            case EXCP_DSI_DABR:
-                info.si_signo = TARGET_SIGTRAP;
-                info.si_errno = 0;
-                info.si_code = TARGET_TRAP_BRKPT;
-                break;
             default:
                 /* Let's send a regular segfault... */
                 fprintf(stderr, "Invalid segfault errno (%02x)\n",
@@ -748,19 +742,14 @@ void cpu_loop(CPUPPCState *env)
             fprintf(stderr, "Invalid instruction fetch\n");
             if (loglevel)
                 fprintf(logfile, "Invalid instruction fetch\n");
-            switch (env->error_code) {
-            case EXCP_ISI_TRANSLATE:
+            switch (env->error_code & 0xFF000000) {
+            case 0x40000000:
                 info.si_signo = TARGET_SIGSEGV;
             info.si_errno = 0;
                 info.si_code = TARGET_SEGV_MAPERR;
                 break;
-            case EXCP_ISI_GUARD:
-                info.si_signo = TARGET_SIGILL;
-                info.si_errno = 0;
-                info.si_code = TARGET_ILL_ILLADR;
-                break;
-            case EXCP_ISI_NOEXEC:
-            case EXCP_ISI_PROT:
+            case 0x10000000:
+            case 0x08000000:
                 info.si_signo = TARGET_SIGSEGV;
                 info.si_errno = 0;
                 info.si_code = TARGET_SEGV_ACCERR;
@@ -930,18 +919,6 @@ void cpu_loop(CPUPPCState *env)
             if (loglevel)
                 fprintf(logfile, "Decrementer exception\n");
             abort();
-        case EXCP_RESA: /* Implementation specific          */
-            /* Should not happen ! */
-            fprintf(stderr, "RESA exception should never happen !\n");
-            if (loglevel)
-                fprintf(logfile, "RESA exception should never happen !\n");
-            abort();
-        case EXCP_RESB: /* Implementation specific          */
-            /* Should not happen ! */
-            fprintf(stderr, "RESB exception should never happen !\n");
-            if (loglevel)
-                fprintf(logfile, "RESB exception should never happen !\n");
-            abort();
         case EXCP_TRACE:
             /* Do nothing: we use this to trace execution */
             break;
@@ -963,12 +940,6 @@ void cpu_loop(CPUPPCState *env)
         case EXCP_BRANCH:
             /* We stopped because of a jump... */
             break;
-        case EXCP_RFI:
-            /* Should not occur: we always are in user mode */
-            fprintf(stderr, "Return from interrupt ?\n");
-            if (loglevel)
-                fprintf(logfile, "Return from interrupt ?\n");
-            abort();
         case EXCP_INTERRUPT:
             /* Don't know why this should ever happen... */
             break;
index a7b4051..7fc7943 100644 (file)
@@ -924,62 +924,72 @@ enum {
 
 /*****************************************************************************/
 /* Exceptions */
-enum {
-    EXCP_NONE          = -1,
-    /* PowerPC hardware exceptions : exception vector / 0x100 */
-    EXCP_RESET         = 0x01, /* System reset                     */
-    EXCP_MACHINE_CHECK = 0x02, /* Machine check exception          */
-    EXCP_DSI           = 0x03, /* Impossible memory access         */
-    EXCP_ISI           = 0x04, /* Impossible instruction fetch     */
-    EXCP_EXTERNAL      = 0x05, /* External interruption            */
-    EXCP_ALIGN         = 0x06, /* Alignment exception              */
-    EXCP_PROGRAM       = 0x07, /* Program exception                */
-    EXCP_NO_FP         = 0x08, /* No floating point                */
-    EXCP_DECR          = 0x09, /* Decrementer exception            */
-    EXCP_RESA          = 0x0A, /* Implementation specific          */
-    EXCP_RESB          = 0x0B, /* Implementation specific          */
-    EXCP_SYSCALL       = 0x0C, /* System call                      */
-    EXCP_TRACE         = 0x0D, /* Trace exception (optional)       */
-    EXCP_FP_ASSIST     = 0x0E, /* Floating-point assist (optional) */
-    /* MPC740/745/750 & IBM 750 */
-    EXCP_PERF          = 0x0F,  /* Performance monitor              */
-    EXCP_IABR          = 0x13,  /* Instruction address breakpoint   */
-    EXCP_SMI           = 0x14,  /* System management interrupt      */
-    EXCP_THRM          = 0x15,  /* Thermal management interrupt     */
-    /* MPC755 */
-    EXCP_TLBMISS       = 0x10,  /* Instruction TLB miss             */
-    EXCP_TLBMISS_DL    = 0x11,  /* Data TLB miss for load           */
-    EXCP_TLBMISS_DS    = 0x12,  /* Data TLB miss for store          */
-    EXCP_PPC_MAX       = 0x16,
-    /* Qemu exception */
-    EXCP_OFCALL        = 0x20,  /* Call open-firmware emulator      */
-    EXCP_RTASCALL      = 0x21,  /* Call RTAS emulator               */
-    /* Special cases where we want to stop translation */
-    EXCP_MTMSR         = 0x104, /* mtmsr instruction:               */
+#define EXCP_NONE          -1
+/* PowerPC hardware exceptions : exception vectors defined in PowerPC book 3 */
+#define EXCP_RESET         0x0100 /* System reset                            */
+#define EXCP_MACHINE_CHECK 0x0200 /* Machine check exception                 */
+#define EXCP_DSI           0x0300 /* Data storage exception                  */
+#define EXCP_DSEG          0x0380 /* Data segment exception                  */
+#define EXCP_ISI           0x0400 /* Instruction storage exception           */
+#define EXCP_ISEG          0x0480 /* Instruction segment exception           */
+#define EXCP_EXTERNAL      0x0500 /* External interruption                   */
+#define EXCP_ALIGN         0x0600 /* Alignment exception                     */
+#define EXCP_PROGRAM       0x0700 /* Program exception                       */
+#define EXCP_NO_FP         0x0800 /* Floating point unavailable exception    */
+#define EXCP_DECR          0x0900 /* Decrementer exception                   */
+#define EXCP_HDECR         0x0980 /* Hypervisor decrementer exception        */
+#define EXCP_SYSCALL       0x0C00 /* System call                             */
+#define EXCP_TRACE         0x0D00 /* Trace exception                         */
+#define EXCP_PERF          0x0F00 /* Performance monitor exception           */
+/* Exceptions defined in PowerPC 32 bits programming environment manual      */
+#define EXCP_FP_ASSIST     0x0E00 /* Floating-point assist                   */
+/* Implementation specific exceptions                                        */
+/* 40x exceptions                                                            */
+#define EXCP_40x_PIT       0x1000 /* Programmable interval timer interrupt   */
+#define EXCP_40x_FIT       0x1010 /* Fixed interval timer interrupt          */
+#define EXCP_40x_WATCHDOG  0x1020 /* Watchdog timer exception                */
+#define EXCP_40x_DTLBMISS  0x1100 /* Data TLB miss exception                 */
+#define EXCP_40x_ITLBMISS  0x1200 /* Instruction TLB miss exception          */
+#define EXCP_40x_DEBUG     0x2000 /* Debug exception                         */
+/* 405 specific exceptions                                                   */
+#define EXCP_405_APU       0x0F20 /* APU unavailable exception               */
+/* TLB assist exceptions (602/603)                                           */
+#define EXCP_I_TLBMISS     0x1000 /* Instruction TLB miss                    */
+#define EXCP_DL_TLBMISS    0x1100 /* Data load TLB miss                      */
+#define EXCP_DS_TLBMISS    0x1200 /* Data store TLB miss                     */
+/* Breakpoint exceptions (602/603/604/620/740/745/750/755...)                */
+#define EXCP_IABR          0x1300 /* Instruction address breakpoint          */
+#define EXCP_SMI           0x1400 /* System management interrupt             */
+/* Altivec related exceptions                                                */
+#define EXCP_VPU           0x0F20 /* VPU unavailable exception               */
+/* 601 specific exceptions                                                   */
+#define EXCP_601_IO        0x0600 /* IO error exception                      */
+#define EXCP_601_RUNM      0x2000 /* Run mode exception                      */
+/* 602 specific exceptions                                                   */
+#define EXCP_602_WATCHDOG  0x1500 /* Watchdog exception                      */
+#define EXCP_602_EMUL      0x1600 /* Emulation trap exception                */
+/* G2 specific exceptions                                                    */
+#define EXCP_G2_CRIT       0x0A00 /* Critical interrupt                      */
+/* MPC740/745/750 & IBM 750 specific exceptions                              */
+#define EXCP_THRM          0x1700 /* Thermal management interrupt            */
+/* 74xx specific exceptions                                                  */
+#define EXCP_74xx_VPUA     0x1600 /* VPU assist exception                    */
+/* 970FX specific exceptions                                                 */
+#define EXCP_970_SOFTP     0x1500 /* Soft patch exception                    */
+#define EXCP_970_MAINT     0x1600 /* Maintenance exception                   */
+#define EXCP_970_THRM      0x1800 /* Thermal exception                       */
+#define EXCP_970_VPUA      0x1700 /* VPU assist exception                    */
+/* End of exception vectors area                                             */
+#define EXCP_PPC_MAX       0x4000
+/* Qemu exceptions: special cases we want to stop translation                */
+#define EXCP_MTMSR         0x11000 /* mtmsr instruction:                     */
                                 /* may change privilege level       */
-    EXCP_BRANCH        = 0x108, /* branch instruction               */
-    EXCP_RFI           = 0x10C, /* return from interrupt            */
-    EXCP_SYSCALL_USER  = 0x110, /* System call in user mode only    */
-};
+#define EXCP_BRANCH        0x11001 /* branch instruction                     */
+#define EXCP_SYSCALL_USER  0x12000 /* System call in user mode only          */
+#define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ                      */
+
 /* Error codes */
 enum {
-    /* Exception subtypes for EXCP_DSI                              */
-    EXCP_DSI_TRANSLATE = 0x01,  /* Data address can't be translated */
-    EXCP_DSI_NOTSUP    = 0x02,  /* Access type not supported        */
-    EXCP_DSI_PROT      = 0x03,  /* Memory protection violation      */
-    EXCP_DSI_EXTERNAL  = 0x04,  /* External access disabled         */
-    EXCP_DSI_DABR      = 0x05,  /* Data address breakpoint          */
-    /* flags for EXCP_DSI */
-    EXCP_DSI_DIRECT    = 0x10,
-    EXCP_DSI_STORE     = 0x20,
-    EXCP_DSI_ECXW      = 0x40,
-    /* Exception subtypes for EXCP_ISI                              */
-    EXCP_ISI_TRANSLATE = 0x01,  /* Code address can't be translated */
-    EXCP_ISI_NOEXEC    = 0x02,  /* Try to fetch from a data segment */
-    EXCP_ISI_GUARD     = 0x03,  /* Fetch from guarded memory        */
-    EXCP_ISI_PROT      = 0x04,  /* Memory protection violation      */
-    EXCP_ISI_DIRECT    = 0x05,  /* Trying to fetch from             *
-                                * a direct store segment           */
     /* Exception subtypes for EXCP_ALIGN                            */
     EXCP_ALIGN_FP      = 0x01,  /* FP alignment exception           */
     EXCP_ALIGN_LST     = 0x02,  /* Unaligned mult/extern load/store */
index 6ddc0f4..fbecb76 100644 (file)
@@ -22,8 +22,6 @@
 //#define DEBUG_MMU
 //#define DEBUG_BATS
 //#define DEBUG_EXCEPTIONS
-/* accurate but slower TLB flush in exceptions */
-//#define ACCURATE_TLB_FLUSH
 
 /*****************************************************************************/
 /* PowerPC MMU emulation */
@@ -524,20 +522,25 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
             switch (ret) {
             case -1:
                 /* No matches in page tables */
-                error_code = EXCP_ISI_TRANSLATE;
+                error_code = 0x40000000;
                 break;
             case -2:
                 /* Access rights violation */
-                error_code = EXCP_ISI_PROT;
+                error_code = 0x08000000;
                 break;
             case -3:
                /* No execute protection violation */
-                error_code = EXCP_ISI_NOEXEC;
+                error_code = 0x10000000;
                 break;
             case -4:
                 /* Direct store exception */
                 /* No code fetch is allowed in direct-store areas */
-                error_code = EXCP_ISI_DIRECT;
+                error_code = 0x10000000;
+                break;
+            case -5:
+                /* No match in segment table */
+                exception = EXCP_ISEG;
+                error_code = 0;
                 break;
             }
         } else {
@@ -545,11 +548,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
             switch (ret) {
             case -1:
                 /* No matches in page tables */
-                error_code = EXCP_DSI_TRANSLATE;
+                error_code = 0x40000000;
                 break;
             case -2:
                 /* Access rights violation */
-                error_code = EXCP_DSI_PROT;
+                error_code = 0x08000000;
                 break;
             case -4:
                 /* Direct store exception */
@@ -561,14 +564,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
                     break;
                 case ACCESS_RES:
                     /* lwarx, ldarx or srwcx. */
-                    exception = EXCP_DSI;
-                    error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT;
+                    error_code = 0x04000000;
                     break;
                 case ACCESS_EXT:
                     /* eciwx or ecowx */
-                    exception = EXCP_DSI;
-                    error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT |
-                       EXCP_DSI_ECXW;
+                    error_code = 0x04100000;
                     break;
                 default:
                    printf("DSI: invalid exception (%d)\n", ret);
@@ -576,11 +576,17 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
                     error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
                     break;
                 }
+            case -5:
+                /* No match in segment table */
+                exception = EXCP_DSEG;
+                error_code = 0;
+                break;
             }
             if (rw)
-                error_code |= EXCP_DSI_STORE;
+                error_code |= 0x02000000;
            /* Store fault address */
            env->spr[SPR_DAR] = address;
+            env->spr[SPR_DSISR] = error_code;
         }
 #if 0
         printf("%s: set exception to %d %02x\n",
@@ -985,119 +991,107 @@ static void dump_syscall(CPUState *env)
 
 void do_interrupt (CPUState *env)
 {
-    uint32_t msr;
+    target_ulong msr, *srr_0, *srr_1, tmp;
     int excp;
 
     excp = env->exception_index;
     msr = do_load_msr(env);
+    /* The default is to use SRR0 & SRR1 to save the exception context */
+    srr_0 = &env->spr[SPR_SRR0];
+    srr_1 = &env->spr[SPR_SRR1];
 #if defined (DEBUG_EXCEPTIONS)
-    if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) 
-    {
-        if (loglevel > 0) {
-            fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n",
-                    env->nip, excp << 8, env->error_code);
+    if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) {
+        if (loglevel != 0) {
+            fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n",
+                    (unsigned long)env->nip, excp, env->error_code);
+           cpu_dump_state(env, logfile, fprintf, 0);
         }
-       if (loglevel > 0)
-           cpu_dump_state(env, logfile, fprintf, 0);
     }
 #endif
     if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n",
-                env->nip, excp << 8, env->error_code);
+        fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n",
+                (unsigned long)env->nip, excp, env->error_code);
     }
+    msr_pow = 0;
     /* Generate informations in save/restore registers */
     switch (excp) {
-    case EXCP_NONE:
-        /* Do nothing */
-#if defined (DEBUG_EXCEPTIONS)
-        printf("%s: escape EXCP_NONE\n", __func__);
-#endif
-        return;
-    case EXCP_RESET:
-        if (msr_ip)
-            excp += 0xFFC00;
+        /* Generic PowerPC exceptions */
+    case EXCP_RESET: /* 0x0100 */
+        if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) {
+            if (msr_ip)
+                excp += 0xFFC00;
+            excp |= 0xFFC00000;
+        } else {
+            srr_0 = &env->spr[SPR_40x_SRR2];
+            srr_1 = &env->spr[SPR_40x_SRR3];
+        }
         goto store_next;
-    case EXCP_MACHINE_CHECK:
+    case EXCP_MACHINE_CHECK: /* 0x0200 */
         if (msr_me == 0) {
             cpu_abort(env, "Machine check exception while not allowed\n");
         }
+        if (PPC_EXCP(env) == PPC_FLAGS_EXCP_40x) {
+            srr_0 = &env->spr[SPR_40x_SRR2];
+            srr_1 = &env->spr[SPR_40x_SRR3];
+        }
         msr_me = 0;
         break;
-    case EXCP_DSI:
+    case EXCP_DSI: /* 0x0300 */
         /* Store exception cause */
         /* data location address has been stored
          * when the fault has been detected
-     */
+         */
        msr &= ~0xFFFF0000;
-       env->spr[SPR_DSISR] = 0;
-       if ((env->error_code & 0x0f) ==  EXCP_DSI_TRANSLATE)
-           env->spr[SPR_DSISR] |= 0x40000000;
-       else if ((env->error_code & 0x0f) ==  EXCP_DSI_PROT)
-           env->spr[SPR_DSISR] |= 0x08000000;
-       else if ((env->error_code & 0x0f) ==  EXCP_DSI_NOTSUP) {
-           env->spr[SPR_DSISR] |= 0x80000000;
-           if (env->error_code & EXCP_DSI_DIRECT)
-               env->spr[SPR_DSISR] |= 0x04000000;
-       }
-       if (env->error_code & EXCP_DSI_STORE)
-           env->spr[SPR_DSISR] |= 0x02000000;
-       if ((env->error_code & 0xF) == EXCP_DSI_DABR)
-           env->spr[SPR_DSISR] |= 0x00400000;
-       if (env->error_code & EXCP_DSI_ECXW)
-           env->spr[SPR_DSISR] |= 0x00100000;
 #if defined (DEBUG_EXCEPTIONS)
        if (loglevel) {
            fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
                    env->spr[SPR_DSISR], env->spr[SPR_DAR]);
        } else {
-           printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n",
-                  env->spr[SPR_DSISR], env->spr[SPR_DAR], env->nip);
+           printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
+                  env->spr[SPR_DSISR], env->spr[SPR_DAR]);
        }
 #endif
         goto store_next;
-    case EXCP_ISI:
+    case EXCP_ISI: /* 0x0400 */
         /* Store exception cause */
        msr &= ~0xFFFF0000;
-        if (env->error_code == EXCP_ISI_TRANSLATE)
-            msr |= 0x40000000;
-        else if (env->error_code == EXCP_ISI_NOEXEC ||
-                env->error_code == EXCP_ISI_GUARD ||
-                env->error_code == EXCP_ISI_DIRECT)
-            msr |= 0x10000000;
-        else
-            msr |= 0x08000000;
+        msr |= env->error_code;
 #if defined (DEBUG_EXCEPTIONS)
-       if (loglevel) {
+       if (loglevel != 0) {
            fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n",
                    msr, env->nip);
-       } else {
-           printf("ISI exception: msr=0x%08x, nip=0x%08x tbl:0x%08x\n",
-                  msr, env->nip, env->spr[V_TBL]);
        }
 #endif
         goto store_next;
-    case EXCP_EXTERNAL:
+    case EXCP_EXTERNAL: /* 0x0500 */
         if (msr_ee == 0) {
 #if defined (DEBUG_EXCEPTIONS)
             if (loglevel > 0) {
                 fprintf(logfile, "Skipping hardware interrupt\n");
-    }
+            }
 #endif
             /* Requeue it */
-            do_raise_exception(EXCP_EXTERNAL);
+            env->interrupt_request |= CPU_INTERRUPT_HARD;
             return;
-            }
+        }
         goto store_next;
-    case EXCP_ALIGN:
-        /* Store exception cause */
-        /* Get rS/rD and rA from faulting opcode */
-        env->spr[SPR_DSISR] |=
-            (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
-        /* data location address has been stored
-         * when the fault has been detected
-         */
+    case EXCP_ALIGN: /* 0x0600 */
+        if (PPC_EXCP(env) != PPC_FLAGS_EXCP_601) {
+            /* Store exception cause */
+            /* Get rS/rD and rA from faulting opcode */
+            env->spr[SPR_DSISR] |=
+                (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
+            /* data location address has been stored
+             * when the fault has been detected
+             */
+        } else {
+            /* IO error exception on PowerPC 601 */
+            /* XXX: TODO */
+            cpu_abort(env,
+                      "601 IO error exception is not implemented yet !\n");
+        }
         goto store_current;
-    case EXCP_PROGRAM:
+    case EXCP_PROGRAM: /* 0x0700 */
         msr &= ~0xFFFF0000;
         switch (env->error_code & ~0xF) {
         case EXCP_FP:
@@ -1131,17 +1125,19 @@ void do_interrupt (CPUState *env)
     }
         msr |= 0x00010000;
         goto store_current;
-    case EXCP_NO_FP:
+    case EXCP_NO_FP: /* 0x0800 */
         msr &= ~0xFFFF0000;
         goto store_current;
     case EXCP_DECR:
         if (msr_ee == 0) {
+#if 1
             /* Requeue it */
-            do_raise_exception(EXCP_DECR);
+            env->interrupt_request |= CPU_INTERRUPT_TIMER;
+#endif
             return;
         }
         goto store_next;
-    case EXCP_SYSCALL:
+    case EXCP_SYSCALL: /* 0x0C00 */
         /* NOTE: this is a temporary hack to support graphics OSI
            calls from the MOL driver */
         if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
@@ -1153,35 +1149,332 @@ void do_interrupt (CPUState *env)
             dump_syscall(env);
         }
         goto store_next;
-    case EXCP_TRACE:
+    case EXCP_TRACE: /* 0x0D00 */
+        /* XXX: TODO */
+        cpu_abort(env, "Trace exception is not implemented yet !\n");
+        goto store_next;
+    case EXCP_PERF: /* 0x0F00 */
+        /* XXX: TODO */
+        cpu_abort(env,
+                  "Performance counter exception is not implemented yet !\n");
+        goto store_next;
+    /* 32 bits PowerPC specific exceptions */
+    case EXCP_FP_ASSIST: /* 0x0E00 */
+        /* XXX: TODO */
+        cpu_abort(env, "Floating point assist exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    /* 64 bits PowerPC exceptions */
+    case EXCP_DSEG: /* 0x0380 */
+        /* XXX: TODO */
+        cpu_abort(env, "Data segment exception is not implemented yet !\n");
         goto store_next;
-    case EXCP_FP_ASSIST:
+    case EXCP_ISEG: /* 0x0480 */
+        /* XXX: TODO */
+        cpu_abort(env,
+                  "Instruction segment exception is not implemented yet !\n");
         goto store_next;
-    case EXCP_MTMSR:
-        /* Nothing to do */
+    case EXCP_HDECR: /* 0x0980 */
+        if (msr_ee == 0) {
+#if 1
+            /* Requeue it */
+            env->interrupt_request |= CPU_INTERRUPT_TIMER;
+#endif
         return;
-    case EXCP_BRANCH:
-        /* Nothing to do */
+        }
+        cpu_abort(env,
+                  "Hypervisor decrementer exception is not implemented yet !\n");
+        goto store_next;
+    /* Implementation specific exceptions */
+    case 0x0A00:
+        if (PPC_EXCP(env) != PPC_FLAGS_EXCP_602) {
+            /* Critical interrupt on G2 */
+            /* XXX: TODO */
+            cpu_abort(env, "G2 critical interrupt is not implemented yet !\n");
+            goto store_next;
+        } else {
+            cpu_abort(env, "Invalid exception 0x0A00 !\n");
+        }
         return;
-    case EXCP_RFI:
-        /* Restore user-mode state */
-#if defined (DEBUG_EXCEPTIONS)
-       if (msr_pr == 1)
-           printf("Return from exception => 0x%08x\n", (uint32_t)env->nip);
+    case 0x0F20:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_40x:
+            /* APU unavailable on 405 */
+            /* XXX: TODO */
+            cpu_abort(env,
+                      "APU unavailable exception is not implemented yet !\n");
+            goto store_next;
+        case PPC_FLAGS_EXCP_74xx:
+            /* Altivec unavailable */
+            /* XXX: TODO */
+            cpu_abort(env, "Altivec unavailable exception "
+                      "is not implemented yet !\n");
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x0F20 !\n");
+            break;
+        }
+        return;
+    case 0x1000:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_40x:
+            /* PIT on 4xx */
+            /* XXX: TODO */
+            cpu_abort(env, "40x PIT exception is not implemented yet !\n");
+            goto store_next;
+        case PPC_FLAGS_EXCP_602:
+        case PPC_FLAGS_EXCP_603:
+            /* ITLBMISS on 602/603 */
+            msr &= ~0xF00F0000;
+            msr_tgpr = 1;
+            goto store_gprs;
+        default:
+            cpu_abort(env, "Invalid exception 0x1000 !\n");
+            break;
+        }
+        return;
+    case 0x1010:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_40x:
+            /* FIT on 4xx */
+            cpu_abort(env, "40x FIT exception is not implemented yet !\n");
+            /* XXX: TODO */
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x1010 !\n");
+            break;
+        }
+        return;
+    case 0x1020:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_40x:
+            /* Watchdog on 4xx */
+            /* XXX: TODO */
+            cpu_abort(env,
+                      "40x watchdog exception is not implemented yet !\n");
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x1020 !\n");
+            break;
+        }
+        return;
+    case 0x1100:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_40x:
+            /* DTLBMISS on 4xx */
+            /* XXX: TODO */
+            cpu_abort(env,
+                      "40x DTLBMISS exception is not implemented yet !\n");
+            goto store_next;
+        case PPC_FLAGS_EXCP_602:
+        case PPC_FLAGS_EXCP_603:
+            /* DLTLBMISS on 602/603 */
+            msr &= ~0xF00F0000;
+            msr_tgpr = 1;
+            goto store_gprs;
+        default:
+            cpu_abort(env, "Invalid exception 0x1100 !\n");
+            break;
+        }
+        return;
+    case 0x1200:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_40x:
+            /* ITLBMISS on 4xx */
+            /* XXX: TODO */
+            cpu_abort(env,
+                      "40x ITLBMISS exception is not implemented yet !\n");
+            goto store_next;
+        case PPC_FLAGS_EXCP_602:
+        case PPC_FLAGS_EXCP_603:
+            /* DSTLBMISS on 602/603 */
+            msr &= ~0xF00F0000;
+            msr_tgpr = 1;
+        store_gprs:
+#if defined (DEBUG_SOFTWARE_TLB)
+            if (loglevel != 0) {
+                fprintf(logfile, "6xx %sTLB miss: IM %08x DM %08x IC %08x "
+                        "DC %08x H1 %08x H2 %08x %08x\n",
+                        excp == 0x1000 ? "I" : excp == 0x1100 ? "DL" : "DS",
+                        env->spr[SPR_IMISS], env->spr[SPR_DMISS],
+                        env->spr[SPR_ICMP], env->spr[SPR_DCMP],
+                        env->spr[SPR_DHASH1], env->spr[SPR_DHASH2],
+                        env->error_code);
+            }
 #endif
+            /* Swap temporary saved registers with GPRs */
+            tmp = env->gpr[0];
+            env->gpr[0] = env->tgpr[0];
+            env->tgpr[0] = tmp;
+            tmp = env->gpr[1];
+            env->gpr[1] = env->tgpr[1];
+            env->tgpr[1] = tmp;
+            tmp = env->gpr[2];
+            env->gpr[2] = env->tgpr[2];
+            env->tgpr[2] = tmp;
+            tmp = env->gpr[3];
+            env->gpr[3] = env->tgpr[3];
+            env->tgpr[3] = tmp;
+            msr |= env->crf[0] << 28;
+            msr |= env->error_code; /* key, D/I, S/L bits */
+            /* Set way using a LRU mechanism */
+            msr |= (env->last_way ^ 1) << 17;
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x1200 !\n");
+            break;
+        }
+        return;
+    case 0x1300:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_601:
+        case PPC_FLAGS_EXCP_602:
+        case PPC_FLAGS_EXCP_603:
+        case PPC_FLAGS_EXCP_604:
+        case PPC_FLAGS_EXCP_7x0:
+        case PPC_FLAGS_EXCP_7x5:
+            /* IABR on 6xx/7xx */
+            /* XXX: TODO */
+            cpu_abort(env, "IABR exception is not implemented yet !\n");
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x1300 !\n");
+            break;
+        }
+        return;
+    case 0x1400:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_601:
+        case PPC_FLAGS_EXCP_602:
+        case PPC_FLAGS_EXCP_603:
+        case PPC_FLAGS_EXCP_604:
+        case PPC_FLAGS_EXCP_7x0:
+        case PPC_FLAGS_EXCP_7x5:
+            /* SMI on 6xx/7xx */
+            /* XXX: TODO */
+            cpu_abort(env, "SMI exception is not implemented yet !\n");
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x1400 !\n");
+            break;
+        }
+        return;
+    case 0x1500:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_602:
+            /* Watchdog on 602 */
+            cpu_abort(env,
+                      "602 watchdog exception is not implemented yet !\n");
+            goto store_next;
+        case PPC_FLAGS_EXCP_970:
+            /* Soft patch exception on 970 */
+            /* XXX: TODO */
+            cpu_abort(env,
+                      "970 soft-patch exception is not implemented yet !\n");
+            goto store_next;
+        case PPC_FLAGS_EXCP_74xx:
+            /* VPU assist on 74xx */
+            /* XXX: TODO */
+            cpu_abort(env, "VPU assist exception is not implemented yet !\n");
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x1500 !\n");
+            break;
+        }
+        return;
+    case 0x1600:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_602:
+            /* Emulation trap on 602 */
+            /* XXX: TODO */
+            cpu_abort(env, "602 emulation trap exception "
+                      "is not implemented yet !\n");
+            goto store_next;
+        case PPC_FLAGS_EXCP_970:
+            /* Maintenance exception on 970 */
+            /* XXX: TODO */
+            cpu_abort(env,
+                      "970 maintenance exception is not implemented yet !\n");
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x1600 !\n");
+            break;
+        }
+        return;
+    case 0x1700:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_7x0:
+        case PPC_FLAGS_EXCP_7x5:
+            /* Thermal management interrupt on G3 */
+            /* XXX: TODO */
+            cpu_abort(env, "G3 thermal management exception "
+                      "is not implemented yet !\n");
+            goto store_next;
+        case PPC_FLAGS_EXCP_970:
+            /* VPU assist on 970 */
+            /* XXX: TODO */
+            cpu_abort(env,
+                      "970 VPU assist exception is not implemented yet !\n");
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x1700 !\n");
+            break;
+        }
+        return;
+    case 0x1800:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_970:
+            /* Thermal exception on 970 */
+            /* XXX: TODO */
+            cpu_abort(env, "970 thermal management exception "
+                      "is not implemented yet !\n");
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x1800 !\n");
+            break;
+        }
+        return;
+    case 0x2000:
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_40x:
+            /* DEBUG on 4xx */
+            /* XXX: TODO */
+            cpu_abort(env, "40x debug exception is not implemented yet !\n");
+            goto store_next;
+        case PPC_FLAGS_EXCP_601:
+            /* Run mode exception on 601 */
+            /* XXX: TODO */
+            cpu_abort(env,
+                      "601 run mode exception is not implemented yet !\n");
+            goto store_next;
+        default:
+            cpu_abort(env, "Invalid exception 0x1800 !\n");
+            break;
+        }
+        return;
+    /* Other exceptions */
+    /* Qemu internal exceptions:
+     * we should never come here with those values: abort execution
+     */
+    default:
+        cpu_abort(env, "Invalid exception: code %d (%04x)\n", excp, excp);
         return;
     store_current:
-        /* SRR0 is set to current instruction */
-        env->spr[SPR_SRR0] = (uint32_t)env->nip - 4;
+        /* save current instruction location */
+        *srr_0 = (env->nip - 4) & 0xFFFFFFFFULL;
         break;
     store_next:
-        /* SRR0 is set to next instruction */
-        env->spr[SPR_SRR0] = (uint32_t)env->nip;
+        /* save next instruction location */
+        *srr_0 = env->nip & 0xFFFFFFFFULL;
         break;
     }
-    env->spr[SPR_SRR1] = msr;
+    /* Save msr */
+    *srr_1 = msr;
+    /* If we disactivated any translation, flush TLBs */
+    if (msr_ir || msr_dr) {
+        tlb_flush(env, 1);
+    }
     /* reload MSR with correct bits */
-    msr_pow = 0;
     msr_ee = 0;
     msr_pr = 0;
     msr_fp = 0;
@@ -1193,14 +1486,11 @@ void do_interrupt (CPUState *env)
     msr_dr = 0;
     msr_ri = 0;
     msr_le = msr_ile;
+    msr_sf = msr_isf;
     do_compute_hflags(env);
     /* Jump to handler */
-    env->nip = excp << 8;
+    env->nip = excp;
     env->exception_index = EXCP_NONE;
-    /* Invalidate all TLB as we may have changed translation mode */
-#ifdef ACCURATE_TLB_FLUSH
-    tlb_flush(env, 1);
-#endif
     /* ensure that no TB jump will be modified as
        the program flow was changed */
 #ifdef __sparc__
@@ -1208,6 +1498,6 @@ void do_interrupt (CPUState *env)
 #else
     T0 = 0;
 #endif
-    env->exception_index = -1;
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
 #endif /* !CONFIG_USER_ONLY */
index 38ed13a..c795366 100644 (file)
@@ -204,16 +204,6 @@ PPC_OP(update_nip)
     env->nip = PARAM(1);
 }
 
-PPC_OP(debug)
-{
-    env->nip = PARAM(1);
-#if defined (DEBUG_OP)
-    dump_state();
-#endif
-    do_raise_exception(EXCP_DEBUG);
-    RETURN();
-}
-
 /* Segment registers load and store with immediate index */
 PPC_OP(load_srin)
 {
@@ -1384,14 +1374,10 @@ PPC_OP(check_reservation)
 /* Return from interrupt */
 PPC_OP(rfi)
 {
-    regs->nip = regs->spr[SPR_SRR0] & ~0x00000003;
-#if 1 // TRY
-    T0 = regs->spr[SPR_SRR1] & ~0xFFF00000;
-#else
-    T0 = regs->spr[SPR_SRR1] & ~0xFFFF0000;
-#endif
+    env->nip = env->spr[SPR_SRR0] & ~0x00000003;
+    T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
     do_store_msr(env, T0);
-    do_raise_exception(EXCP_RFI);
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
     RETURN();
 }
 
index 670e278..e57fbe4 100644 (file)
@@ -42,12 +42,6 @@ void do_raise_exception_err (uint32_t exception, int error_code)
     printf("Raise exception %3x code : %d\n", exception, error_code);
 #endif
     switch (exception) {
-    case EXCP_EXTERNAL:
-    case EXCP_DECR:
-       printf("DECREMENTER & EXTERNAL exceptions should be hard interrupts !\n");
-       if (msr_ee == 0)
-           return;
-       break;
     case EXCP_PROGRAM:
        if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
            return;
index 52a28de..70f8863 100644 (file)
@@ -179,6 +179,12 @@ static inline void RET_STOP (DisasContext *ctx)
     RET_EXCP(ctx, EXCP_MTMSR, 0);
 }
 
+static inline void RET_CHG_FLOW (DisasContext *ctx)
+{
+    gen_op_raise_exception_err(EXCP_MTMSR, 0);
+    ctx->exception = EXCP_MTMSR;
+}
+
 #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                      \
 static void gen_##name (DisasContext *ctx);                                   \
 GEN_OPCODE(name, opc1, opc2, opc3, inval, type);                              \
@@ -1895,7 +1901,7 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
         return;
     }
     gen_op_rfi();
-    RET_EXCP(ctx, EXCP_RFI, 0);
+    RET_CHG_FLOW(ctx);
 #endif
 }
 
@@ -2555,7 +2561,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
             (msr_se && (ctx.nip < 0x100 ||
                         ctx.nip > 0xF00 ||
                         (ctx.nip & 0xFC) != 0x04) &&
-             ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI &&
+             ctx.exception != EXCP_SYSCALL &&
+             ctx.exception != EXCP_SYSCALL_USER &&
              ctx.exception != EXCP_TRAP)) {
             RET_EXCP(ctxp, EXCP_TRACE, 0);
         }