halt state support for ppc
[qemu] / target-ppc / translate.c
index 34f92bd..3bc6aa3 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  PPC emulation for qemu: main translation routines.
+ *  PowerPC emulation for qemu: main translation routines.
  * 
- *  Copyright (c) 2003 Jocelyn Mayer
+ *  Copyright (c) 2003-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include "dyngen-exec.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
 #include "cpu.h"
-#include "exec.h"
+#include "exec-all.h"
 #include "disas.h"
 
 //#define DO_SINGLE_STEP
-//#define DO_STEP_FLUSH
-//#define DEBUG_DISAS
+//#define PPC_DEBUG_DISAS
+
+#ifdef USE_DIRECT_JUMP
+#define TBPARAM(x)
+#else
+#define TBPARAM(x) (long)(x)
+#endif
 
 enum {
 #define DEF(s, n, copy_size) INDEX_op_ ## s,
@@ -127,45 +137,58 @@ static uint8_t  spr_access[1024 / 2];
 /* internal defines */
 typedef struct DisasContext {
     struct TranslationBlock *tb;
-    uint32_t *nip;
+    target_ulong nip;
     uint32_t opcode;
     uint32_t exception;
-    /* Time base offset */
-    uint32_t tb_offset;
-    /* Decrementer offset */
-    uint32_t decr_offset;
-    /* Execution mode */
+    /* Routine used to access memory */
+    int mem_idx;
+    /* Translation flags */
 #if !defined(CONFIG_USER_ONLY)
     int supervisor;
 #endif
-    /* Routine used to access memory */
-    int mem_idx;
+    int fpu_enabled;
+    ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
 } DisasContext;
 
-typedef struct opc_handler_t {
+struct opc_handler_t {
     /* invalid bits */
     uint32_t inval;
     /* instruction type */
     uint32_t type;
     /* handler */
     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()                                                         \
-RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
+#define RET_PRIVOPC(ctx)                                                      \
+RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
+
+#define RET_PRIVREG(ctx)                                                      \
+RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
+
+/* Stop translation */
+static inline void RET_STOP (DisasContext *ctx)
+{
+    gen_op_update_nip((ctx)->nip);
+    ctx->exception = EXCP_MTMSR;
+}
 
-#define RET_PRIVREG()                                                         \
-RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
+/* No need to update nip here, as execution flow will change */
+static inline void RET_CHG_FLOW (DisasContext *ctx)
+{
+    ctx->exception = EXCP_MTMSR;
+}
 
 #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                      \
 static void gen_##name (DisasContext *ctx);                                   \
@@ -174,13 +197,15 @@ static void gen_##name (DisasContext *ctx)
 
 typedef struct opcode_t {
     unsigned char opc1, opc2, opc3;
+#if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */
+    unsigned char pad[5];
+#else
+    unsigned char pad[1];
+#endif
     opc_handler_t handler;
+    const unsigned char *oname;
 } opcode_t;
 
-/* XXX: move that elsewhere */
-extern FILE *logfile;
-extern int loglevel;
-
 /***                           Instruction decoding                        ***/
 #define EXTRACT_HELPER(name, shift, nb)                                       \
 static inline uint32_t name (uint32_t opcode)                                 \
@@ -191,7 +216,7 @@ static inline uint32_t name (uint32_t opcode)                                 \
 #define EXTRACT_SHELPER(name, shift, nb)                                      \
 static inline int32_t name (uint32_t opcode)                                  \
 {                                                                             \
-    return s_ext16((opcode >> (shift)) & ((1 << (nb)) - 1));                  \
+    return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1));                \
 }
 
 /* Opcode part 1 */
@@ -219,7 +244,13 @@ EXTRACT_HELPER(crbD, 21, 5);
 EXTRACT_HELPER(crbA, 16, 5);
 EXTRACT_HELPER(crbB, 11, 5);
 /* SPR / TBL */
-EXTRACT_HELPER(SPR, 11, 10);
+EXTRACT_HELPER(_SPR, 11, 10);
+static inline uint32_t SPR (uint32_t opcode)
+{
+    uint32_t sprn = _SPR(opcode);
+
+    return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
+}
 /***                              Get constants                            ***/
 EXTRACT_HELPER(IMM, 12, 8);
 /* 16 bits signed immediate value */
@@ -275,30 +306,45 @@ static inline uint32_t MASK (uint32_t start, uint32_t end)
     return ret;
 }
 
+#if HOST_LONG_BITS == 64
+#define OPC_ALIGN 8
+#else
+#define OPC_ALIGN 4
+#endif
+#if defined(__APPLE__)
+#define OPCODES_SECTION \
+    __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
+#else
+#define OPCODES_SECTION \
+    __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
+#endif
+
 #define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
-__attribute__ ((section(".opcodes"), unused))                                 \
-static opcode_t opc_##name = {                                                \
+OPCODES_SECTION opcode_t opc_##name = {                                       \
     .opc1 = op1,                                                              \
     .opc2 = op2,                                                              \
     .opc3 = op3,                                                              \
+    .pad  = { 0, },                                                           \
     .handler = {                                                              \
         .inval   = invl,                                                      \
         .type = _typ,                                                         \
         .handler = &gen_##name,                                               \
     },                                                                        \
+    .oname = stringify(name),                                                 \
 }
 
 #define GEN_OPCODE_MARK(name)                                                 \
-__attribute__ ((section(".opcodes"), unused))                                 \
-static opcode_t opc_##name = {                                                \
+OPCODES_SECTION opcode_t opc_##name = {                                       \
     .opc1 = 0xFF,                                                             \
     .opc2 = 0xFF,                                                             \
     .opc3 = 0xFF,                                                             \
+    .pad  = { 0, },                                                           \
     .handler = {                                                              \
         .inval   = 0x00000000,                                                \
         .type = 0x00,                                                         \
         .handler = NULL,                                                      \
     },                                                                        \
+    .oname = stringify(name),                                                 \
 }
 
 /* Start opcode list */
@@ -307,29 +353,7 @@ GEN_OPCODE_MARK(start);
 /* Invalid instruction */
 GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
 {
-    RET_INVAL();
-}
-
-/* Special opcode to stop emulation */
-GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON)
-{
-    gen_op_queue_exception(EXCP_HLT);
-    ctx->exception = EXCP_HLT;
-}
-
-/* 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;
-}
-
-/* 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_INVAL(ctx);
 }
 
 static opc_handler_t invalid_handler = {
@@ -357,7 +381,7 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER)                       \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
     gen_op_##name();                                                          \
     if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0_ov();                                                  \
+        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
 }
 
@@ -376,7 +400,7 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER)                  \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_##name();                                                          \
     if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0_ov();                                                  \
+        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
 }
 
@@ -639,7 +663,7 @@ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
     if (uimm != 0)
-    gen_op_xori(UIMM(ctx->opcode));
+    gen_op_xori(uimm);
     gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 
@@ -654,7 +678,7 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
     if (uimm != 0)
-    gen_op_xori(UIMM(ctx->opcode) << 16);
+    gen_op_xori(uimm << 16);
     gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 
@@ -682,25 +706,29 @@ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
     mb = MB(ctx->opcode);
     me = ME(ctx->opcode);
     gen_op_load_gpr_T0(rS(ctx->opcode));
+#if 1 // TRY
+    if (sh == 0) {
+        gen_op_andi_(MASK(mb, me));
+        goto store;
+    }
+#endif
     if (mb == 0) {
         if (me == 31) {
             gen_op_rotlwi(sh);
             goto store;
+#if 0
         } else if (me == (31 - sh)) {
             gen_op_slwi(sh);
             goto store;
-        } else if (sh == 0) {
-            gen_op_andi_(MASK(0, me));
-            goto store;
+#endif
         }
     } else if (me == 31) {
+#if 0
         if (sh == (32 - mb)) {
             gen_op_srwi(mb);
             goto store;
-        } else if (sh == 0) {
-            gen_op_andi_(MASK(mb, 31));
-            goto store;
         }
+#endif
     }
     gen_op_rlwinm(sh, MASK(mb, me));
 store:
@@ -737,6 +765,7 @@ __GEN_LOGICAL2(sraw, 0x18, 0x18);
 GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
 {
     gen_op_load_gpr_T0(rS(ctx->opcode));
+    if (SH(ctx->opcode) != 0)
     gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
     if (Rc(ctx->opcode) != 0)
         gen_op_set_Rc0();
@@ -746,56 +775,81 @@ GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
 __GEN_LOGICAL2(srw, 0x18, 0x10);
 
 /***                       Floating-Point arithmetic                       ***/
-#define _GEN_FLOAT_ACB(name, op1, op2)                                        \
+#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat)                           \
 GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT)                   \
 {                                                                             \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rA(ctx->opcode));                                     \
     gen_op_load_fpr_FT1(rC(ctx->opcode));                                     \
     gen_op_load_fpr_FT2(rB(ctx->opcode));                                     \
-    gen_op_f##name();                                                         \
+    gen_op_f##op();                                                           \
+    if (isfloat) {                                                            \
+        gen_op_frsp();                                                        \
+    }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
     if (Rc(ctx->opcode))                                                      \
         gen_op_set_Rc1();                                                     \
 }
 
 #define GEN_FLOAT_ACB(name, op2)                                              \
-_GEN_FLOAT_ACB(name, 0x3F, op2);                                              \
-_GEN_FLOAT_ACB(name##s, 0x3B, op2);
+_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0);                                     \
+_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
 
-#define _GEN_FLOAT_AB(name, op1, op2, inval)                                  \
+#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat)                     \
 GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
 {                                                                             \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rA(ctx->opcode));                                     \
     gen_op_load_fpr_FT1(rB(ctx->opcode));                                     \
-    gen_op_f##name();                                                         \
+    gen_op_f##op();                                                           \
+    if (isfloat) {                                                            \
+        gen_op_frsp();                                                        \
+    }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
     if (Rc(ctx->opcode))                                                      \
         gen_op_set_Rc1();                                                     \
 }
 #define GEN_FLOAT_AB(name, op2, inval)                                        \
-_GEN_FLOAT_AB(name, 0x3F, op2, inval);                                        \
-_GEN_FLOAT_AB(name##s, 0x3B, op2, inval);
+_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0);                               \
+_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
 
-#define _GEN_FLOAT_AC(name, op1, op2, inval)                                  \
+#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat)                     \
 GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
 {                                                                             \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rA(ctx->opcode));                                     \
     gen_op_load_fpr_FT1(rC(ctx->opcode));                                     \
-    gen_op_f##name();                                                         \
+    gen_op_f##op();                                                           \
+    if (isfloat) {                                                            \
+        gen_op_frsp();                                                        \
+    }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
     if (Rc(ctx->opcode))                                                      \
         gen_op_set_Rc1();                                                     \
 }
 #define GEN_FLOAT_AC(name, op2, inval)                                        \
-_GEN_FLOAT_AC(name, 0x3F, op2, inval);                                        \
-_GEN_FLOAT_AC(name##s, 0x3B, op2, inval);
+_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0);                               \
+_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
 
 #define GEN_FLOAT_B(name, op2, op3)                                           \
 GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT)                   \
 {                                                                             \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rB(ctx->opcode));                                     \
     gen_op_f##name();                                                         \
