PowerPC merge: real time TB and decrementer - faster and simpler exception handling...
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Fri, 21 May 2004 12:59:32 +0000 (12:59 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Fri, 21 May 2004 12:59:32 +0000 (12:59 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@841 c046a42c-6fe2-441c-8c8c-71466251a162

14 files changed:
cpu-all.h
cpu-exec.c
exec.c
hw/ppc.c
hw/ppc_prep.c
linux-user/main.c
monitor.c
target-ppc/cpu.h
target-ppc/exec.h
target-ppc/helper.c
target-ppc/op.c
target-ppc/op_helper.c
target-ppc/op_mem.h
target-ppc/translate.c

index 69b6e7c..bb6e74a 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -627,14 +627,15 @@ void cpu_single_step(CPUState *env, int enabled);
    if no page found. */
 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
 
-#define CPU_LOG_TB_OUT_ASM  (1 << 0) 
-#define CPU_LOG_TB_IN_ASM     (1 << 1)
+#define CPU_LOG_TB_OUT_ASM (1 << 0) 
+#define CPU_LOG_TB_IN_ASM  (1 << 1)
 #define CPU_LOG_TB_OP      (1 << 2)
 #define CPU_LOG_TB_OP_OPT  (1 << 3)
 #define CPU_LOG_INT        (1 << 4)
 #define CPU_LOG_EXEC       (1 << 5)
 #define CPU_LOG_PCALL      (1 << 6)
 #define CPU_LOG_IOPORT     (1 << 7)
+#define CPU_LOG_TB_CPU     (1 << 8)
 
 /* define log items */
 typedef struct CPULogItem {
index 12e848b..5846885 100644 (file)
@@ -241,11 +241,25 @@ int cpu_exec(CPUState *env1)
 #endif
                     }
 #elif defined(TARGET_PPC)
+#if 0
+                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
+                        cpu_ppc_reset(env);
+                    }
+#endif
+                    if (msr_ee != 0) {
                     if ((interrupt_request & CPU_INTERRUPT_HARD)) {
-                        do_queue_exception(EXCP_EXTERNAL);
-                        if (check_exception_state(env))
+                           /* Raise it */
+                           env->exception_index = EXCP_EXTERNAL;
+                           env->error_code = 0;
                             do_interrupt(env);
                         env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+                       } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
+                           /* Raise it */
+                           env->exception_index = EXCP_DECR;
+                           env->error_code = 0;
+                           do_interrupt(env);
+                            env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
+                       }
                     }
 #endif
                     if (interrupt_request & CPU_INTERRUPT_EXITTB) {
@@ -757,7 +771,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
     /* we restore the process signal mask as the sigreturn should
        do it (XXX: use sigsetjmp) */
         sigprocmask(SIG_SETMASK, old_set, NULL);
-        do_queue_exception_err(env->exception_index, env->error_code);
+        do_raise_exception_err(env->exception_index, env->error_code);
     } else {
         /* activate soft MMU for this block */
         cpu_resume_from_signal(env, puc);
diff --git a/exec.c b/exec.c
index b484dc6..695779a 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -1132,6 +1132,8 @@ CPULogItem cpu_log_items[] = {
       "show interrupts/exceptions in short format" },
     { CPU_LOG_EXEC, "exec",
       "show trace before each executed TB (lots of logs)" },
+    { CPU_LOG_TB_CPU, "cpu",
+      "show CPU state before bloc translation" },
 #ifdef TARGET_I386
     { CPU_LOG_PCALL, "pcall",
       "show protected mode far calls/returns/exceptions" },
index 7cba03b..3858952 100644 (file)
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -28,6 +28,181 @@ void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device,
                    const char *kernel_filename, const char *kernel_cmdline,
                    const char *initrd_filename);
 