@@ -804,9 +858,13 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT)                   \
         gen_op_set_Rc1();                                                     \
 }
 
-#define GEN_FLOAT_BS(name, op2)                                               \
-GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT)                  \
+#define GEN_FLOAT_BS(name, op1, op2)                                          \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT)                   \
 {                                                                             \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rB(ctx->opcode));                                     \
     gen_op_f##name();                                                         \
@@ -817,43 +875,60 @@ GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT)                  \
 
 /* fadd - fadds */
 GEN_FLOAT_AB(add, 0x15, 0x000007C0);
-/* fdiv */
+/* fdiv - fdivs */
 GEN_FLOAT_AB(div, 0x12, 0x000007C0);
-/* fmul */
+/* fmul - fmuls */
 GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
 
 /* fres */
-GEN_FLOAT_BS(res, 0x18);
+GEN_FLOAT_BS(res, 0x3B, 0x18);
 
 /* frsqrte */
-GEN_FLOAT_BS(rsqrte, 0x1A);
+GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
 
 /* fsel */
-_GEN_FLOAT_ACB(sel, 0x3F, 0x17);
-/* fsub */
+_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
+/* fsub - fsubs */
 GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
 /* Optional: */
 /* fsqrt */
-GEN_FLOAT_BS(sqrt, 0x16);
+GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
+{
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
+    gen_op_reset_scrfx();
+    gen_op_load_fpr_FT0(rB(ctx->opcode));
+    gen_op_fsqrt();
+    gen_op_store_FT0_fpr(rD(ctx->opcode));
+    if (Rc(ctx->opcode))
+        gen_op_set_Rc1();
+}
 
 GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
 {
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
     gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rB(ctx->opcode));
-    gen_op_fsqrts();
+    gen_op_fsqrt();
+    gen_op_frsp();
     gen_op_store_FT0_fpr(rD(ctx->opcode));
     if (Rc(ctx->opcode))
         gen_op_set_Rc1();
 }
 
 /***                     Floating-Point multiply-and-add                   ***/
-/* fmadd */
+/* fmadd - fmadds */
 GEN_FLOAT_ACB(madd, 0x1D);
-/* fmsub */
+/* fmsub - fmsubs */
 GEN_FLOAT_ACB(msub, 0x1C);
-/* fnmadd */
+/* fnmadd - fnmadds */
 GEN_FLOAT_ACB(nmadd, 0x1F);
-/* fnmsub */
+/* fnmsub - fnmsubs */
 GEN_FLOAT_ACB(nmsub, 0x1E);
 
 /***                     Floating-Point round & convert                    ***/
@@ -868,6 +943,10 @@ GEN_FLOAT_B(rsp, 0x0C, 0x00);
 /* fcmpo */
 GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
 {
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
     gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rA(ctx->opcode));
     gen_op_load_fpr_FT1(rB(ctx->opcode));
@@ -878,6 +957,10 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
 /* fcmpu */
 GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
 {
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
     gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rA(ctx->opcode));
     gen_op_load_fpr_FT1(rB(ctx->opcode));
@@ -892,6 +975,10 @@ GEN_FLOAT_B(abs, 0x08, 0x08);
 /* fmr  - fmr. */
 GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
 {
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
     gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rB(ctx->opcode));
     gen_op_store_FT0_fpr(rD(ctx->opcode));
@@ -908,6 +995,10 @@ GEN_FLOAT_B(neg, 0x08, 0x01);
 /* mcrfs */
 GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
 {
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
     gen_op_load_fpscr_T0(crfS(ctx->opcode));
     gen_op_store_T0_crf(crfD(ctx->opcode));
     gen_op_clear_fpscr(crfS(ctx->opcode));
@@ -916,6 +1007,10 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
 /* mffs */
 GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
 {
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
     gen_op_load_fpscr();
     gen_op_store_FT0_fpr(rD(ctx->opcode));
     if (Rc(ctx->opcode))
@@ -927,6 +1022,10 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
 {
     uint8_t crb;
     
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
     crb = crbD(ctx->opcode) >> 2;
     gen_op_load_fpscr_T0(crb);
     gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03)));
@@ -940,6 +1039,10 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
 {
     uint8_t crb;
     
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
     crb = crbD(ctx->opcode) >> 2;
     gen_op_load_fpscr_T0(crb);
     gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
@@ -951,6 +1054,10 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
 /* mtfsf */
 GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
 {
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
     gen_op_load_fpr_FT0(rB(ctx->opcode));
     gen_op_store_fpscr(FM(ctx->opcode));
     if (Rc(ctx->opcode))
@@ -960,28 +1067,51 @@ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
 /* mtfsfi */
 GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
 {
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
     gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
     if (Rc(ctx->opcode))
         gen_op_set_Rc1();
 }
 
 /***                             Integer load                              ***/
+#define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
 #if defined(CONFIG_USER_ONLY)
-#define op_ldst(name)        gen_op_##name##_raw()
-#define OP_LD_TABLE(width)
-#define OP_ST_TABLE(width)
+#define OP_LD_TABLE(width)                                                    \
+static GenOpFunc *gen_op_l##width[] = {                                       \
+    &gen_op_l##width##_raw,                                                   \
+    &gen_op_l##width##_le_raw,                                                \
+};
+#define OP_ST_TABLE(width)                                                    \
+static GenOpFunc *gen_op_st##width[] = {                                      \
+    &gen_op_st##width##_raw,                                                  \
+    &gen_op_st##width##_le_raw,                                               \
+};
+/* Byte access routine are endian safe */
+#define gen_op_stb_le_raw gen_op_stb_raw
+#define gen_op_lbz_le_raw gen_op_lbz_raw
 #else
-#define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
 #define OP_LD_TABLE(width)                                                    \
 static GenOpFunc *gen_op_l##width[] = {                                       \
     &gen_op_l##width##_user,                                                  \
+    &gen_op_l##width##_le_user,                                               \
     &gen_op_l##width##_kernel,                                                \
-}
+    &gen_op_l##width##_le_kernel,                                             \
+};
 #define OP_ST_TABLE(width)                                                    \
 static GenOpFunc *gen_op_st##width[] = {                                      \
     &gen_op_st##width##_user,                                                 \
+    &gen_op_st##width##_le_user,                                              \
     &gen_op_st##width##_kernel,                                               \
-}
+    &gen_op_st##width##_le_kernel,                                            \
+};
+/* Byte access routine are endian safe */
+#define gen_op_stb_le_user gen_op_stb_user
+#define gen_op_lbz_le_user gen_op_lbz_user
+#define gen_op_stb_le_kernel gen_op_stb_kernel
+#define gen_op_lbz_le_kernel gen_op_lbz_kernel
 #endif
 
 #define GEN_LD(width, opc)                                                    \
@@ -1005,7 +1135,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)                                                            \
@@ -1020,7 +1151,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));                                      \
@@ -1081,7 +1213,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)                                                            \
@@ -1095,7 +1228,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));                                      \
@@ -1148,17 +1282,28 @@ OP_ST_TABLE(wbr);
 GEN_STX(wbr, 0x16, 0x14);
 
 /***                    Integer load and store multiple                    ***/
+#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
 #if defined(CONFIG_USER_ONLY)
-#define op_ldstm(name, reg) gen_op_##name##_raw(reg)
+static GenOpFunc1 *gen_op_lmw[] = {
+    &gen_op_lmw_raw,
+    &gen_op_lmw_le_raw,
+};
+static GenOpFunc1 *gen_op_stmw[] = {
+    &gen_op_stmw_raw,
+    &gen_op_stmw_le_raw,
+};
 #else
-#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
 static GenOpFunc1 *gen_op_lmw[] = {
     &gen_op_lmw_user,
+    &gen_op_lmw_le_user,
     &gen_op_lmw_kernel,
+    &gen_op_lmw_le_kernel,
 };
 static GenOpFunc1 *gen_op_stmw[] = {
     &gen_op_stmw_user,
+    &gen_op_stmw_le_user,
     &gen_op_stmw_kernel,
+    &gen_op_stmw_le_kernel,
 };
 #endif
 
@@ -1193,28 +1338,44 @@ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 }
 
 /***                    Integer load and store strings                     ***/
-#if defined(CONFIG_USER_ONLY)
-#define op_ldsts(name, start) gen_op_##name##_raw(start)
-#define op_ldstsx(name, rd, ra, rb) gen_op_##name##_raw(rd, ra, rb)
-#else
 #define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
 #define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc1 *gen_op_lswi[] = {
+    &gen_op_lswi_raw,
+    &gen_op_lswi_le_raw,
+};
+static GenOpFunc3 *gen_op_lswx[] = {
+    &gen_op_lswx_raw,
+    &gen_op_lswx_le_raw,
+};
+static GenOpFunc1 *gen_op_stsw[] = {
+    &gen_op_stsw_raw,
+    &gen_op_stsw_le_raw,
+};
+#else
 static GenOpFunc1 *gen_op_lswi[] = {
     &gen_op_lswi_user,
+    &gen_op_lswi_le_user,
     &gen_op_lswi_kernel,
+    &gen_op_lswi_le_kernel,
 };
 static GenOpFunc3 *gen_op_lswx[] = {
     &gen_op_lswx_user,
+    &gen_op_lswx_le_user,
     &gen_op_lswx_kernel,
+    &gen_op_lswx_le_kernel,
 };
 static GenOpFunc1 *gen_op_stsw[] = {
     &gen_op_stsw_user,
+    &gen_op_stsw_le_user,
     &gen_op_stsw_kernel,
+    &gen_op_stsw_le_kernel,
 };
 #endif
 
 /* lswi */
-/* PPC32 specification says we must generate an exception if
+/* PowerPC32 specification says we must generate an exception if
  * rA is in the range of registers to be loaded.
  * In an other hand, IBM says this is valid, but rA won't be loaded.
  * For now, I'll follow the spec...
@@ -1229,16 +1390,19 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
     if (nb == 0)
         nb = 32;
     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);
-        }
+    if (((start + nr) > 32  && start <= ra && (start + nr - 32) > ra) ||
+        ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) {
+        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+        return;
+    }
     if (ra == 0) {
         gen_op_set_T0(0);
     } else {
         gen_op_load_gpr_T0(ra);
     }
     gen_op_set_T1(nb);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip((ctx)->nip - 4); 
     op_ldsts(lswi, start);
 }
 
@@ -1257,18 +1421,26 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
         gen_op_add();
     }
     gen_op_load_xer_bc();
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip((ctx)->nip - 4); 
     op_ldstsx(lswx, rD(ctx->opcode), ra, rb);
 }
 
 /* stswi */
 GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
 {
+    int nb = NB(ctx->opcode);
+
     if (rA(ctx->opcode) == 0) {
         gen_op_set_T0(0);
     } else {
         gen_op_load_gpr_T0(rA(ctx->opcode));
     }
-    gen_op_set_T1(NB(ctx->opcode));
+    if (nb == 0)
+        nb = 32;
+    gen_op_set_T1(nb);
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip((ctx)->nip - 4); 
     op_ldsts(stsw, rS(ctx->opcode));
 }
 
@@ -1286,6 +1458,8 @@ GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
         gen_op_add();
     }
     gen_op_load_xer_bc();
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip((ctx)->nip - 4); 
     op_ldsts(stsw, rS(ctx->opcode));
 }
 
@@ -1300,17 +1474,33 @@ GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM)
 {
 }
 
-/* lwarx */
+#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
+#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
 #if defined(CONFIG_USER_ONLY)
-#define op_stwcx() gen_op_stwcx_raw()
+static GenOpFunc *gen_op_lwarx[] = {
+    &gen_op_lwarx_raw,
+    &gen_op_lwarx_le_raw,
+};
+static GenOpFunc *gen_op_stwcx[] = {
+    &gen_op_stwcx_raw,
+    &gen_op_stwcx_le_raw,
+};
 #else
-#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
+static GenOpFunc *gen_op_lwarx[] = {
+    &gen_op_lwarx_user,
+    &gen_op_lwarx_le_user,
+    &gen_op_lwarx_kernel,
+    &gen_op_lwarx_le_kernel,
+};
 static GenOpFunc *gen_op_stwcx[] = {
     &gen_op_stwcx_user,
+    &gen_op_stwcx_le_user,
     &gen_op_stwcx_kernel,
+    &gen_op_stwcx_le_kernel,
 };
 #endif
 
+/* lwarx */
 GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
 {
     if (rA(ctx->opcode) == 0) {
@@ -1320,9 +1510,8 @@ GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
         gen_op_load_gpr_T1(rB(ctx->opcode));
         gen_op_add();
     }
-    op_ldst(lwz);
+    op_lwarx();
     gen_op_store_T1_gpr(rD(ctx->opcode));
-    gen_op_set_reservation();
 }
 
 /* stwcx. */
@@ -1346,9 +1535,13 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
 
 /***                         Floating-point load                           ***/
 #define GEN_LDF(width, opc)                                                   \
-GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)               \
+GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)                 \
 {                                                                             \
     uint32_t simm = SIMM(ctx->opcode);                                        \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     if (rA(ctx->opcode) == 0) {                                               \
         gen_op_set_T0(simm);                                                  \
     } else {                                                                  \
@@ -1361,12 +1554,17 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)               \
 }
 
 #define GEN_LDUF(width, opc)                                                  \
-GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)            \
+GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)              \
 {                                                                             \
     uint32_t simm = SIMM(ctx->opcode);                                        \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     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)                                                            \
@@ -1377,11 +1575,16 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)            \
 }
 
 #define GEN_LDUXF(width, opc)                                                 \
-GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)           \
+GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)             \
 {                                                                             \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     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));                                      \
@@ -1392,8 +1595,12 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)           \
 }
 
 #define GEN_LDXF(width, opc2, opc3)                                           \
-GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER)           \
+GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT)             \
 {                                                                             \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     if (rA(ctx->opcode) == 0) {                                               \
         gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
     } else {                                                                  \
@@ -1419,9 +1626,13 @@ GEN_LDFS(fs, 0x10);
 
 /***                         Floating-point store                          ***/
 #define GEN_STF(width, opc)                                                   \
-GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)              \
+GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)                \
 {                                                                             \
     uint32_t simm = SIMM(ctx->opcode);                                        \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     if (rA(ctx->opcode) == 0) {                                               \
         gen_op_set_T0(simm);                                                  \
     } else {                                                                  \
@@ -1434,11 +1645,16 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)              \
 }
 
 #define GEN_STUF(width, opc)                                                  \
-GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
+GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)             \
 {                                                                             \
     uint32_t simm = SIMM(ctx->opcode);                                        \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     if (rA(ctx->opcode) == 0) {                                               \
-        RET_INVAL();                                                          \
+        RET_INVAL(ctx);                                                       \
+        return;                                                               \
     }                                                                         \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     if (simm != 0)                                                            \
@@ -1449,10 +1665,15 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
 }
 
 #define GEN_STUXF(width, opc)                                                 \
-GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)          \
+GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)            \
 {                                                                             \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     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));                                      \
@@ -1463,8 +1684,12 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)          \
 }
 
 #define GEN_STXF(width, opc2, opc3)                                           \
-GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER)          \
+GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT)            \
 {                                                                             \
+    if (!ctx->fpu_enabled) {                                                  \
+        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+        return;                                                               \
+    }                                                                         \
     if (rA(ctx->opcode) == 0) {                                               \
         gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
     } else {                                                                  \
@@ -1492,214 +1717,168 @@ GEN_STFS(fs, 0x14);
 /* stfiwx */
 GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
 {
-    RET_INVAL();
+    if (!ctx->fpu_enabled) {
+        RET_EXCP(ctx, EXCP_NO_FP, 0);
+        return;
+    }
+    RET_INVAL(ctx);
 }
 
 /***                                Branch                                 ***/
-#define GEN_BCOND(name, opc1, opc2, opc3, prologue,                           \
-   bl_ctr,       b_ctr,       bl_ctrz,       b_ctrz,       b,        bl,      \
-   bl_ctr_true,  b_ctr_true,  bl_ctrz_true,  b_ctrz_true,  bl_true,  b_true,  \
-   bl_ctr_false, b_ctr_false, bl_ctrz_false, b_ctrz_false, bl_false, b_false) \
-GEN_HANDLER(name, opc1, opc2, opc3, 0x00000000, PPC_FLOW)                     \
-{                                                                             \
-    __attribute__ ((unused)) uint32_t target;                                 \
-    uint32_t bo = BO(ctx->opcode);                                            \
-    uint32_t bi = BI(ctx->opcode);                                            \
-    uint32_t mask;                                                            \
-    gen_op_update_tb(ctx->tb_offset);                                         \
-    gen_op_update_decr(ctx->decr_offset);                                     \
-    gen_op_process_exceptions((uint32_t)ctx->nip - 4);                        \
-    prologue;                                                                 \
-/*    gen_op_set_T1((uint32_t)ctx->tb);*/                                     \
-    if ((bo & 0x4) == 0)                                                      \
-        gen_op_dec_ctr();                                                     \
-    if (bo & 0x10) {                                                          \
-        /* No CR condition */                                                 \
-        switch (bo & 0x6) {                                                   \
-        case 0:                                                               \
-            if (LK(ctx->opcode)) {                                            \
-                bl_ctr;                                                       \
-            } else {                                                          \
-                b_ctr;                                                        \
-            }                                                                 \
-            break;                                                            \
-        case 2:                                                               \
-            if (LK(ctx->opcode)) {                                            \
-                bl_ctrz;                                                      \
-            } else {                                                          \
-                b_ctrz;                                                       \
-            }                                                                 \
-            break;                                                            \
-        case 4:                                                               \
-        case 6:                                                               \
-            if (LK(ctx->opcode)) {                                            \
-                bl;                                                           \
-            } else {                                                          \
-            b;                                                                \
-            }                                                                 \
-            break;                                                            \
-        default:                                                              \
-            printf("ERROR: %s: unhandled ba case (%d)\n", __func__, bo);      \
-            RET_INVAL();                                                      \
-            break;                                                            \
-        }                                                                     \
-    } else {                                                                  \
-        mask = 1 << (3 - (bi & 0x03));                                        \
-        gen_op_load_crf_T0(bi >> 2);                                          \
-        if (bo & 0x8) {                                                       \
-            switch (bo & 0x6) {                                               \
-            case 0:                                                           \
-                if (LK(ctx->opcode)) {                                        \
-                    bl_ctr_true;                                              \
-                } else {                                                      \
-                    b_ctr_true;                                               \
-                }                                                             \
-                break;                                                        \
-            case 2:                                                           \
-                if (LK(ctx->opcode)) {                                        \
-                    bl_ctrz_true;                                             \
-                } else {                                                      \
-                    b_ctrz_true;                                              \
-                }                                                             \
-                break;                                                        \
-            case 4:                                                           \
-            case 6:                                                           \
-                if (LK(ctx->opcode)) {                                        \
-                    bl_true;                                                  \
-                } else {                                                      \
-                    b_true;                                                   \
-                }                                                             \
-                break;                                                        \
-            default:                                                          \
-                printf("ERROR: %s: unhandled b case (%d)\n", __func__, bo);   \
-                RET_INVAL();                                                  \
-                break;                                                        \
-            }                                                                 \
-        } else {                                                              \
-            switch (bo & 0x6) {                                               \
-            case 0:                                                           \
-                if (LK(ctx->opcode)) {                                        \
-                    bl_ctr_false;                                             \
-                } else {                                                      \
-                    b_ctr_false;                                              \
-                }                                                             \
-                break;                                                        \
-            case 2:                                                           \
-                if (LK(ctx->opcode)) {                                        \
-                    bl_ctrz_false;                                            \
-                } else {                                                      \
-                    b_ctrz_false;                                             \
-                }                                                             \
-                break;                                                        \
-            case 4:                                                           \
-            case 6:                                                           \
-                if (LK(ctx->opcode)) {                                        \
-                    bl_false;                                                 \
-                } else {                                                      \
-                    b_false;                                                  \
-                }                                                             \
-                break;                                                        \
-            default:                                                          \
-                printf("ERROR: %s: unhandled bn case (%d)\n", __func__, bo);  \
-                RET_INVAL();                                                  \
-                break;                                                        \
-            }                                                                 \
-        }                                                                     \
-    }                                                                         \
-    ctx->exception = EXCP_BRANCH;                                             \
+
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+    tb = ctx->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+        if (n == 0)
+            gen_op_goto_tb0(TBPARAM(tb));
+        else
+            gen_op_goto_tb1(TBPARAM(tb));
+        gen_op_set_T1(dest);
+        gen_op_b_T1();
+        gen_op_set_T0((long)tb + n);
+        gen_op_exit_tb();
+    } else {
+        gen_op_set_T1(dest);
+        gen_op_b_T1();
+        gen_op_set_T0(0);
+        gen_op_exit_tb();
+    }
 }
 
 /* b ba bl bla */
 GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
 {
-    uint32_t li = s_ext24(LI(ctx->opcode)), target;
+    uint32_t li, target;
+
+    /* sign extend LI */
+    li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
 
-    gen_op_update_tb(ctx->tb_offset);
-    gen_op_update_decr(ctx->decr_offset);
-    gen_op_process_exceptions((uint32_t)ctx->nip - 4);
     if (AA(ctx->opcode) == 0)
-        target = (uint32_t)ctx->nip + li - 4;
+        target = ctx->nip + li - 4;
     else
         target = li;
-//    gen_op_set_T1((uint32_t)ctx->tb);
     if (LK(ctx->opcode)) {
-        gen_op_bl(target, (uint32_t)ctx->nip);
-    } else {
-    gen_op_b(target);
+        gen_op_setlr(ctx->nip);
     }
+    gen_goto_tb(ctx, 0, target);
     ctx->exception = EXCP_BRANCH;
 }
 