+/*****************************************************************************/
+/* PPC time base and decrementer emulation */
+//#define DEBUG_TB
+
+struct ppc_tb_t {
+    /* Time base management */
+    int64_t  tb_offset;    /* Compensation               */
+    uint32_t tb_freq;      /* TB frequency               */
+    /* Decrementer management */
+    uint64_t decr_next;    /* Tick for next decr interrupt  */
+    struct QEMUTimer *decr_timer;
+};
+
+static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
+{
+    /* TB time in tb periods */
+    return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
+                   tb_env->tb_freq, ticks_per_sec);
+}
+
+uint32_t cpu_ppc_load_tbl (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env);
+#ifdef DEBUG_TB
+    {
+         static int last_time;
+        int now;
+        now = time(NULL);
+        if (last_time != now) {
+            last_time = now;
+            printf("%s: tb=0x%016lx %d %08lx\n",
+                    __func__, tb, now, tb_env->tb_offset);
+        }
+    }
+#endif
+
+    return tb & 0xFFFFFFFF;
+}
+
+uint32_t cpu_ppc_load_tbu (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env);
+#ifdef DEBUG_TB
+    printf("%s: tb=0x%016lx\n", __func__, tb);
+#endif
+    return tb >> 32;
+}
+
+static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
+{
+    tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
+        - qemu_get_clock(vm_clock);
+#ifdef DEBUG_TB
+    printf("%s: tb=0x%016lx offset=%08x\n", __func__, value);
+#endif
+}
+
+void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    cpu_ppc_store_tb(tb_env,
+                     ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
+}
+
+void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    cpu_ppc_store_tb(tb_env,
+                     ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
+}
+
+uint32_t cpu_ppc_load_decr (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint32_t decr;
+
+    decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock),
+                    tb_env->tb_freq, ticks_per_sec);
+#ifdef DEBUG_TB
+    printf("%s: 0x%08x\n", __func__, decr);
+#endif
+
+    return decr;
+}
+
+/* When decrementer expires,
+ * all we need to do is generate or queue a CPU exception
+ */
+static inline void cpu_ppc_decr_excp (CPUState *env)
+{
+    /* Raise it */
+#ifdef DEBUG_TB
+    printf("raise decrementer exception\n");
+#endif
+    cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+}
+
+static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
+                                 uint32_t value, int is_excp)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t now, next;
+
+#ifdef DEBUG_TB
+    printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value);
+#endif
+    now = qemu_get_clock(vm_clock);
+    next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
+    if (is_excp)
+        next += tb_env->decr_next - now;
+    if (next == now)
+       next++;
+    tb_env->decr_next = next;
+    /* Adjust timer */
+    qemu_mod_timer(tb_env->decr_timer, next);
+    /* If we set a negative value and the decrementer was positive,
+     * raise an exception.
+     */
+    if ((value & 0x80000000) && !(decr & 0x80000000))
+       cpu_ppc_decr_excp(env);
+}
+
+void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+{
+    _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
+}
+
+static void cpu_ppc_decr_cb (void *opaque)
+{
+    _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
+}
+
+/* Set up (once) timebase frequency (in Hz) */
+ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
+{
+    ppc_tb_t *tb_env;
+
+    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
+    if (tb_env == NULL)
+        return NULL;
+    env->tb_env = tb_env;
+    if (tb_env->tb_freq == 0 || 1) {
+       tb_env->tb_freq = freq;
+       /* Create new timer */
+       tb_env->decr_timer =
+            qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
+       /* There is a bug in  2.4 kernels:
+        * if a decrementer exception is pending when it enables msr_ee,
+        * it's not ready to handle it...
+        */
+       _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+    }
+
+    return tb_env;
+}
+
+#if 0
+/*****************************************************************************/
+/* Handle system reset (for now, just stop emulation) */
+void cpu_ppc_reset (CPUState *env)
+{
+    printf("Reset asked... Stop emulation\n");
+    abort();
+}
+#endif
+
+/*****************************************************************************/
 void ppc_init (int ram_size, int vga_ram_size, int boot_device,
               DisplayState *ds, const char **fd_filename, int snapshot,
               const char *kernel_filename, const char *kernel_cmdline,
index f64649c..0578399 100644 (file)
@@ -24,6 +24,9 @@
 #include "vl.h"
 #include "m48t59.h"
 
+/* XXX: move all TB related stuff in ppc_prep.c and suppress ppc.c ? */
+ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq);
+
 //#define HARD_DEBUG_PPC_IO
 //#define DEBUG_PPC_IO
 
@@ -663,7 +666,6 @@ static void VGA_printf (uint8_t *s)
 static void VGA_init (void)
 {
     /* Basic VGA init, inspired by plex86 VGAbios */
-    printf("Init VGA...\n");
 #if 1
     /* switch to color mode and enable CPU access 480 lines */
     PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3);
@@ -725,7 +727,6 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size,
      * if a decrementer exception is pending when it enables msr_ee,
      * it's not ready to handle it...
      */
-    env->decr = 0xFFFFFFFF;
     p = phys_ram_base + kernel_addr;
 #if !defined (USE_OPEN_FIRMWARE)
     /* Let's register the whole memory available only in supervisor mode */
@@ -948,6 +949,8 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
        }
     }
 
+    cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
+
     /* init basic PC hardware */
     vga_initialize(ds, phys_ram_base + ram_size, ram_size, 
                    vga_ram_size, 0);
index c0759bf..2275b01 100644 (file)
@@ -504,6 +504,49 @@ void cpu_loop (CPUSPARCState *env)
 #endif
 
 #ifdef TARGET_PPC
+
+static inline uint64_t cpu_ppc_get_tb (CPUState *env)
+{
+    /* TO FIX */
+    return 0;
+}
+  
+uint32_t cpu_ppc_load_tbl (CPUState *env)
+{
+    return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
+}
+  
+uint32_t cpu_ppc_load_tbu (CPUState *env)
+{
+    return cpu_ppc_get_tb(env) >> 32;
+}
+  
+static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
+{
+    /* TO FIX */
+}
+
+void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+{
+    cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
+}
+void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
+{
+    cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
+}
+  
+uint32_t cpu_ppc_load_decr (CPUState *env)
+{
+    /* TO FIX */
+    return -1;
+}
+void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+{
+    /* TO FIX */
+}
 void cpu_loop(CPUPPCState *env)
 {
     target_siginfo_t info;
@@ -812,7 +855,7 @@ void cpu_loop(CPUPPCState *env)
             abort();
         case EXCP_MTMSR:
             /* We reloaded the msr, just go on */
-            if (msr_pr) {
+            if (msr_pr == 0) {
                 fprintf(stderr, "Tried to go into supervisor mode !\n");
                 if (loglevel)
                     fprintf(logfile, "Tried to go into supervisor mode !\n");
@@ -842,12 +885,7 @@ void cpu_loop(CPUPPCState *env)
             }
             abort();
         }
-        if (trapnr < EXCP_PPC_MAX)
-            env->exceptions &= ~(1 << trapnr);
         process_pending_signals(env);
-        if (env->exceptions != 0) {
-            check_exception_state(env);
-        }
     }
 }
 #endif
index f5ab043..ab1c842 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -589,6 +589,24 @@ static int monitor_get_xer (struct MonitorDef *md)
         (cpu_single_env->xer[XER_CA] << XER_CA) |
         (cpu_single_env->xer[XER_BC] << XER_BC);
 }