-/* bc bca bcl bcla */
-GEN_BCOND(bc, 0x10, 0xFF, 0xFF,
-          do {
-              uint32_t li = s_ext16(BD(ctx->opcode));
-              if (AA(ctx->opcode) == 0) {
-                  target = (uint32_t)ctx->nip + li - 4;
-              } else {
-                  target = li;
-              }
-          } while (0),
-          gen_op_bl_ctr((uint32_t)ctx->nip, target),
-          gen_op_b_ctr((uint32_t)ctx->nip, target),
-          gen_op_bl_ctrz((uint32_t)ctx->nip, target),
-          gen_op_b_ctrz((uint32_t)ctx->nip, target),
-          gen_op_b(target),
-          gen_op_bl(target, (uint32_t)ctx->nip),
-          gen_op_bl_ctr_true((uint32_t)ctx->nip, target, mask),
-          gen_op_b_ctr_true((uint32_t)ctx->nip, target, mask),
-          gen_op_bl_ctrz_true((uint32_t)ctx->nip, target, mask),
-          gen_op_b_ctrz_true((uint32_t)ctx->nip, target, mask),
-          gen_op_bl_true((uint32_t)ctx->nip, target, mask),
-          gen_op_b_true((uint32_t)ctx->nip, target, mask),
-          gen_op_bl_ctr_false((uint32_t)ctx->nip, target, mask),
-          gen_op_b_ctr_false((uint32_t)ctx->nip, target, mask),
-          gen_op_bl_ctrz_false((uint32_t)ctx->nip, target, mask),
-          gen_op_b_ctrz_false((uint32_t)ctx->nip, target, mask),
-          gen_op_bl_false((uint32_t)ctx->nip, target, mask),
-          gen_op_b_false((uint32_t)ctx->nip, target, mask));
-
-/* bcctr bcctrl */
-GEN_BCOND(bcctr, 0x13, 0x10, 0x10, do { } while (0),
-          gen_op_bctrl_ctr((uint32_t)ctx->nip),
-          gen_op_bctr_ctr((uint32_t)ctx->nip),
-          gen_op_bctrl_ctrz((uint32_t)ctx->nip),
-          gen_op_bctr_ctrz((uint32_t)ctx->nip),
-          gen_op_bctr(),
-          gen_op_bctrl((uint32_t)ctx->nip),
-          gen_op_bctrl_ctr_true((uint32_t)ctx->nip, mask),
-          gen_op_bctr_ctr_true((uint32_t)ctx->nip, mask),
-          gen_op_bctrl_ctrz_true((uint32_t)ctx->nip, mask),
-          gen_op_bctr_ctrz_true((uint32_t)ctx->nip, mask),
-          gen_op_bctrl_true((uint32_t)ctx->nip, mask),
-          gen_op_bctr_true((uint32_t)ctx->nip, mask),
-          gen_op_bctrl_ctr_false((uint32_t)ctx->nip, mask),
-          gen_op_bctr_ctr_false((uint32_t)ctx->nip, mask),
-          gen_op_bctrl_ctrz_false((uint32_t)ctx->nip, mask),
-          gen_op_bctr_ctrz_false((uint32_t)ctx->nip, mask),
-          gen_op_bctrl_false((uint32_t)ctx->nip, mask),
-          gen_op_bctr_false((uint32_t)ctx->nip, mask))
-
-/* bclr bclrl */
-GEN_BCOND(bclr, 0x13, 0x10, 0x00, do { } while (0),
-          gen_op_blrl_ctr((uint32_t)ctx->nip),
-          gen_op_blr_ctr((uint32_t)ctx->nip),
-          gen_op_blrl_ctrz((uint32_t)ctx->nip),
-          gen_op_blr_ctrz((uint32_t)ctx->nip),
-          gen_op_blr(),
-          gen_op_blrl((uint32_t)ctx->nip),
-          gen_op_blrl_ctr_true((uint32_t)ctx->nip, mask),
-          gen_op_blr_ctr_true((uint32_t)ctx->nip, mask),
-          gen_op_blrl_ctrz_true((uint32_t)ctx->nip, mask),
-          gen_op_blr_ctrz_true((uint32_t)ctx->nip, mask),
-          gen_op_blrl_true((uint32_t)ctx->nip, mask),
-          gen_op_blr_true((uint32_t)ctx->nip, mask),
-          gen_op_blrl_ctr_false((uint32_t)ctx->nip, mask),
-          gen_op_blr_ctr_false((uint32_t)ctx->nip, mask),
-          gen_op_blrl_ctrz_false((uint32_t)ctx->nip, mask),
-          gen_op_blr_ctrz_false((uint32_t)ctx->nip, mask),
-          gen_op_blrl_false((uint32_t)ctx->nip, mask),
-          gen_op_blr_false((uint32_t)ctx->nip, mask))
+#define BCOND_IM  0
+#define BCOND_LR  1
+#define BCOND_CTR 2
+
+static inline void gen_bcond(DisasContext *ctx, int type) 
+{                                                                             
+    uint32_t target = 0;
+    uint32_t bo = BO(ctx->opcode);                                            
+    uint32_t bi = BI(ctx->opcode);                                            
+    uint32_t mask;                                                            
+    uint32_t li;
+
+    if ((bo & 0x4) == 0)
+        gen_op_dec_ctr();                                                     
+    switch(type) {
+    case BCOND_IM:
+        li = (int32_t)((int16_t)(BD(ctx->opcode)));
+        if (AA(ctx->opcode) == 0) {
+            target = ctx->nip + li - 4;
+        } else {
+            target = li;
+        }
+        break;
+    case BCOND_CTR:
+        gen_op_movl_T1_ctr();
+        break;
+    default:
+    case BCOND_LR:
+        gen_op_movl_T1_lr();
+        break;
+    }
+    if (LK(ctx->opcode)) {                                        
+        gen_op_setlr(ctx->nip);
+    }
+    if (bo & 0x10) {
+        /* No CR condition */                                                 
+        switch (bo & 0x6) {                                                   
+        case 0:                                                               
+            gen_op_test_ctr();
+            break;
+        case 2:                                                               
+            gen_op_test_ctrz();
+            break;                                                            
+        default:
+        case 4:                                                               
+        case 6:                                                               
+            if (type == BCOND_IM) {
+                gen_goto_tb(ctx, 0, target);
+            } else {
+                gen_op_b_T1();
+            }
+            goto no_test;
+        }
+    } else {                                                                  
+        mask = 1 << (3 - (bi & 0x03));                                        
+        gen_op_load_crf_T0(bi >> 2);                                          
+        if (bo & 0x8) {                                                       
+            switch (bo & 0x6) {                                               
+            case 0:                                                           
+                gen_op_test_ctr_true(mask);
+                break;                                                        
+            case 2:                                                           
+                gen_op_test_ctrz_true(mask);
+                break;                                                        
+            default:                                                          
+            case 4:                                                           
+            case 6:                                                           
+                gen_op_test_true(mask);
+                break;                                                        
+            }                                                                 
+        } else {                                                              
+            switch (bo & 0x6) {                                               
+            case 0:                                                           
+                gen_op_test_ctr_false(mask);
+                break;                                                        
+            case 2:                                                           
+                gen_op_test_ctrz_false(mask);
+                break;                                                        
+            default:
+            case 4:                                                           
+            case 6:                                                           
+                gen_op_test_false(mask);
+                break;                                                        
+            }                                                                 
+        }                                                                     
+    }                                                                         
+    if (type == BCOND_IM) {
+        int l1 = gen_new_label();
+        gen_op_jz_T0(l1);
+        gen_goto_tb(ctx, 0, target);
+        gen_set_label(l1);
+        gen_goto_tb(ctx, 1, ctx->nip);
+    } else {
+        gen_op_btest_T1(ctx->nip);
+    }
+ no_test:
+    ctx->exception = EXCP_BRANCH;                                             
+}
+
+GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
+{                                                                             
+    gen_bcond(ctx, BCOND_IM);
+}
+
+GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
+{                                                                             
+    gen_bcond(ctx, BCOND_CTR);
+}
+
+GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
+{                                                                             
+    gen_bcond(ctx, BCOND_LR);
+}
 
 /***                      Condition register logical                       ***/
 #define GEN_CRLOGIC(op, opc)                                                  \
@@ -1744,14 +1923,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_CHG_FLOW(ctx);
 #endif
 }
 
@@ -1759,11 +1939,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                                   ***/
@@ -1831,192 +2010,78 @@ 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));
 #endif
 }
 
+#if 0
+#define SPR_NOACCESS ((void *)(-1))
+#else
+static void spr_noaccess (void *opaque, int sprn)
+{
+    sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
+    printf("ERROR: try to access SPR %d !\n", sprn);
+}
+#define SPR_NOACCESS (&spr_noaccess)
+#endif
+
 /* mfspr */
-GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
+static inline void gen_op_mfspr (DisasContext *ctx)
 {
+    void (*read_cb)(void *opaque, int sprn);
     uint32_t sprn = SPR(ctx->opcode);
 
-#if defined(CONFIG_USER_ONLY)
-    switch (check_spr_access(sprn, 0, 0))
-#else
-    switch (check_spr_access(sprn, 0, ctx->supervisor))
+#if !defined(CONFIG_USER_ONLY)
+    if (ctx->supervisor)
+        read_cb = ctx->spr_cb[sprn].oea_read;
+    else
 #endif
-    {
-    case -1:
-        RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
-        break;
-    case 0:
-        RET_PRIVREG();
-        break;
-    default:
-        break;
+        read_cb = ctx->spr_cb[sprn].uea_read;
+    if (read_cb != NULL) {
+        if (read_cb != SPR_NOACCESS) {
+            (*read_cb)(ctx, sprn);
+            gen_op_store_T0_gpr(rD(ctx->opcode));
+        } else {
+            /* Privilege exception */
+            if (loglevel) {
+                fprintf(logfile, "Trying to read priviledged spr %d %03x\n",
+                        sprn, sprn);
+            }
+            printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
+        RET_PRIVREG(ctx);
         }
-    switch (sprn) {
-    case XER:
-        gen_op_load_xer();
-        break;
-    case LR:
-        gen_op_load_lr();
-        break;
-    case CTR:
-        gen_op_load_ctr();
-        break;
-    case IBAT0U:
-        gen_op_load_ibat(0, 0);
-        break;
-    case IBAT1U:
-        gen_op_load_ibat(0, 1);
-        break;
-    case IBAT2U:
-        gen_op_load_ibat(0, 2);
-        break;
-    case IBAT3U:
-        gen_op_load_ibat(0, 3);
-        break;
-    case IBAT4U:
-        gen_op_load_ibat(0, 4);
-        break;
-    case IBAT5U:
-        gen_op_load_ibat(0, 5);
-        break;
-    case IBAT6U:
-        gen_op_load_ibat(0, 6);
-        break;
-    case IBAT7U:
-        gen_op_load_ibat(0, 7);
-        break;
-    case IBAT0L:
-        gen_op_load_ibat(1, 0);
-        break;
-    case IBAT1L:
-        gen_op_load_ibat(1, 1);
-        break;
-    case IBAT2L:
-        gen_op_load_ibat(1, 2);
-        break;
-    case IBAT3L:
-        gen_op_load_ibat(1, 3);
-        break;
-    case IBAT4L:
-        gen_op_load_ibat(1, 4);
-        break;
-    case IBAT5L:
-        gen_op_load_ibat(1, 5);
-        break;
-    case IBAT6L:
-        gen_op_load_ibat(1, 6);
-        break;
-    case IBAT7L:
-        gen_op_load_ibat(1, 7);
-        break;
-    case DBAT0U:
-        gen_op_load_dbat(0, 0);
-        break;
-    case DBAT1U:
-        gen_op_load_dbat(0, 1);
-        break;
-    case DBAT2U:
-        gen_op_load_dbat(0, 2);
-        break;
-    case DBAT3U:
-        gen_op_load_dbat(0, 3);
-        break;
-    case DBAT4U:
-        gen_op_load_dbat(0, 4);
-        break;
-    case DBAT5U:
-        gen_op_load_dbat(0, 5);
-        break;
-    case DBAT6U:
-        gen_op_load_dbat(0, 6);
-        break;
-    case DBAT7U:
-        gen_op_load_dbat(0, 7);
-        break;
-    case DBAT0L:
-        gen_op_load_dbat(1, 0);
-        break;
-    case DBAT1L:
-        gen_op_load_dbat(1, 1);
-        break;
-    case DBAT2L:
-        gen_op_load_dbat(1, 2);
-        break;
-    case DBAT3L:
-        gen_op_load_dbat(1, 3);
-        break;
-    case DBAT4L:
-        gen_op_load_dbat(1, 4);
-        break;
-    case DBAT5L:
-        gen_op_load_dbat(1, 5);
-        break;
-    case DBAT6L:
-        gen_op_load_dbat(1, 6);
-        break;
-    case DBAT7L:
-        gen_op_load_dbat(1, 7);
-        break;
-    case SDR1:
-        gen_op_load_sdr1();
-        break;
-    case V_TBL:
-        gen_op_update_tb(ctx->tb_offset);
-        ctx->tb_offset = 0;
-        /* TBL is still in T0 */
-        break;
-    case V_TBU:
-        gen_op_update_tb(ctx->tb_offset);
-        ctx->tb_offset = 0;
-        gen_op_load_tb(1);
-        break;
-    case DECR:
-        gen_op_update_decr(ctx->decr_offset);
-        ctx->decr_offset = 0;
-        /* decr is still in T0 */
-        break;
-    default:
-        gen_op_load_spr(sprn);
-        break;
+    } else {
+        /* Not defined */
+        if (loglevel) {
+            fprintf(logfile, "Trying to read invalid spr %d %03x\n",
+                    sprn, sprn);
+        }
+        printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
+        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
     }
-    gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 
-/* mftb */
-GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC)
+GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
 {
-    uint32_t sprn = SPR(ctx->opcode);
-
-        /* 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 */
-        break;
-    case V_TBU:
-        gen_op_update_tb(ctx->tb_offset);
-        gen_op_load_tb(1);
-        break;
-    default:
-        RET_INVAL();
-        break;
+    gen_op_mfspr(ctx);
     }
-    ctx->tb_offset = 0;
-    gen_op_store_T0_gpr(rD(ctx->opcode));
-}
+
+/* mftb */
+GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
+{
+    gen_op_mfspr(ctx);
+}
 
 /* mtcrf */
-GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC)
+/* The mask should be 0x00100801, but Mac OS X 10.4 use an alternate form */
+GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
 {
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_store_cr(CRM(ctx->opcode));
@@ -2026,203 +2091,53 @@ 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_update_nip((ctx)->nip);
     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_CHG_FLOW(ctx);
 #endif
 }
 
 /* mtspr */
 GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
 {
+    void (*write_cb)(void *opaque, int sprn);
     uint32_t sprn = SPR(ctx->opcode);
 
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "MTSPR %d src=%d (%d)\n", SPR_ENCODE(sprn),
-                rS(ctx->opcode), sprn);
-    }
-#endif
-#if defined(CONFIG_USER_ONLY)
-    switch (check_spr_access(sprn, 1, 0))
-#else
-    switch (check_spr_access(sprn, 1, ctx->supervisor))
+#if !defined(CONFIG_USER_ONLY)
+    if (ctx->supervisor)
+        write_cb = ctx->spr_cb[sprn].oea_write;
+    else
 #endif
-    {
-    case -1:
-        RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
-        break;
-    case 0:
-        RET_PRIVREG();
-        break;
-    default:
-        break;
+        write_cb = ctx->spr_cb[sprn].uea_write;
+    if (write_cb != NULL) {
+        if (write_cb != SPR_NOACCESS) {
+            gen_op_load_gpr_T0(rS(ctx->opcode));
+            (*write_cb)(ctx, sprn);
+        } else {
+            /* Privilege exception */
+            if (loglevel) {
+                fprintf(logfile, "Trying to write priviledged spr %d %03x\n",
+                        sprn, sprn);
+            }
+            printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
+        RET_PRIVREG(ctx);
     }
-    gen_op_load_gpr_T0(rS(ctx->opcode));
-    switch (sprn) {
-    case XER:
-        gen_op_store_xer();
-        break;
-    case LR:
-        gen_op_andi_(~0x03);
-        gen_op_store_lr();
-        break;
-    case CTR:
-        gen_op_store_ctr();
-        break;
-    case IBAT0U:
-        gen_op_store_ibat(0, 0);
-        gen_op_tlbia();
-        break;
-    case IBAT1U:
-        gen_op_store_ibat(0, 1);
-        gen_op_tlbia();
-        break;
-    case IBAT2U:
-        gen_op_store_ibat(0, 2);
-        gen_op_tlbia();
-        break;
-    case IBAT3U:
-        gen_op_store_ibat(0, 3);
-        gen_op_tlbia();
-        break;
-    case IBAT4U:
-        gen_op_store_ibat(0, 4);
-        gen_op_tlbia();
-        break;
-    case IBAT5U:
-        gen_op_store_ibat(0, 5);
-        gen_op_tlbia();
-        break;
-    case IBAT6U:
-        gen_op_store_ibat(0, 6);
-        gen_op_tlbia();
-        break;
-    case IBAT7U:
-        gen_op_store_ibat(0, 7);
-        gen_op_tlbia();
-        break;
-    case IBAT0L:
-        gen_op_store_ibat(1, 0);
-        gen_op_tlbia();
-        break;
-    case IBAT1L:
-        gen_op_store_ibat(1, 1);
-        gen_op_tlbia();
-        break;
-    case IBAT2L:
-        gen_op_store_ibat(1, 2);
-        gen_op_tlbia();
-        break;
-    case IBAT3L:
-        gen_op_store_ibat(1, 3);
-        gen_op_tlbia();
-        break;
-    case IBAT4L:
-        gen_op_store_ibat(1, 4);
-        gen_op_tlbia();
-        break;
-    case IBAT5L:
-        gen_op_store_ibat(1, 5);
-        gen_op_tlbia();
-        break;
-    case IBAT6L:
-        gen_op_store_ibat(1, 6);
-        gen_op_tlbia();
-        break;
-    case IBAT7L:
-        gen_op_store_ibat(1, 7);
-        gen_op_tlbia();
-        break;
-    case DBAT0U:
-        gen_op_store_dbat(0, 0);
-        gen_op_tlbia();
-        break;
-    case DBAT1U:
-        gen_op_store_dbat(0, 1);
-        gen_op_tlbia();
-        break;
-    case DBAT2U:
-        gen_op_store_dbat(0, 2);
-        gen_op_tlbia();
-        break;
-    case DBAT3U:
-        gen_op_store_dbat(0, 3);
-        gen_op_tlbia();
-        break;
-    case DBAT4U:
-        gen_op_store_dbat(0, 4);
-        gen_op_tlbia();
-        break;
-    case DBAT5U:
-        gen_op_store_dbat(0, 5);
-        gen_op_tlbia();
-        break;
-    case DBAT6U:
-        gen_op_store_dbat(0, 6);
-        gen_op_tlbia();
-        break;
-    case DBAT7U:
-        gen_op_store_dbat(0, 7);
-        gen_op_tlbia();
-        break;
-    case DBAT0L:
-        gen_op_store_dbat(1, 0);
-        gen_op_tlbia();
-        break;
-    case DBAT1L:
-        gen_op_store_dbat(1, 1);
-        gen_op_tlbia();
-        break;
-    case DBAT2L:
-        gen_op_store_dbat(1, 2);
-        gen_op_tlbia();
-        break;
-    case DBAT3L:
-        gen_op_store_dbat(1, 3);
-        gen_op_tlbia();
-        break;
-    case DBAT4L:
-        gen_op_store_dbat(1, 4);
-        gen_op_tlbia();
-        break;
-    case DBAT5L:
-        gen_op_store_dbat(1, 5);
-        gen_op_tlbia();
-        break;
-    case DBAT6L:
-        gen_op_store_dbat(1, 6);
-        gen_op_tlbia();
-        break;
-    case DBAT7L:
-        gen_op_store_dbat(1, 7);
-        gen_op_tlbia();
-        break;
-    case SDR1:
-        gen_op_store_sdr1();
-        gen_op_tlbia();
-        break;
-    case O_TBL:
-        gen_op_store_tb(0);
-        ctx->tb_offset = 0;
-        break;
-    case O_TBU:
-        gen_op_store_tb(1);
-        ctx->tb_offset = 0;
-        break;
-    case DECR:
-        gen_op_store_decr();
-        ctx->decr_offset = 0;
-        break;
-    default:
-        gen_op_store_spr(sprn);
-        break;
+    } else {
+        /* Not defined */
+        if (loglevel) {
+            fprintf(logfile, "Trying to write invalid spr %d %03x\n",
+                    sprn, sprn);
+        }
+        printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
+        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
     }
 }
 
@@ -2234,22 +2149,49 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
 /* dcbf */
 GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE)
 {
+    if (rA(ctx->opcode) == 0) {
+        gen_op_load_gpr_T0(rB(ctx->opcode));
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rB(ctx->opcode));
+        gen_op_add();
+    }
+    op_ldst(lbz);
 }
 
 /* dcbi (Supervisor only) */
 GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
 {
-#if !defined(CONFIG_USER_ONLY)
-    if (!ctx->supervisor)
-#endif
-    {
-        RET_PRIVOPC();
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (!ctx->supervisor) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    if (rA(ctx->opcode) == 0) {
+        gen_op_load_gpr_T0(rB(ctx->opcode));
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rB(ctx->opcode));
+        gen_op_add();
     }
+    op_ldst(lbz);
+    op_ldst(stb);
+#endif
 }
 
 /* dcdst */
 GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
 {
+    if (rA(ctx->opcode) == 0) {
+        gen_op_load_gpr_T0(rB(ctx->opcode));
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rB(ctx->opcode));
+        gen_op_add();
+    }
+    op_ldst(lbz);
 }
 
 /* dcbt */