+
+uint32_t cpu_ppc_load_decr (CPUState *env);
+static int monitor_get_decr (struct MonitorDef *md)
+{
+    return cpu_ppc_load_decr(cpu_single_env);
+}
+
+uint32_t cpu_ppc_load_tbu (CPUState *env);
+static int monitor_get_tbu (struct MonitorDef *md)
+{
+    return cpu_ppc_load_tbu(cpu_single_env);
+}
+
+uint32_t cpu_ppc_load_tbl (CPUState *env);
+static int monitor_get_tbl (struct MonitorDef *md)
+{
+    return cpu_ppc_load_tbl(cpu_single_env);
+}
 #endif
 
 static MonitorDef monitor_defs[] = {
@@ -651,12 +669,12 @@ static MonitorDef monitor_defs[] = {
     { "nip|pc", offsetof(CPUState, nip) },
     { "lr", offsetof(CPUState, lr) },
     { "ctr", offsetof(CPUState, ctr) },
-    { "decr", offsetof(CPUState, decr) },
+    { "decr", 0, &monitor_get_decr, },
     { "ccr", 0, &monitor_get_ccr, },
     { "msr", 0, &monitor_get_msr, },
     { "xer", 0, &monitor_get_xer, },
-    { "tbu", offsetof(CPUState, tb[0]) },
-    { "tbl", offsetof(CPUState, tb[1]) },
+    { "tbu", 0, &monitor_get_tbu, },
+    { "tbl", 0, &monitor_get_tbl, },
     { "sdr1", offsetof(CPUState, sdr1) },
     { "sr0", offsetof(CPUState, sr[0]) },
     { "sr1", offsetof(CPUState, sr[1]) },
index e6cb094..bd430af 100644 (file)
@@ -78,6 +78,8 @@ enum {
 #define PPC_750 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM |               \
                  PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT)
 
+typedef struct ppc_tb_t ppc_tb_t;
+
 /* Supervisor mode registers */
 /* Machine state register */
 #define MSR_POW 18
@@ -134,10 +136,6 @@ typedef struct CPUPPCState {
     /* special purpose registers */
     uint32_t lr;
     uint32_t ctr;
-    /* Time base */
-    uint32_t tb[2];
-    /* decrementer */
-    uint32_t decr;
     /* BATs */
     uint32_t DBAT[2][8];
     uint32_t IBAT[2][8];
@@ -154,13 +152,6 @@ typedef struct CPUPPCState {
     int error_code;
     int access_type; /* when a memory exception occurs, the access
                         type is stored here */
-#if 0 /* TODO */
-    uint32_t pending_exceptions; /* For external & decr exception,
-                                 * that can be delayed */
-#else
-    uint32_t exceptions; /* exception queue */
-    uint32_t errors[32];
-#endif
     int user_mode_only; /* user mode only simulation */
     struct TranslationBlock *current_tb; /* currently executing TB */
     /* soft mmu support */
@@ -178,8 +169,13 @@ typedef struct CPUPPCState {
     /* ice debug support */
     uint32_t breakpoints[MAX_BREAKPOINTS];
     int nb_breakpoints;
-    int brkstate;
-    int singlestep_enabled;
+    int singlestep_enabled; /* XXX: should use CPU single step mode instead */
+
+    /* Time base and decrementer */
+    ppc_tb_t *tb_env;
+
+    /* Power management */
+    int power_mode;
 
     /* user data */
     void *opaque;
@@ -206,10 +202,15 @@ void _store_xer (CPUPPCState *env, uint32_t value);
 uint32_t _load_msr (CPUPPCState *env);
 void _store_msr (CPUPPCState *env, uint32_t value);
 
-void PPC_init_hw (uint32_t mem_size,
-                  uint32_t kernel_addr, uint32_t kernel_size,
-                  uint32_t stack_addr, int boot_device,
-                 const unsigned char *initrd_file);
+/* Time-base and decrementer management */
+#ifndef NO_CPU_IO_DEFS
+uint32_t cpu_ppc_load_tbl (CPUPPCState *env);
+uint32_t cpu_ppc_load_tbu (CPUPPCState *env);
+void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value);
+void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value);
+uint32_t cpu_ppc_load_decr (CPUPPCState *env);
+void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value);
+#endif
 
 #define TARGET_PAGE_BITS 12
 #include "cpu-all.h"
index f4d20a8..edb73ef 100644 (file)
@@ -119,12 +119,8 @@ static inline uint32_t rotl (uint32_t i, int n)
 
 #endif /* !defined(CONFIG_USER_ONLY) */
 
-int check_exception_state (CPUState *env);
-
-void do_queue_exception_err (uint32_t exception, int error_code);
-void do_queue_exception (uint32_t exception);
-void do_process_exceptions (void);
-void do_check_exception_state (void);
+void do_raise_exception_err (uint32_t exception, int error_code);
+void do_raise_exception (uint32_t exception);
 
 void do_load_cr (void);
 void do_store_cr (uint32_t mask);
index 09c0eeb..e8b776b 100644 (file)
 //#define DEBUG_BATS
 //#define DEBUG_EXCEPTIONS
 
-extern FILE *logfile, *stdout, *stderr;
-void exit (int);
+extern FILE *stdout, *stderr;
 void abort (void);
 
-void cpu_loop_exit(void)
-{
-    longjmp(env->jmp_env, 1);
-}
-
-void do_process_exceptions (void)
-{
-    cpu_loop_exit();
-}
-
-int check_exception_state (CPUState *env)
-{
-    int i;
-
-    /* Process PPC exceptions */
-    for (i = 1; i  < EXCP_PPC_MAX; i++) {
-        if (env->exceptions & (1 << i)) {
-            switch (i) {
-            case EXCP_EXTERNAL:
-            case EXCP_DECR:
-                if (msr_ee == 0)
-                    return 0;
-                break;
-            case EXCP_PROGRAM:
-                if (env->errors[EXCP_PROGRAM] == EXCP_FP &&
-                    msr_fe0 == 0 && msr_fe1 == 0)
-                    return 0;
-                break;
-            default:
-                break;
-            }
-            env->exception_index = i;
-            env->error_code = env->errors[i];
-            return 1;
-        }
-    }
-
-    return 0;
-}
+/*****************************************************************************/
 
 /*****************************************************************************/
 /* PPC MMU emulation */
@@ -500,8 +461,7 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
                 cpu_restore_state(tb, env, pc, NULL);
             }
         }