@@ -2269,6 +2211,8 @@ GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
 #define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
 static GenOpFunc *gen_op_dcbz[] = {
     &gen_op_dcbz_user,
+    &gen_op_dcbz_user,
+    &gen_op_dcbz_kernel,
     &gen_op_dcbz_kernel,
 };
 #endif
@@ -2283,6 +2227,7 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
         gen_op_add();
     }
     op_dcbz();
+    gen_op_check_reservation();
 }
 
 /* icbi */
@@ -2300,7 +2245,7 @@ GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE)
 
 /* Optional: */
 /* dcba */
-GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE_OPT)
+GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_OPT)
 {
 }
 
@@ -2310,10 +2255,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));
@@ -2324,10 +2270,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();
@@ -2336,17 +2283,18 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
 }
 
 /* mtsr */
-GEN_HANDLER(mtsr, 0x1F, 0x12, 0x02, 0x0010F801, 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));
-    gen_op_tlbia();
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2354,30 +2302,35 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x02, 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));
     gen_op_store_srin();
-    gen_op_tlbia();
+    RET_STOP(ctx);
 #endif
 }
 
 /***                      Lookaside buffer management                      ***/
 /* Optional & supervisor only: */
 /* tlbia */
-GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT)
+GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
 {
 #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();
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2385,50 +2338,64 @@ 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();
+    RET_STOP(ctx);
 #endif
 }
 
 /* tlbsync */
-GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFFC01, 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
      */
+    RET_STOP(ctx);
 #endif
 }
 
 /***                              External control                         ***/
 /* Optional: */
-/* eciwx */
-#if defined(CONFIG_USER_ONLY)
-#define op_eciwx() gen_op_eciwx_raw()
-#define op_ecowx() gen_op_ecowx_raw()
-#else
 #define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
 #define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_eciwx[] = {
+    &gen_op_eciwx_raw,
+    &gen_op_eciwx_le_raw,
+};
+static GenOpFunc *gen_op_ecowx[] = {
+    &gen_op_ecowx_raw,
+    &gen_op_ecowx_le_raw,
+};
+#else
 static GenOpFunc *gen_op_eciwx[] = {
     &gen_op_eciwx_user,
+    &gen_op_eciwx_le_user,
     &gen_op_eciwx_kernel,
+    &gen_op_eciwx_le_kernel,
 };
 static GenOpFunc *gen_op_ecowx[] = {
     &gen_op_ecowx_user,
+    &gen_op_ecowx_le_user,
     &gen_op_ecowx_kernel,
+    &gen_op_ecowx_le_kernel,
 };
 #endif
 
+/* eciwx */
 GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
 {
     /* Should check EAR[E] & alignment ! */
@@ -2461,486 +2428,44 @@ GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
 /* End opcode list */
 GEN_OPCODE_MARK(end);
 
-/*****************************************************************************/
-#include <stdlib.h>
-#include <string.h>
-
-int fflush (FILE *stream);
-
-/* Main ppc opcodes table:
- * at init, all opcodes are invalids
- */
-static opc_handler_t *ppc_opcodes[0x40];
-
-/* Opcode types */
-enum {
-    PPC_DIRECT   = 0, /* Opcode routine        */
-    PPC_INDIRECT = 1, /* Indirect opcode table */
-};
-
-static inline int is_indirect_opcode (void *handler)
-{
-    return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
-}
-
-static inline opc_handler_t **ind_table(void *handler)
-{
-    return (opc_handler_t **)((unsigned long)handler & ~3);
-}
-
-/* Instruction table creation */
-/* Opcodes tables creation */
-static void fill_new_table (opc_handler_t **table, int len)
-{
-    int i;
-
-    for (i = 0; i < len; i++)
-        table[i] = &invalid_handler;
-}
-
-static int create_new_table (opc_handler_t **table, unsigned char idx)
-{
-    opc_handler_t **tmp;
-
-    tmp = malloc(0x20 * sizeof(opc_handler_t));
-    if (tmp == NULL)
-        return -1;
-    fill_new_table(tmp, 0x20);
-    table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
-
-    return 0;
-}
-
-static int insert_in_table (opc_handler_t **table, unsigned char idx,
-                            opc_handler_t *handler)
-{
-    if (table[idx] != &invalid_handler)
-        return -1;
-    table[idx] = handler;
-
-    return 0;
-}
-
-static int register_direct_insn (opc_handler_t **ppc_opcodes,
-                                 unsigned char idx, opc_handler_t *handler)
-{
-    if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
-        printf("*** ERROR: opcode %02x already assigned in main "
-                "opcode table\n", idx);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int register_ind_in_table (opc_handler_t **table,
-                                  unsigned char idx1, unsigned char idx2,
-                                  opc_handler_t *handler)
-{
-    if (table[idx1] == &invalid_handler) {
-        if (create_new_table(table, idx1) < 0) {
-            printf("*** ERROR: unable to create indirect table "
-                    "idx=%02x\n", idx1);
-            return -1;
-        }
-    } else {
-        if (!is_indirect_opcode(table[idx1])) {
-            printf("*** ERROR: idx %02x already assigned to a direct "
-                    "opcode\n", idx1);
-            return -1;
-        }
-    }
-    if (handler != NULL &&
-        insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
-        printf("*** ERROR: opcode %02x already assigned in "
-                "opcode table %02x\n", idx2, idx1);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int register_ind_insn (opc_handler_t **ppc_opcodes,
-                              unsigned char idx1, unsigned char idx2,
-                               opc_handler_t *handler)
-{
-    int ret;
-
-    ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
-
-    return ret;
-}
-
-static int register_dblind_insn (opc_handler_t **ppc_opcodes, 
-                                 unsigned char idx1, unsigned char idx2,
-                                  unsigned char idx3, opc_handler_t *handler)
-{
-    if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
-        printf("*** ERROR: unable to join indirect table idx "
-                "[%02x-%02x]\n", idx1, idx2);
-        return -1;
-    }
-    if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
-                              handler) < 0) {
-        printf("*** ERROR: unable to insert opcode "
-                "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn)
-{
-    if (insn->opc2 != 0xFF) {
-        if (insn->opc3 != 0xFF) {
-            if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
-                                     insn->opc3, &insn->handler) < 0)
-                return -1;
-        } else {
-            if (register_ind_insn(ppc_opcodes, insn->opc1,
-                                  insn->opc2, &insn->handler) < 0)
-                return -1;
-        }
-    } else {
-        if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0)
-            return -1;
-    }
-
-    return 0;
-}
-
-static int test_opcode_table (opc_handler_t **table, int len)
-{
-    int i, count, tmp;
-
-    for (i = 0, count = 0; i < len; i++) {
-        /* Consistency fixup */
-        if (table[i] == NULL)
-            table[i] = &invalid_handler;
-        if (table[i] != &invalid_handler) {
-            if (is_indirect_opcode(table[i])) {
-                tmp = test_opcode_table(ind_table(table[i]), 0x20);
-                if (tmp == 0) {
-                    free(table[i]);
-                    table[i] = &invalid_handler;
-                } else {
-                    count++;
-                }
-            } else {
-                count++;
-            }
-        }
-    }
-
-    return count;
-}
-
-static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
-{
-    if (test_opcode_table(ppc_opcodes, 0x40) == 0)
-        printf("*** WARNING: no opcode defined !\n");
-}
-
-#define SPR_RIGHTS(rw, priv) (1 << ((2 * (priv)) + (rw)))
-#define SPR_UR SPR_RIGHTS(0, 0)
-#define SPR_UW SPR_RIGHTS(1, 0)
-#define SPR_SR SPR_RIGHTS(0, 1)
-#define SPR_SW SPR_RIGHTS(1, 1)
-
-#define spr_set_rights(spr, rights)                            \
-do {                                                           \
-    spr_access[(spr) >> 1] |= ((rights) << (4 * ((spr) & 1))); \
-} while (0)
-
-static void init_spr_rights (uint32_t pvr)
-{
-    /* XER    (SPR 1) */
-    spr_set_rights(XER,    SPR_UR | SPR_UW | SPR_SR | SPR_SW);
-    /* LR     (SPR 8) */
-    spr_set_rights(LR,     SPR_UR | SPR_UW | SPR_SR | SPR_SW);
-    /* CTR    (SPR 9) */
-    spr_set_rights(CTR,    SPR_UR | SPR_UW | SPR_SR | SPR_SW);
-    /* TBL    (SPR 268) */
-    spr_set_rights(V_TBL,  SPR_UR | SPR_SR);
-    /* TBU    (SPR 269) */
-    spr_set_rights(V_TBU,  SPR_UR | SPR_SR);
-    /* DSISR  (SPR 18) */
-    spr_set_rights(DSISR,  SPR_SR | SPR_SW);
-    /* DAR    (SPR 19) */
-    spr_set_rights(DAR,    SPR_SR | SPR_SW);
-    /* DEC    (SPR 22) */
-    spr_set_rights(DECR,   SPR_SR | SPR_SW);
-    /* SDR1   (SPR 25) */
-    spr_set_rights(SDR1,   SPR_SR | SPR_SW);
-    /* SRR0   (SPR 26) */
-    spr_set_rights(SRR0,   SPR_SR | SPR_SW);
-    /* SRR1   (SPR 27) */
-    spr_set_rights(SRR1,   SPR_SR | SPR_SW);
-    /* SPRG0  (SPR 272) */
-    spr_set_rights(SPRG0,  SPR_SR | SPR_SW);
-    /* SPRG1  (SPR 273) */
-    spr_set_rights(SPRG1,  SPR_SR | SPR_SW);
-    /* SPRG2  (SPR 274) */
-    spr_set_rights(SPRG2,  SPR_SR | SPR_SW);
-    /* SPRG3  (SPR 275) */
-    spr_set_rights(SPRG3,  SPR_SR | SPR_SW);
-    /* ASR    (SPR 280) */
-    spr_set_rights(ASR,    SPR_SR | SPR_SW);
-    /* EAR    (SPR 282) */
-    spr_set_rights(EAR,    SPR_SR | SPR_SW);
-    /* TBL    (SPR 284) */
-    spr_set_rights(O_TBL,  SPR_SW);
-    /* TBU    (SPR 285) */
-    spr_set_rights(O_TBU,  SPR_SW);
-    /* PVR    (SPR 287) */
-    spr_set_rights(PVR,    SPR_SR);
-    /* IBAT0U (SPR 528) */
-    spr_set_rights(IBAT0U, SPR_SR | SPR_SW);
-    /* IBAT0L (SPR 529) */
-    spr_set_rights(IBAT0L, SPR_SR | SPR_SW);
-    /* IBAT1U (SPR 530) */
-    spr_set_rights(IBAT1U, SPR_SR | SPR_SW);
-    /* IBAT1L (SPR 531) */
-    spr_set_rights(IBAT1L, SPR_SR | SPR_SW);
-    /* IBAT2U (SPR 532) */
-    spr_set_rights(IBAT2U, SPR_SR | SPR_SW);
-    /* IBAT2L (SPR 533) */
-    spr_set_rights(IBAT2L, SPR_SR | SPR_SW);
-    /* IBAT3U (SPR 534) */
-    spr_set_rights(IBAT3U, SPR_SR | SPR_SW);
-    /* IBAT3L (SPR 535) */
-    spr_set_rights(IBAT3L, SPR_SR | SPR_SW);
-    /* DBAT0U (SPR 536) */
-    spr_set_rights(DBAT0U, SPR_SR | SPR_SW);
-    /* DBAT0L (SPR 537) */
-    spr_set_rights(DBAT0L, SPR_SR | SPR_SW);
-    /* DBAT1U (SPR 538) */
-    spr_set_rights(DBAT1U, SPR_SR | SPR_SW);
-    /* DBAT1L (SPR 539) */
-    spr_set_rights(DBAT1L, SPR_SR | SPR_SW);
-    /* DBAT2U (SPR 540) */
-    spr_set_rights(DBAT2U, SPR_SR | SPR_SW);
-    /* DBAT2L (SPR 541) */
-    spr_set_rights(DBAT2L, SPR_SR | SPR_SW);
-    /* DBAT3U (SPR 542) */
-    spr_set_rights(DBAT3U, SPR_SR | SPR_SW);
-    /* DBAT3L (SPR 543) */
-    spr_set_rights(DBAT3L, SPR_SR | SPR_SW);
-    /* DABR   (SPR 1013) */
-    spr_set_rights(DABR,   SPR_SR | SPR_SW);
-    /* FPECR  (SPR 1022) */
-    spr_set_rights(FPECR,  SPR_SR | SPR_SW);
-    /* PIR    (SPR 1023) */
-    spr_set_rights(PIR,    SPR_SR | SPR_SW);
-    /* Special registers for MPC740/745/750/755 (aka G3) & IBM 750 */
-    if ((pvr & 0xFFFF0000) == 0x00080000 ||
-        (pvr & 0xFFFF0000) == 0x70000000) {
-        /* HID0 */
-        spr_set_rights(SPR_ENCODE(1008), SPR_SR | SPR_SW);
-        /* HID1 */
-        spr_set_rights(SPR_ENCODE(1009), SPR_SR | SPR_SW);
-        /* IABR */
-        spr_set_rights(SPR_ENCODE(1010), SPR_SR | SPR_SW);
-        /* ICTC */
-        spr_set_rights(SPR_ENCODE(1019), SPR_SR | SPR_SW);
-        /* L2CR */
-        spr_set_rights(SPR_ENCODE(1017), SPR_SR | SPR_SW);
-        /* MMCR0 */
-        spr_set_rights(SPR_ENCODE(952), SPR_SR | SPR_SW);
-        /* MMCR1 */
-        spr_set_rights(SPR_ENCODE(956), SPR_SR | SPR_SW);
-        /* PMC1 */
-        spr_set_rights(SPR_ENCODE(953), SPR_SR | SPR_SW);
-        /* PMC2 */
-        spr_set_rights(SPR_ENCODE(954), SPR_SR | SPR_SW);
-        /* PMC3 */
-        spr_set_rights(SPR_ENCODE(957), SPR_SR | SPR_SW);
-        /* PMC4 */
-        spr_set_rights(SPR_ENCODE(958), SPR_SR | SPR_SW);
-        /* SIA */
-        spr_set_rights(SPR_ENCODE(955), SPR_SR | SPR_SW);
-        /* THRM1 */
-        spr_set_rights(SPR_ENCODE(1020), SPR_SR | SPR_SW);
-        /* THRM2 */
-        spr_set_rights(SPR_ENCODE(1021), SPR_SR | SPR_SW);
-        /* THRM3 */
-        spr_set_rights(SPR_ENCODE(1022), SPR_SR | SPR_SW);
-        /* UMMCR0 */
-        spr_set_rights(SPR_ENCODE(936), SPR_UR | SPR_UW);
-        /* UMMCR1 */
-        spr_set_rights(SPR_ENCODE(940), SPR_UR | SPR_UW);
-        /* UPMC1 */
-        spr_set_rights(SPR_ENCODE(937), SPR_UR | SPR_UW);
-        /* UPMC2 */
-        spr_set_rights(SPR_ENCODE(938), SPR_UR | SPR_UW);
-        /* UPMC3 */
-        spr_set_rights(SPR_ENCODE(941), SPR_UR | SPR_UW);
-        /* UPMC4 */
-        spr_set_rights(SPR_ENCODE(942), SPR_UR | SPR_UW);
-        /* USIA */
-        spr_set_rights(SPR_ENCODE(939), SPR_UR | SPR_UW);
-    }
-    /* MPC755 has special registers */
-    if (pvr == 0x00083100) {
-        /* SPRG4 */
-        spr_set_rights(SPRG4, SPR_SR | SPR_SW);
-        /* SPRG5 */
-        spr_set_rights(SPRG5, SPR_SR | SPR_SW);
-        /* SPRG6 */
-        spr_set_rights(SPRG6, SPR_SR | SPR_SW);
-        /* SPRG7 */
-        spr_set_rights(SPRG7, SPR_SR | SPR_SW);
-        /* IBAT4U */
-        spr_set_rights(IBAT4U, SPR_SR | SPR_SW);
-        /* IBAT4L */
-        spr_set_rights(IBAT4L, SPR_SR | SPR_SW);
-        /* IBAT5U */
-        spr_set_rights(IBAT5U, SPR_SR | SPR_SW);
-        /* IBAT5L */
-        spr_set_rights(IBAT5L, SPR_SR | SPR_SW);
-        /* IBAT6U */
-        spr_set_rights(IBAT6U, SPR_SR | SPR_SW);
-        /* IBAT6L */
-        spr_set_rights(IBAT6L, SPR_SR | SPR_SW);
-        /* IBAT7U */
-        spr_set_rights(IBAT7U, SPR_SR | SPR_SW);
-        /* IBAT7L */
-        spr_set_rights(IBAT7L, SPR_SR | SPR_SW);
-        /* DBAT4U */
-        spr_set_rights(DBAT4U, SPR_SR | SPR_SW);
-        /* DBAT4L */
-        spr_set_rights(DBAT4L, SPR_SR | SPR_SW);
-        /* DBAT5U */
-        spr_set_rights(DBAT5U, SPR_SR | SPR_SW);
-        /* DBAT5L */
-        spr_set_rights(DBAT5L, SPR_SR | SPR_SW);
-        /* DBAT6U */
-        spr_set_rights(DBAT6U, SPR_SR | SPR_SW);
-        /* DBAT6L */
-        spr_set_rights(DBAT6L, SPR_SR | SPR_SW);
-        /* DBAT7U */
-        spr_set_rights(DBAT7U, SPR_SR | SPR_SW);
-        /* DBAT7L */
-        spr_set_rights(DBAT7L, SPR_SR | SPR_SW);
-        /* DMISS */
-        spr_set_rights(SPR_ENCODE(976), SPR_SR | SPR_SW);
-        /* DCMP */
-        spr_set_rights(SPR_ENCODE(977), SPR_SR | SPR_SW);
-        /* DHASH1 */
-        spr_set_rights(SPR_ENCODE(978), SPR_SR | SPR_SW);
-        /* DHASH2 */
-        spr_set_rights(SPR_ENCODE(979), SPR_SR | SPR_SW);
-        /* IMISS */
-        spr_set_rights(SPR_ENCODE(980), SPR_SR | SPR_SW);
-        /* ICMP */
-        spr_set_rights(SPR_ENCODE(981), SPR_SR | SPR_SW);
-        /* RPA */
-        spr_set_rights(SPR_ENCODE(982), SPR_SR | SPR_SW);
-        /* HID2 */
-        spr_set_rights(SPR_ENCODE(1011), SPR_SR | SPR_SW);
-        /* L2PM */
-        spr_set_rights(SPR_ENCODE(1016), SPR_SR | SPR_SW);
-    }
-}
-
-/*****************************************************************************/
-/* PPC "main stream" common instructions (no optional ones) */
-
-typedef struct ppc_proc_t {
-    int flags;
-    void *specific;
-} ppc_proc_t;
-
-typedef struct ppc_def_t {
-    unsigned long pvr;
-    unsigned long pvr_mask;
-    ppc_proc_t *proc;
-} ppc_def_t;
-
-static ppc_proc_t ppc_proc_common = {
-    .flags    = PPC_COMMON,
-    .specific = NULL,
-};
-
-static ppc_proc_t ppc_proc_G3 = {
-    .flags    = PPC_750,
-    .specific = NULL,
-};
-
-static ppc_def_t ppc_defs[] =
-{
-    /* MPC740/745/750/755 (G3) */
-    {
-        .pvr      = 0x00080000,
-        .pvr_mask = 0xFFFF0000,
-        .proc     = &ppc_proc_G3,
-    },
-    /* IBM 750FX (G3 embedded) */
-    {
-        .pvr      = 0x70000000,
-        .pvr_mask = 0xFFFF0000,
-        .proc     = &ppc_proc_G3,
-    },
-    /* Fallback (generic PPC) */
-    {
-        .pvr      = 0x00000000,
-        .pvr_mask = 0x00000000,
-        .proc     = &ppc_proc_common,
-    },
-};
-
-static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr)
-{
-    opcode_t *opc;
-    int i, flags;
-
-    fill_new_table(ppc_opcodes, 0x40);
-    for (i = 0; ; i++) {
-        if ((ppc_defs[i].pvr & ppc_defs[i].pvr_mask) ==
-            (pvr & ppc_defs[i].pvr_mask)) {
-            flags = ppc_defs[i].proc->flags;
-            break;
-        }
-    }
-    
-    for (opc = &opc_start + 1; opc != &opc_end; opc++) {
-        if ((opc->handler.type & flags) != 0)
-            if (register_insn(ppc_opcodes, opc) < 0) {
-                printf("*** ERROR initializing PPC instruction "
-                        "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
-                        opc->opc3);
-                return -1;
-            }
-    }
-    fix_opcode_tables(ppc_opcodes);
-
-    return 0;
-}
-
+#include "translate_init.c"
 
 /*****************************************************************************/
-/* Misc PPC helpers */
-FILE *stdout;
+/* Misc PowerPC helpers */
+void cpu_dump_state(CPUState *env, FILE *f, 
+                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                    int flags)
+{
+#if defined(TARGET_PPC64) || 1
+#define FILL ""
+#define REGX "%016llx"
+#define RGPL  4
+#define RFPL  4
+#else
+#define FILL "        "
+#define REGX "%08llx"
+#define RGPL  8
+#define RFPL  4
+#endif
 
-void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags)
-{
     int i;
 
-    fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x "
-            "MSR=0x%08x\n", env->nip, env->lr, env->ctr,
-            _load_xer(), _load_msr());
+    cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n",
+                env->nip, env->lr, env->ctr);
+    cpu_fprintf(f, "MSR " REGX FILL " XER %08x      TB %08x %08x DECR %08x\n",
+                do_load_msr(env), do_load_xer(env), cpu_ppc_load_tbu(env),
+                cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env));
         for (i = 0; i < 32; i++) {
-            if ((i & 7) == 0)
-            fprintf(f, "GPR%02d:", i);
-        fprintf(f, " %08x", env->gpr[i]);
-            if ((i & 7) == 7)
-            fprintf(f, "\n");
+        if ((i & (RGPL - 1)) == 0)
+            cpu_fprintf(f, "GPR%02d", i);
+        cpu_fprintf(f, " " REGX, env->gpr[i]);
+        if ((i & (RGPL - 1)) == (RGPL - 1))
+            cpu_fprintf(f, "\n");
         }