-        do_queue_exception_err(env->exception_index, env->error_code);
-        do_process_exceptions();
+        do_raise_exception_err(env->exception_index, env->error_code);
     }
     {
         unsigned long tlb_addrr, tlb_addrw;
@@ -701,9 +661,6 @@ void do_interrupt (CPUState *env)
     uint32_t msr;
     int excp = env->exception_index;
 
-    /* Dequeue PPC exceptions */
-    if (excp < EXCP_PPC_MAX)
-        env->exceptions &= ~(1 << excp);
     msr = _load_msr(env);
 #if defined (DEBUG_EXCEPTIONS)
     if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) 
@@ -812,7 +769,7 @@ void do_interrupt (CPUState *env)
     }
 #endif
             /* Requeue it */
-            do_queue_exception(EXCP_EXTERNAL);
+            do_raise_exception(EXCP_EXTERNAL);
             return;
             }
         goto store_next;
@@ -864,7 +821,7 @@ void do_interrupt (CPUState *env)
     case EXCP_DECR:
         if (msr_ee == 0) {
             /* Requeue it */
-            do_queue_exception(EXCP_DECR);
+            do_raise_exception(EXCP_DECR);
             return;
         }
         goto store_next;
@@ -937,4 +894,5 @@ void do_interrupt (CPUState *env)
     T0 = 0;
 #endif
 #endif
+    env->exception_index = -1;
 }
index de7e247..38eae7f 100644 (file)
@@ -208,32 +208,28 @@ PPC_OP(set_T2)
 }
 
 /* Generate exceptions */
-PPC_OP(queue_exception_err)
+PPC_OP(raise_exception_err)
 {
-    do_queue_exception_err(PARAM(1), PARAM(2));
+    do_raise_exception_err(PARAM(1), PARAM(2));
 }
 
-PPC_OP(queue_exception)
+PPC_OP(raise_exception)
 {
-    do_queue_exception(PARAM(1));
+    do_raise_exception(PARAM(1));
 }
 
-PPC_OP(process_exceptions)
+PPC_OP(update_nip)
 {
     env->nip = PARAM(1);
-    if (env->exceptions != 0) {
-        do_check_exception_state();
-    }
 }
 
 PPC_OP(debug)
 {
     env->nip = PARAM(1);
-    env->brkstate = 1;
 #if defined (DEBUG_OP)
     dump_state();
 #endif
-    do_queue_exception(EXCP_DEBUG);
+    do_raise_exception(EXCP_DEBUG);
     RETURN();
 }
 
@@ -364,58 +360,38 @@ PPC_OP(store_ctr)
     RETURN();
 }
 
-/* Update time base */
-PPC_OP(update_tb)
+PPC_OP(load_tbl)
 {
-    T0 = regs->tb[0];
-    T1 = T0;
-    T0 += PARAM(1);
-#if defined (DEBUG_OP)
-    dump_update_tb(PARAM(1));
-#endif
-    if (T0 < T1) {
-        T1 = regs->tb[1] + 1;
-        regs->tb[1] = T1;
-    }
-    regs->tb[0] = T0;
+    T0 = cpu_ppc_load_tbl(regs);
     RETURN();
 }
 
-PPC_OP(load_tb)
+PPC_OP(load_tbu)
 {
-    T0 = regs->tb[PARAM(1)];
+    T0 = cpu_ppc_load_tbu(regs);
     RETURN();
 }
 
-PPC_OP(store_tb)
+PPC_OP(store_tbl)
 {
-    regs->tb[PARAM(1)] = T0;
-#if defined (DEBUG_OP)
-    dump_store_tb(PARAM(1));
-#endif
+    cpu_ppc_store_tbl(regs, T0);
     RETURN();
 }
 
-/* Update decrementer */
-PPC_OP(update_decr)
+PPC_OP(store_tbu)
 {
-    T0 = regs->decr;
-    T1 = T0;
-    T0 -= PARAM(1);
-    regs->decr = T0;
-    if (PARAM(1) > T1) {
-        do_queue_exception(EXCP_DECR);
-    }
+    cpu_ppc_store_tbu(regs, T0);
     RETURN();
 }
 
-PPC_OP(store_decr)
+PPC_OP(load_decr)
 {
-    T1 = regs->decr;
-    regs->decr = T0;
-    if (Ts0 < 0 && Ts1 > 0) {
-        do_queue_exception(EXCP_DECR);
+    T0 = cpu_ppc_load_decr(regs);
     }
+
+PPC_OP(store_decr)
+{
+    cpu_ppc_store_decr(regs, T0);
     RETURN();
 }
 
@@ -1471,17 +1447,14 @@ PPC_OP(fneg)
 /* Return from interrupt */
 PPC_OP(rfi)
 {
+    regs->nip = regs->spr[SRR0] & ~0x00000003;
     T0 = regs->spr[SRR1] & ~0xFFFF0000;
     do_store_msr();
-    do_tlbia();
 #if defined (DEBUG_OP)
     dump_rfi();
 #endif
-    regs->nip = regs->spr[SRR0] & ~0x00000003;
-    do_queue_exception(EXCP_RFI);
-    if (env->exceptions != 0) {
-        do_check_exception_state();
-    }
+    //    do_tlbia();
+    do_raise_exception(EXCP_RFI);
     RETURN();
 }
 
@@ -1493,7 +1466,7 @@ PPC_OP(tw)
         (Ts0 == Ts1 && (PARAM(1) & 0x04)) ||
         (T0 < T1 && (PARAM(1) & 0x02)) ||
         (T0 > T1 && (PARAM(1) & 0x01)))
-        do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP);
+        do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
     RETURN();
 }
 
@@ -1504,7 +1477,7 @@ PPC_OP(twi)
         (Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) ||
         (T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) ||
         (T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01)))
-        do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP);
+        do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
     RETURN();
 }
 
index ae3d254..3ddda1e 100644 (file)
 
 /*****************************************************************************/
 /* Exceptions processing helpers */
-void do_queue_exception_err (uint32_t exception, int error_code)
+void cpu_loop_exit(void)
 {
-    /* Queue real PPC exceptions */
-    if (exception < EXCP_PPC_MAX) {
-        env->exceptions |= 1 << exception;
-        env->errors[exception] = error_code;
-    } else {
-        /* Preserve compatibility with qemu core */
-        env->exceptions |= 1;
-        env->exception_index = exception;
-        env->error_code = error_code;
-    }
+    longjmp(env->jmp_env, 1);
 }
 
-void do_queue_exception (uint32_t exception)
+void do_raise_exception_err (uint32_t exception, int error_code)
 {
-    do_queue_exception_err(exception, 0);
-}
-
-void do_check_exception_state (void)
-{
-    if ((env->exceptions & 1) == 1 || check_exception_state(env)) {
-        env->exceptions &= ~1;
+#if 0
+    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;
+       break;
+    default:
+       break;
+}
+    env->exception_index = exception;
+    env->error_code = error_code;
         cpu_loop_exit();
     }
+
+void do_raise_exception (uint32_t exception)
+{
+    do_raise_exception_err(exception, 0);
 }
 
 /*****************************************************************************/
@@ -125,13 +132,6 @@ void do_store_msr (void)
         /* Flush all tlb when changing translation mode or privilege level */
         do_tlbia();
     }
-#if 0
-    if ((T0 >> MSR_IP) & 0x01) {
-        printf("Halting CPU. Stop emulation\n");
-        do_queue_exception(EXCP_HLT);
-        cpu_loop_exit();
-    }
-#endif
     msr_pow = (T0 >> MSR_POW) & 0x03;
     msr_ile = (T0 >> MSR_ILE) & 0x01;
     msr_ee = (T0 >> MSR_EE) & 0x01;