-    fprintf(f, "CR: 0x");
+    cpu_fprintf(f, "CR ");
         for (i = 0; i < 8; i++)
-        fprintf(f, "%01x", env->crf[i]);
-    fprintf(f, "  [");
+        cpu_fprintf(f, "%01x", env->crf[i]);
+    cpu_fprintf(f, "  [");
         for (i = 0; i < 8; i++) {
             char a = '-';
             if (env->crf[i] & 0x08)
@@ -2949,78 +2474,33 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags)
                 a = 'G';
             else if (env->crf[i] & 0x02)
                 a = 'E';
-        fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
+        cpu_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]);
-        for (i = 0; i < 16; i++) {
-            if ((i & 3) == 0)
-            fprintf(f, "FPR%02d:", i);
-        fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i]));
-            if ((i & 3) == 3)
-            fprintf(f, "\n");
-    }
-    fprintf(f, "SRR0 0x%08x SRR1 0x%08x\n",
-            env->spr[SRR0], env->spr[SRR1]);
-    fprintf(f, "reservation 0x%08x\n", env->reserve);
-    fflush(f);
-}
-
-#if !defined(CONFIG_USER_ONLY) && defined (USE_OPENFIRMWARE)
-int setup_machine (CPUPPCState *env, uint32_t mid);
-#endif
-
-CPUPPCState *cpu_ppc_init(void)
-{
-    CPUPPCState *env;
-
-    cpu_exec_init();
-
-    env = malloc(sizeof(CPUPPCState));
-    if (!env)
-        return NULL;
-    memset(env, 0, sizeof(CPUPPCState));
-#if !defined(CONFIG_USER_ONLY) && defined (USE_OPEN_FIRMWARE)
-    setup_machine(env, 0);
-#else
-//    env->spr[PVR] = 0; /* Basic PPC */
-    env->spr[PVR] = 0x00080100; /* G3 CPU */
-//    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]);
-    tlb_flush(env);
-#if defined (DO_SINGLE_STEP)
-    /* Single step trace mode */
-    msr_se = 1;
-#endif
-#if defined(CONFIG_USER_ONLY)
-    msr_pr = 1;
-#endif
-
-    return env;
-}
+    cpu_fprintf(f, " ]             " FILL "RES " REGX "\n", env->reserve);
+    for (i = 0; i < 32; i++) {
+        if ((i & (RFPL - 1)) == 0)
+            cpu_fprintf(f, "FPR%02d", i);
+        cpu_fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i]));
+        if ((i & (RFPL - 1)) == (RFPL - 1))
+            cpu_fprintf(f, "\n");
+    }
+    cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX "         " FILL FILL FILL
+                "SDR1 " REGX "\n",
+                env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
 
-void cpu_ppc_close(CPUPPCState *env)
-{
-    /* Should also remove all opcode tables... */
-    free(env);
+#undef REGX
+#undef RGPL
+#undef RFPL
+#undef FILL
 }
 
 /*****************************************************************************/
-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;
+    target_ulong pc_start;
     uint16_t *gen_opc_end;
     int j, lj = -1;
 
@@ -3028,56 +2508,57 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     gen_opc_ptr = gen_opc_buf;
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
     gen_opparam_ptr = gen_opparam_buf;
-    ctx.nip = (uint32_t *)pc_start;
-    ctx.tb_offset = 0;
-    ctx.decr_offset = 0;
+    nb_gen_labels = 0;
+    ctx.nip = pc_start;
     ctx.tb = tb;
     ctx.exception = EXCP_NONE;
+    ctx.spr_cb = env->spr_cb;
 #if defined(CONFIG_USER_ONLY)
-    ctx.mem_idx = 0;
+    ctx.mem_idx = msr_le;
 #else
     ctx.supervisor = 1 - msr_pr;
-    ctx.mem_idx = (1 - msr_pr);
+    ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
 #endif
-#if defined (DO_SINGLE_STEP)
+    ctx.fpu_enabled = msr_fp;
+#if defined (DO_SINGLE_STEP) && 0
     /* Single step trace mode */
     msr_se = 1;
 #endif
     /* Set env in case of segfault during code fetch */
     while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
         if (search_pc) {
-            if (loglevel > 0)
-                fprintf(logfile, "Search PC...\n");
             j = gen_opc_ptr - gen_opc_buf;
             if (lj < j) {
                 lj++;
                 while (lj < j)
                     gen_opc_instr_start[lj++] = 0;
-                gen_opc_pc[lj] = (uint32_t)ctx.nip;
+                gen_opc_pc[lj] = ctx.nip;
                 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=%p super=%d ir=%d\n",
+            fprintf(logfile, "nip=%08x super=%d ir=%d\n",
                     ctx.nip, 1 - msr_pr, msr_ir);
         }
 #endif
         ctx.opcode = ldl_code(ctx.nip);
-#if defined DEBUG_DISAS
-        if (loglevel > 0) {
-            fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n",
+        if (msr_le) {
+            ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) |
+                ((ctx.opcode & 0x00FF0000) >> 8) |
+                ((ctx.opcode & 0x0000FF00) << 8) |
+                ((ctx.opcode & 0x000000FF) << 24);
+        }
+#if defined PPC_DEBUG_DISAS
+        if (loglevel & CPU_LOG_TB_IN_ASM) {
+            fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
                     ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
-                    opc3(ctx.opcode));
+                    opc3(ctx.opcode), msr_le ? "little" : "big");
         }
 #endif
-        ctx.nip++;
-        ctx.tb_offset++;
-        /* Check decrementer exception */
-        if (++ctx.decr_offset == env->decr + 1)
-            ctx.exception = EXCP_DECR;
-        table = ppc_opcodes;
+        ctx.nip += 4;
+        table = env->opcodes;
         handler = table[opc1(ctx.opcode)];
         if (is_indirect_opcode(handler)) {
             table = ind_table(handler);
@@ -3088,38 +2569,38 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
             }
         }
         /* Is opcode *REALLY* valid ? */
-        if ((ctx.opcode & handler->inval) != 0) {
-            if (loglevel > 0) {
                 if (handler->handler == &gen_invalid) {
+            if (loglevel > 0) {
                     fprintf(logfile, "invalid/unsupported opcode: "
-                            "%02x -%02x - %02x (%08x) %p\n",
+                        "%02x - %02x - %02x (%08x) 0x%08x %d\n",
                             opc1(ctx.opcode), opc2(ctx.opcode),
-                            opc3(ctx.opcode), ctx.opcode, ctx.nip - 1);
+                        opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
+            } else {
+                printf("invalid/unsupported opcode: "
+                       "%02x - %02x - %02x (%08x) 0x%08x %d\n",
+                       opc1(ctx.opcode), opc2(ctx.opcode),
+                       opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
+            }
                 } else {
+            if ((ctx.opcode & handler->inval) != 0) {
+                if (loglevel > 0) {
                     fprintf(logfile, "invalid bits: %08x for opcode: "
-                            "%02x -%02x - %02x (0x%08x) (%p)\n",
+                            "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
                             ctx.opcode & handler->inval, opc1(ctx.opcode),
                             opc2(ctx.opcode), opc3(ctx.opcode),
-                            ctx.opcode, ctx.nip - 1);
-                }
-            } else {
-                if (handler->handler == &gen_invalid) {
-                    printf("invalid/unsupported opcode: "
-                           "%02x -%02x - %02x (%08x) %p\n",
-                           opc1(ctx.opcode), opc2(ctx.opcode),
-                           opc3(ctx.opcode), ctx.opcode, ctx.nip - 1);
+                            ctx.opcode, ctx.nip - 4);
                 } else {
                     printf("invalid bits: %08x for opcode: "
-                           "%02x -%02x - %02x (0x%08x) (%p)\n",
+                           "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
                             ctx.opcode & handler->inval, opc1(ctx.opcode),
                             opc2(ctx.opcode), opc3(ctx.opcode),
-                           ctx.opcode, ctx.nip - 1);
+                           ctx.opcode, ctx.nip - 4);
             }
+                RET_INVAL(ctxp);
+                break;
             }
-            (*gen_invalid)(&ctx);
-        } else {
-            (*(handler->handler))(&ctx);
         }
+        (*(handler->handler))(&ctx);
         /* Check trace mode exceptions */
         if ((msr_be && ctx.exception == EXCP_BRANCH) ||
             /* Check in single step trace mode
@@ -3127,32 +2608,26 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
              * - rfi, trap or syscall
              * - first instruction of an exception handler
              */
-            (msr_se && ((uint32_t)ctx.nip < 0x100 ||
-                        (uint32_t)ctx.nip > 0xF00 ||
-                        ((uint32_t)ctx.nip & 0xFC) != 0x04) &&
-             ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI &&
+            (msr_se && (ctx.nip < 0x100 ||
+                        ctx.nip > 0xF00 ||
+                        (ctx.nip & 0xFC) != 0x04) &&
+             ctx.exception != EXCP_SYSCALL &&
+             ctx.exception != EXCP_SYSCALL_USER &&
              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 too long translation, stop generation too */
-        if (gen_opc_ptr >= gen_opc_end ||
-            ((uint32_t)ctx.nip - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
-            if (ctx.exception == EXCP_NONE) {
-        gen_op_b((uint32_t)ctx.nip);
-                ctx.exception = EXCP_BRANCH;
-    }
+        /* if we reach a page boundary, stop generation */
+        if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) {
+            break;
     }
+#if defined (DO_SINGLE_STEP)
+        break;
+#endif
     }
-    /* 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((uint32_t)ctx.nip);
+    if (ctx.exception == EXCP_NONE) {
+        gen_goto_tb(&ctx, 0, 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
@@ -3169,26 +2644,30 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
         while (lj <= j)
             gen_opc_instr_start[lj++] = 0;
         tb->size = 0;
+#if 0
         if (loglevel > 0) {
             page_dump(logfile);
         }
+#endif
     } else {
-        tb->size = (uint32_t)ctx.nip - pc_start;
+        tb->size = ctx.nip - pc_start;
     }
 #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);
-        fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start));
-       disas(logfile, (void *)pc_start, (uint32_t)ctx.nip - pc_start, 0, 0);
+        cpu_dump_state(env, logfile, fprintf, 0);
+    }
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
+       target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le);
         fprintf(logfile, "\n");
-
+    }
+    if (loglevel & CPU_LOG_TB_OP) {
         fprintf(logfile, "OP:\n");
         dump_ops(gen_opc_buf, gen_opparam_buf);
         fprintf(logfile, "\n");
     }
 #endif
-
     return 0;
 }