index 52f55c9..b5d10ce 100644 (file)
@@ -97,8 +97,7 @@ PPC_OP(glue(lswx, MEMSUFFIX))
     if (T1 > 0) {
         if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
             (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
-            do_queue_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
-            do_process_exceptions();
+            do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
         } else {
             glue(do_lsw, MEMSUFFIX)(PARAM(1));
         }
@@ -138,8 +137,7 @@ PPC_LDF_OP(fs, ldfl);
 PPC_OP(glue(lwarx, MEMSUFFIX))
 {
     if (T0 & 0x03) {
-        do_queue_exception(EXCP_ALIGN);
-        do_process_exceptions();
+        do_raise_exception(EXCP_ALIGN);
     } else {
        T1 = glue(ldl, MEMSUFFIX)((void *)T0);
        regs->reserve = T0;
@@ -151,8 +149,7 @@ PPC_OP(glue(lwarx, MEMSUFFIX))
 PPC_OP(glue(stwcx, MEMSUFFIX))
 {
     if (T0 & 0x03) {
-        do_queue_exception(EXCP_ALIGN);
-        do_process_exceptions();
+        do_raise_exception(EXCP_ALIGN);
     } else {
         if (regs->reserve != T0) {
             env->crf[0] = xer_ov;
index 0090973..021cc74 100644 (file)
@@ -30,6 +30,7 @@
 //#define DO_SINGLE_STEP
 //#define DO_STEP_FLUSH
 //#define DEBUG_DISAS
+//#define PPC_DEBUG_DISAS
 
 enum {
 #define DEF(s, n, copy_size) INDEX_op_ ## s,
@@ -135,10 +136,6 @@ typedef struct DisasContext {
     uint32_t nip;
     uint32_t opcode;
     uint32_t exception;
-    /* Time base offset */
-    uint32_t tb_offset;
-    /* Decrementer offset */
-    uint32_t decr_offset;
     /* Execution mode */
 #if !defined(CONFIG_USER_ONLY)
     int supervisor;
@@ -156,21 +153,26 @@ typedef struct opc_handler_t {
     void (*handler)(DisasContext *ctx);
 } opc_handler_t;
 
-#define RET_EXCP(excp, error)                                                 \
+#define RET_EXCP(ctx, excp, error)                                            \
 do {                                                                          \
-    gen_op_queue_exception_err(excp, error);                                  \
-    ctx->exception = excp;                                                    \
-    return;                                                                   \
+    if ((ctx)->exception == EXCP_NONE) {                                      \
+        gen_op_update_nip((ctx)->nip);                                        \
+    }                                                                         \
+    gen_op_raise_exception_err((excp), (error));                              \
+    ctx->exception = (excp);                                                  \
 } while (0)
 
-#define RET_INVAL()                                                           \
-RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
+#define RET_INVAL(ctx)                                                        \
+RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
+
+#define RET_PRIVOPC(ctx)                                                      \
+RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
 
-#define RET_PRIVOPC()                                                         \
-RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
+#define RET_PRIVREG(ctx)                                                      \
+RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
 
-#define RET_PRIVREG()                                                         \
-RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
+#define RET_MTMSR(ctx)                                                        \
+RET_EXCP((ctx), EXCP_MTMSR, 0)
 
 #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                      \
 static void gen_##name (DisasContext *ctx);                                   \
@@ -312,29 +314,26 @@ GEN_OPCODE_MARK(start);
 /* Invalid instruction */
 GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
 {
-    RET_INVAL();
+    RET_INVAL(ctx);
 }
 
 /* Special opcode to stop emulation */
 GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON)
 {
-    gen_op_queue_exception(EXCP_HLT);
-    ctx->exception = EXCP_HLT;
+    RET_EXCP(ctx, EXCP_HLT, 0);
 }
 
 /* Special opcode to call open-firmware */
 GEN_HANDLER(of_enter, 0x06, 0x01, 0xFF, 0x03FFFFC1, PPC_COMMON)
 {
-    gen_op_queue_exception(EXCP_OFCALL);
-    ctx->exception = EXCP_OFCALL;
+    RET_EXCP(ctx, EXCP_OFCALL, 0);
 }
 
 /* Special opcode to call RTAS */
 GEN_HANDLER(rtas_enter, 0x06, 0x02, 0xFF, 0x03FFFFC1, PPC_COMMON)
 {
     printf("RTAS entry point !\n");
-    gen_op_queue_exception(EXCP_RTASCALL);
-    ctx->exception = EXCP_RTASCALL;
+    RET_EXCP(ctx, EXCP_RTASCALL, 0);
 }
 
 static opc_handler_t invalid_handler = {
@@ -1010,7 +1009,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)            \
     uint32_t simm = SIMM(ctx->opcode);                                        \
     if (rA(ctx->opcode) == 0 ||                                               \
         rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
-        RET_INVAL();                                                          \
+        RET_INVAL(ctx);                                                       \
+        return;                                                               \
     }                                                                         \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     if (simm != 0)                                                            \
@@ -1025,7 +1025,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)           \
 {                                                                             \
     if (rA(ctx->opcode) == 0 ||                                               \
         rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
-        RET_INVAL();                                                          \
+        RET_INVAL(ctx);                                                       \
+        return;                                                               \
     }                                                                         \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
@@ -1086,7 +1087,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
 {                                                                             \
     uint32_t simm = SIMM(ctx->opcode);                                        \
     if (rA(ctx->opcode) == 0) {                                               \
-        RET_INVAL();                                                          \
+        RET_INVAL(ctx);                                                       \
+        return;                                                               \
     }                                                                         \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     if (simm != 0)                                                            \
@@ -1100,7 +1102,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
 GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)          \
 {                                                                             \
     if (rA(ctx->opcode) == 0) {                                               \
-        RET_INVAL();                                                          \
+        RET_INVAL(ctx);                                                       \
+        return;                                                               \
     }                                                                         \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
@@ -1236,7 +1239,8 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
     nr = nb / 4;
     if (((start + nr) > 32  && start <= ra && (start + nr - 32) > ra) ||
         ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) {
-        RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+        return;
     }
     if (ra == 0) {
         gen_op_set_T0(0);
@@ -1376,7 +1380,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)            \
     uint32_t simm = SIMM(ctx->opcode);                                        \
     if (rA(ctx->opcode) == 0 ||                                               \
         rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
-        RET_INVAL();                                                          \
+        RET_INVAL(ctx);                                                       \
+        return;                                                               \
     }                                                                         \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     if (simm != 0)                                                            \
@@ -1391,7 +1396,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)           \
 {                                                                             \
     if (rA(ctx->opcode) == 0 ||                                               \
         rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
-        RET_INVAL();                                                          \
+        RET_INVAL(ctx);                                                       \
+        return;                                                               \
     }                                                                         \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
@@ -1448,7 +1454,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
 {                                                                             \
     uint32_t simm = SIMM(ctx->opcode);                                        \
     if (rA(ctx->opcode) == 0) {                                               \
-        RET_INVAL();                                                          \
+        RET_INVAL(ctx);                                                       \
+        return;                                                               \
     }                                                                         \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     if (simm != 0)                                                            \
@@ -1462,7 +1469,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
 GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)          \
 {                                                                             \
     if (rA(ctx->opcode) == 0) {                                               \
-        RET_INVAL();                                                          \
+        RET_INVAL(ctx);                                                       \
+        return;                                                               \
     }                                                                         \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
@@ -1502,7 +1510,7 @@ GEN_STFS(fs, 0x14);
 /* stfiwx */
 GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
 {
-    RET_INVAL();
+    RET_INVAL(ctx);
 }
 
 /***                                Branch                                 ***/
@@ -1512,9 +1520,6 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
 {
     uint32_t li = s_ext24(LI(ctx->opcode)), target;
 
-    gen_op_update_tb(ctx->tb_offset);
-    gen_op_update_decr(ctx->decr_offset);
-    gen_op_process_exceptions(ctx->nip - 4);
     if (AA(ctx->opcode) == 0)
         target = ctx->nip + li - 4;
     else
@@ -1538,10 +1543,6 @@ static inline void gen_bcond(DisasContext *ctx, int type)
     uint32_t mask;                                                            
     uint32_t li;
 
-    gen_op_update_tb(ctx->tb_offset);                                         
-    gen_op_update_decr(ctx->decr_offset);                                     
-    gen_op_process_exceptions(ctx->nip - 4);                        
-
     if ((bo & 0x4) == 0)
         gen_op_dec_ctr();                                                     
     switch(type) {
@@ -1683,14 +1684,15 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
 GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVOPC();
+    RET_PRIVOPC(ctx);
 #else
     /* Restore CPU state */
     if (!ctx->supervisor) {
-        RET_PRIVOPC();
+        RET_PRIVOPC(ctx);
+        return;
     }
     gen_op_rfi();
-    ctx->exception = EXCP_RFI;
+    RET_EXCP(ctx, EXCP_RFI, 0);
 #endif
 }
 
@@ -1698,11 +1700,10 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
 GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
 {
 #if defined(CONFIG_USER_ONLY)
-    gen_op_queue_exception(EXCP_SYSCALL_USER);
+    RET_EXCP(ctx, EXCP_SYSCALL_USER, 0);
 #else
-    gen_op_queue_exception(EXCP_SYSCALL);
+    RET_EXCP(ctx, EXCP_SYSCALL, 0);
 #endif
-    ctx->exception = EXCP_SYSCALL;
 }
 
 /***                                Trap                                   ***/
@@ -1770,10 +1771,11 @@ GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC)
 GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG();
+    RET_PRIVREG(ctx);
 #else
     if (!ctx->supervisor) {
-        RET_PRIVREG();
+        RET_PRIVREG(ctx);
+        return;
     }
     gen_op_load_msr();
     gen_op_store_T0_gpr(rD(ctx->opcode));
@@ -1792,11 +1794,11 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
 #endif
     {
     case -1:
-        RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
-        break;
+        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
+        return;
     case 0:
-        RET_PRIVREG();
-        break;
+        RET_PRIVREG(ctx);
+        return;
     default:
         break;
         }
@@ -1910,19 +1912,13 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
         gen_op_load_sdr1();
         break;
     case V_TBL:
-        gen_op_update_tb(ctx->tb_offset);
-        ctx->tb_offset = 0;
-        /* TBL is still in T0 */
+        gen_op_load_tbl();
         break;
     case V_TBU:
-        gen_op_update_tb(ctx->tb_offset);
-        ctx->tb_offset = 0;
-        gen_op_load_tb(1);
+        gen_op_load_tbu();
         break;
     case DECR:
-        gen_op_update_decr(ctx->decr_offset);
-        ctx->decr_offset = 0;
-        /* decr is still in T0 */
+        gen_op_load_decr();
         break;
     default:
         gen_op_load_spr(sprn);
@@ -1939,18 +1935,16 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC)
         /* We need to update the time base before reading it */
     switch (sprn) {
     case V_TBL:
-        gen_op_update_tb(ctx->tb_offset);
         /* TBL is still in T0 */
+        gen_op_load_tbl();
         break;
     case V_TBU:
-        gen_op_update_tb(ctx->tb_offset);
-        gen_op_load_tb(1);
+        gen_op_load_tbu();
         break;
     default:
-        RET_INVAL();
-        break;
+        RET_INVAL(ctx);
+        return;
     }
-    ctx->tb_offset = 0;
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 
@@ -1965,15 +1959,16 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC)
 GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG();
+    RET_PRIVREG(ctx);
 #else
     if (!ctx->supervisor) {
-        RET_PRIVREG();
+        RET_PRIVREG(ctx);
+        return;
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_store_msr();
     /* Must stop the translation as machine state (may have) changed */
-    ctx->exception = EXCP_MTMSR;
+    RET_MTMSR(ctx);
 #endif
 }
 
@@ -1995,10 +1990,10 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
 #endif
     {
     case -1:
-        RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
+        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
         break;
     case 0:
-        RET_PRIVREG();
+        RET_PRIVREG(ctx);
         break;
     default:
         break;
@@ -2147,16 +2142,13 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
         gen_op_tlbia();
         break;
     case O_TBL:
-        gen_op_store_tb(0);
-        ctx->tb_offset = 0;
+        gen_op_store_tbl();
         break;
     case O_TBU:
-        gen_op_store_tb(1);
-        ctx->tb_offset = 0;
+        gen_op_store_tbu();
         break;
     case DECR:
         gen_op_store_decr();
-        ctx->decr_offset = 0;
         break;
     default:
         gen_op_store_spr(sprn);
@@ -2186,10 +2178,11 @@ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE)
 GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVOPC();
+    RET_PRIVOPC(ctx);
 #else
     if (!ctx->supervisor) {
-        RET_PRIVOPC();
+        RET_PRIVOPC(ctx);
+        return;
     }
     if (rA(ctx->opcode) == 0) {
         gen_op_load_gpr_T0(rB(ctx->opcode));
@@ -2274,10 +2267,11 @@ GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE_OPT)
 GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG();
+    RET_PRIVREG(ctx);
 #else
     if (!ctx->supervisor) {
-        RET_PRIVREG();
+        RET_PRIVREG(ctx);
+        return;
     }
     gen_op_load_sr(SR(ctx->opcode));
     gen_op_store_T0_gpr(rD(ctx->opcode));
@@ -2288,10 +2282,11 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
 GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG();
+    RET_PRIVREG(ctx);
 #else
     if (!ctx->supervisor) {
-        RET_PRIVREG();
+        RET_PRIVREG(ctx);
+        return;
     }
     gen_op_load_gpr_T1(rB(ctx->opcode));
     gen_op_load_srin();
@@ -2303,14 +2298,18 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
 GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG();
+    RET_PRIVREG(ctx);
 #else
     if (!ctx->supervisor) {
-        RET_PRIVREG();
+        RET_PRIVREG(ctx);
+        return;
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_store_sr(SR(ctx->opcode));
+#if 0
     gen_op_tlbia();
+    RET_MTMSR(ctx);
+#endif
 #endif
 }
 
@@ -2318,10 +2317,11 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
 GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG();
+    RET_PRIVREG(ctx);
 #else
     if (!ctx->supervisor) {
-        RET_PRIVREG();
+        RET_PRIVREG(ctx);
+        return;
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_load_gpr_T1(rB(ctx->opcode));
@@ -2336,10 +2336,13 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
 GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVOPC();
+    RET_PRIVOPC(ctx);
 #else
     if (!ctx->supervisor) {
-        RET_PRIVOPC();
+        if (loglevel)
+            fprintf(logfile, "%s: ! supervisor\n", __func__);
+        RET_PRIVOPC(ctx);
+        return;
     }
     gen_op_tlbia();
 #endif
@@ -2349,10 +2352,11 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT)
 GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVOPC();
+    RET_PRIVOPC(ctx);
 #else
     if (!ctx->supervisor) {
-        RET_PRIVOPC();
+        RET_PRIVOPC(ctx);
+        return;
     }
     gen_op_load_gpr_T0(rB(ctx->opcode));
     gen_op_tlbie();
@@ -2363,10 +2367,11 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
 GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVOPC();
+    RET_PRIVOPC(ctx);
 #else
     if (!ctx->supervisor) {
-        RET_PRIVOPC();
+        RET_PRIVOPC(ctx);
+        return;
     }
     /* This has no effect: it should ensure that all previous
      * tlbie have completed
@@ -2916,7 +2921,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags)
         fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
         }
     fprintf(f, " ] ");
-    fprintf(f, "TB: 0x%08x %08x\n", env->tb[1], env->tb[0]);
+    fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env),
+            cpu_ppc_load_tbl(env));
         for (i = 0; i < 16; i++) {
             if ((i & 3) == 0)
             fprintf(f, "FPR%02d:", i);
@@ -2924,8 +2930,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags)
             if ((i & 3) == 3)
             fprintf(f, "\n");
     }
-    fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x excp:0x%08x\n",
-            env->spr[SRR0], env->spr[SRR1], env->decr, env->exceptions);
+    fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n",
+            env->spr[SRR0], env->spr[SRR1], cpu_ppc_load_decr(env));
     fprintf(f, "reservation 0x%08x\n", env->reserve);
     fflush(f);
 }
@@ -2952,7 +2958,6 @@ CPUPPCState *cpu_ppc_init(void)
 //    env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */
 //    env->spr[PVR] = 0x00070100; /* IBM 750FX */
 #endif
-    env->decr = 0xFFFFFFFF;
     if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0)
         return NULL;
     init_spr_rights(env->spr[PVR]);
@@ -2976,14 +2981,13 @@ void cpu_ppc_close(CPUPPCState *env)
 }
 
 /*****************************************************************************/
-void raise_exception_err (int exception_index, int error_code);
 int print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
                         int dialect);
 
 int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
                                     int search_pc)
 {
-    DisasContext ctx;
+    DisasContext ctx, *ctxp = &ctx;
     opc_handler_t **table, *handler;
     uint32_t pc_start;
     uint16_t *gen_opc_end;
@@ -2994,8 +2998,6 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
     gen_opparam_ptr = gen_opparam_buf;
     ctx.nip = pc_start;
-    ctx.tb_offset = 0;
-    ctx.decr_offset = 0;
     ctx.tb = tb;
     ctx.exception = EXCP_NONE;
 #if defined(CONFIG_USER_ONLY)
@@ -3023,26 +3025,22 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
                 gen_opc_instr_start[lj] = 1;
             }
         }
-#if defined DEBUG_DISAS
-        if (loglevel > 0) {
+#if defined PPC_DEBUG_DISAS
+        if (loglevel & CPU_LOG_TB_IN_ASM) {
             fprintf(logfile, "----------------\n");
             fprintf(logfile, "nip=%08x super=%d ir=%d\n",
                     ctx.nip, 1 - msr_pr, msr_ir);
         }
 #endif
         ctx.opcode = ldl_code((void *)ctx.nip);
-#if defined DEBUG_DISAS
-        if (loglevel > 0) {
+#if defined PPC_DEBUG_DISAS
+        if (loglevel & CPU_LOG_TB_IN_ASM) {
             fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n",
                     ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
                     opc3(ctx.opcode));
         }
 #endif
         ctx.nip += 4;
-        ctx.tb_offset++;
-        /* Check decrementer exception */
-        if (++ctx.decr_offset == env->decr + 1)
-            ctx.exception = EXCP_DECR;
         table = ppc_opcodes;
         handler = table[opc1(ctx.opcode)];
         if (is_indirect_opcode(handler)) {
@@ -3098,26 +3096,17 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
                         (ctx.nip & 0xFC) != 0x04) &&
              ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI &&
              ctx.exception != EXCP_TRAP)) {
-#if !defined(CONFIG_USER_ONLY)
-            gen_op_queue_exception(EXCP_TRACE);
-#endif
-            if (ctx.exception == EXCP_NONE) {
-                ctx.exception = EXCP_TRACE;
-    }
+            RET_EXCP(ctxp, EXCP_TRACE, 0);
         }
         /* if we reach a page boundary, stop generation */
         if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) {
-            if (ctx.exception == EXCP_NONE) {
-        gen_op_b((long)ctx.tb, ctx.nip);
-                ctx.exception = EXCP_BRANCH;
-    }
+            RET_EXCP(ctxp, EXCP_BRANCH, 0);
     }
     }
-    /* In case of branch, this has already been done *BEFORE* the branch */
-    if (ctx.exception != EXCP_BRANCH && ctx.exception != EXCP_RFI) {
-        gen_op_update_tb(ctx.tb_offset);
-        gen_op_update_decr(ctx.decr_offset);
-        gen_op_process_exceptions(ctx.nip);
+    if (ctx.exception == EXCP_NONE) {
+        gen_op_b((unsigned long)ctx.tb, ctx.nip);
+    } else if (ctx.exception != EXCP_BRANCH) {
+        gen_op_set_T0(0);
     }
 #if 1
     /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump
@@ -3144,15 +3133,16 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     }
     env->access_type = ACCESS_INT;
 #ifdef DEBUG_DISAS
-    if (loglevel > 0) {
+    if (loglevel & CPU_LOG_TB_CPU) {
         fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
         cpu_ppc_dump_state(env, logfile, 0);
+    }
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
         fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start));
-#if defined(CONFIG_USER_ONLY)
        disas(logfile, (void *)pc_start, ctx.nip - pc_start, 0, 0);
-#endif
         fprintf(logfile, "\n");
-
+    }
+    if (loglevel & CPU_LOG_TB_OP) {
         fprintf(logfile, "OP:\n");
         dump_ops(gen_opc_buf, gen_opparam_buf);
         fprintf(logfile, "\n");